Skip to content

feat(claude): emit plugin bin/ executables (#187 slice 1) - #282

Merged
ScriptedAlchemy merged 1 commit into
mainfrom
feat/187-s1-bin
Sep 2, 2026
Merged

feat(claude): emit plugin bin/ executables (#187 slice 1)#282
ScriptedAlchemy merged 1 commit into
mainfrom
feat/187-s1-bin

Conversation

@ScriptedAlchemy

Copy link
Copy Markdown
Owner

Summary

  • Adds the host-scoped claude.bin config surface: a project-authored directory lowered byte-for-byte into the Claude plugin-root bin/ convention (executables added to the Bash tool's PATH and invokable as bare commands while the plugin is enabled), preserving executable modes through prebuilt copy entries.
  • Normalize-time enumeration via a new adapter binSource hook (mirroring nativeHookSource), with containment, missing/empty/not-a-directory, and source-shape issues carried on the model and diagnosed at plan time; top-level non-executable files are a build error with a chmod +x recovery.
  • Reserves the bin payload destination (AB4741 now points authors at claude.bin), records bin roots in the project-identity snapshot so dev rebuilds track executable changes, and accepts bin/ in artifact validation.
  • Honest capability row (bin) driven by new pinned plugin.bin facts in claude-2.1.250.json, including the documented claude.ai organization-distribution prohibition, with dated 2026-09-01 citations of https://code.claude.com/docs/en/plugins-reference and https://code.claude.com/docs/en/plugins, plus a recorded native proof against the locally observed Claude Code 2.1.257 (claude plugin validate --strict accepts an emitted plugin with an executable bin/ command). The unified plugin bundle keeps an unavailable bin row per the lsp intersection convention while its Claude half emits the directory; adapter revisions bumped (claude 1.6.0, plugin 1.5.0).

Part of #187 slice 1 (systematic Claude host-parity pass).

Test plan

  • Scoped suites (host-adapters, native host proof, capability states, adapter metadata, artifact validator, normalization, plugin bundle, prebuilt payload, api): 181 passed, 0 failed, 0 skipped (native proof executed against Claude Code 2.1.257)
  • pnpm typecheck
  • pnpm lint (0 errors, 0 warnings)
  • Re-verified after rebase onto origin/main (2655ca5)

Add a host-scoped claude.bin directory surface that preserves authored bytes and executable modes, with capability evidence and native host validation.
@changeset-bot

changeset-bot Bot commented Sep 2, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 79fa2a5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
agent-bundle Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@ScriptedAlchemy
ScriptedAlchemy merged commit 3e431ea into main Sep 2, 2026
4 checks passed
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 2, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-02T05:27:48.899067Z 79fa2a5 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 79fa2a5bf7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +587 to +588
if (!isInside(loaded.context.projectRoot, source)) {
bins.push({ files: [], issue: 'outside', provenance: { ...provenance }, source, target: binSource.target });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Resolve bin roots before checking project containment

When claude.bin names a symlink located inside the project whose target is outside it, this lexical isInside check passes and the subsequent stat/enumeration follows the symlink. Public callers of normalizeProject can therefore receive a plan that copies external files, while ProjectService fails earlier with the generic AB7003 snapshot error instead of the intended claude.bin.directory.outside diagnostic. Resolve the physical bin root and verify it remains inside the canonical project root before enumeration.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 2b5a9857e: host payload normalization now resolves the configured bin root with realpath against the canonical project root before enumeration, so an in-project symlink that escapes outside is rejected as claude.bin.directory.outside instead of admitting external files. Merged via #300.

resolvedConfigPath,
...(await sourcePaths(resolvedRoot, resolvedOutputRoots)),
...(await payloadSourcePaths(resolvedRoot, payloadRoots)),
...(await payloadSourcePaths(resolvedRoot, additionalSourceRoots)),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Track executable bits in bin freshness snapshots

If a bin command loses its execute bits after normalization but before emission, the plan has already passed planClaudeBin, emit.ts copies the command's current non-executable mode, and the post-build freshness check still succeeds because sourceInput records only the file path and content hash. Thus an epoch can publish a broken bare command without reporting that the source changed; include bin modes in the freshness identity or revalidate the planned executable state before publication.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in a45992e and completed in 6fae061: snapshots record the executable bit, canonical project/manifests retain it in revision identity, and publication rejects mode-only drift with AB7101. The mode-only red/green regression and packed release matrix pass.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant