fix(kyberforge): resolve PR #144 review and audit round 2
- factory-audit: ./ and bare/absolute script checks scoped to command position (no false FAILs on ./src or printf); hook sources limited to .apm/hooks or package-root hooks/; Kiro-aware lowercase events; unfilled template placeholders FAIL; repo-only instructions FAIL at any scope; Vale description FAIL documented; bats 367 -> 378 - primitive-author: split-quote/spaced paths and handler-less entries promoted to Must; Step 4.2 renders into a scratch consumer instead of a no-op dry run; dispatch and gate hand-off trimmed - apm-workflow 1.0.2: mutual boundary with primitive-author - forge: no double package bump; gotcha wording - skill-author: create keeps seeded 0.1.0 (ADR-0022); portable, retry-safe new-skill.sh; template and flow consistency fixes - hook docs: cite the ADR-0019 correction; guard caveat Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KkT7RSDwDbmrM9T34b6sTi
This commit is contained in:
@@ -48,7 +48,7 @@ target:
|
||||
- **`${PLUGIN_ROOT}`** is the target-neutral token; apm rewrites it per target
|
||||
(`"${CLAUDE_PROJECT_DIR}/.claude/hooks/<pkg>/…"` on Claude, repo-relative elsewhere).
|
||||
`${CLAUDE_PLUGIN_ROOT}` is rewritten identically, so it is valid, but it ties the source to one
|
||||
harness's name (Should 12).
|
||||
harness's name (Should 11).
|
||||
- **Claude is the verified target.** apm 0.28.0 passes this nested shape to Copilot without
|
||||
reshaping it, and whether Copilot CLI runs nested entries or honours `matcher` is unverified. That
|
||||
gap is apm's to close. Per-file target routing is deprecated, so a Copilot-native flat hook
|
||||
@@ -65,15 +65,25 @@ Must:
|
||||
2. Use the wrapped shape `{"hooks": {Event: [...]}}`. If a naked settings slice is used instead,
|
||||
every top-level value must be a list, with no stray scalar keys anywhere.
|
||||
3. Every event value is a list of objects, and every nested `hooks` is a list of objects. Anything
|
||||
else fails the Copilot install outright. The file contributes at least one entry: an empty one
|
||||
deploys nothing, with only a warning.
|
||||
else fails the Copilot install outright. The file contributes at least one entry, and every
|
||||
entry carries at least one handler: an empty list or a handler-less entry deploys nothing, with
|
||||
only a warning.
|
||||
4. Event names are PascalCase (`PreToolUse`, `PostToolUse`, `UserPromptSubmit`, `SessionStart`,
|
||||
`Stop`, …). An all-lowercase name (`stop`) never warns and never fires; a camelCase name outside
|
||||
apm's rename map (`userPromptSubmit`) deploys verbatim to Claude and never fires.
|
||||
`Stop`, …). An all-lowercase name never warns: only Kiro's rename map covers one (`stop` →
|
||||
`Stop`), and every other target deploys it verbatim, where it never fires. A camelCase name
|
||||
outside apm's rename map (`userPromptSubmit`) likewise deploys verbatim to Claude and never
|
||||
fires.
|
||||
5. The script is referenced as `${PLUGIN_ROOT}/…` (or `${CLAUDE_PLUGIN_ROOT}/…`, see Shape) for
|
||||
the package root, or `./…` for the hook directory, and exists inside the package. No absolute
|
||||
path and no bare relative path (`scripts/x.sh`): apm bundles and rewrites neither. No `$` or
|
||||
backtick in the path itself. A missing script is only a warning at install time.
|
||||
the package root, or `./…` for the hook directory, and exists inside the package. The script is
|
||||
the command's first token or the first argument after an interpreter (`bash`, `sh`, `zsh`,
|
||||
`python`, `python3`, `node`, `pwsh`, `ruby`, `perl`); in either position, no absolute path and
|
||||
no bare relative path (`scripts/x.sh`): apm bundles and rewrites neither. No `$` or backtick in
|
||||
the path itself, and no space. When quoting, quote the whole token —
|
||||
`"${PLUGIN_ROOT}/scripts/my-hook.sh"`, never `"${PLUGIN_ROOT}"/scripts/x.sh`: apm rewrites
|
||||
`${PLUGIN_ROOT}` only when a path separator follows it directly, and only up to the next space
|
||||
or quote, so a split quote is left unrewritten and a spaced path is cut short. This is stricter
|
||||
than the research's Should, as with Must 6: either defect fails every time the hook fires. A
|
||||
missing script is only a warning at install time.
|
||||
6. A script run directly as the command's first token is executable. This is stricter than the
|
||||
research's Should: without it the hook fails every time it fires. A script passed to an
|
||||
interpreter (`bash ${PLUGIN_ROOT}/x.sh`) needs no executable bit.
|
||||
@@ -86,14 +96,10 @@ Should:
|
||||
Claude receives `"*"`.
|
||||
9. Do not author Copilot's flat `bash` / `powershell` / `timeoutSec` keys in a Claude-shaped file;
|
||||
they render onto Claude as stray keys.
|
||||
10. Keep script paths free of spaces, and when quoting, quote the whole token:
|
||||
`"${PLUGIN_ROOT}/scripts/my-hook.sh"`. apm rewrites `${PLUGIN_ROOT}` only when a path separator
|
||||
follows it directly, and only up to the next space or quote — so `"${PLUGIN_ROOT}"/scripts/x.sh`
|
||||
is left unrewritten and a spaced path is cut short.
|
||||
11. Keep helper files in the hook directory non-JSON. Copilot's loader rejects any bundled `.json`
|
||||
10. Keep helper files in the hook directory non-JSON. Copilot's loader rejects any bundled `.json`
|
||||
without a `hooks` key.
|
||||
12. Prefer `${PLUGIN_ROOT}` over `${CLAUDE_PLUGIN_ROOT}`.
|
||||
13. No filename that routes by target. Case-insensitively, apm routes a stem of exactly
|
||||
11. Prefer `${PLUGIN_ROOT}` over `${CLAUDE_PLUGIN_ROOT}`.
|
||||
12. No filename that routes by target. Case-insensitively, apm routes a stem of exactly
|
||||
`hooks-<target>` and any stem ending `<target>-hooks` — bare (`claude-hooks`), prefixed
|
||||
(`x-claude-hooks`) or combined (`claude-codex-hooks`, the union). That routing is deprecated and
|
||||
reach belongs to `targets:` (see Gate); the research allows it only when deprecated routing is
|
||||
|
||||
Reference in New Issue
Block a user