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
|
||||
|
||||
@@ -18,8 +18,8 @@ glob. On Claude it deploys to `.claude/rules/<stem>.md` with `applyTo` renamed t
|
||||
always-on source. Stop and hand to `agentsmd-author`.
|
||||
- **No file pattern fits** → an instruction without `applyTo` is always-on in every session of
|
||||
every repo that installs this package, and `apm compile` can fold it into the global sections of
|
||||
`AGENTS.md` and `CLAUDE.md` (skipped when `.github/instructions/` or `.claude/rules/` is already
|
||||
populated, unless `--force-instructions`). Say exactly that to the user and continue only on an explicit yes.
|
||||
`AGENTS.md` and `CLAUDE.md` (CLAUDE.md is skipped when `.claude/rules/` is populated, AGENTS.md
|
||||
when `.github/instructions/` is, unless `--force-instructions`). Say exactly that to the user and continue only on an explicit yes.
|
||||
Legitimate when a package deliberately ships guidance to its consumers; never a default.
|
||||
- **Procedure the agent follows step by step** → a skill. Stop and hand to `skill-author`.
|
||||
- **A rule scoped to a file pattern** → continue.
|
||||
@@ -47,8 +47,8 @@ Should:
|
||||
its handling of a list is unverified.
|
||||
7. Keep frontmatter to `description` and `applyTo`, plus optional `author` and `version`. No target
|
||||
consumes other keys, and Claude drops them.
|
||||
8. Put any rationale Claude needs in the body. `description` never reaches Claude — it survives only
|
||||
for Copilot and as Cursor's index text.
|
||||
8. Put any rationale Claude needs in the body. `description` never reaches Claude — it survives for
|
||||
Copilot and as index text in Cursor rules and compiled AGENTS.md/CLAUDE.md.
|
||||
9. Keep relative markdown links resolvable from the source file.
|
||||
10. Check the glob against the tree: one that matches nothing here fires only in consumer repos
|
||||
that have such files, and one broader than the rule's real scope spends context on every file
|
||||
|
||||
@@ -56,6 +56,8 @@ Should:
|
||||
5. Frontmatter keys stay within `description`, `allowed-tools`, `model`, `argument-hint` and
|
||||
`input`. Claude drops everything else with only a warning. The exception: a Copilot-only key
|
||||
(`agent`, `tools`, …) that is intended, with its Claude drop accepted and said so.
|
||||
The research files this as a Must; it is a Should here because only the author can say a
|
||||
Copilot-only key is intended.
|
||||
6. The description follows the contract above: one plain sentence, no trigger or boundary clause,
|
||||
naming the skills or agents it steers.
|
||||
7. Spell keys in kebab-case — `allowed-tools`, `argument-hint` — not the camelCase aliases.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
- **URL:** file:///root/.local/pipx/venvs/apm-cli/lib/python3.11/site-packages/apm_cli/
|
||||
- **Research doc:** plugins/kyberforge/docs/research/docs/microsoft-apm/sources.md
|
||||
- **Description:** Installed apm-cli 0.28.0 source — ground truth for what apm deploys from a hook, instruction or prompt file and what it silently skips or only warns on; every Must/Should checklist item traces to the research docs' Authoring checklists, and the `**/*.instructions.md` local-discovery glob behind the template-suffix Gotcha is `primitives/discovery.py` `LOCAL_PRIMITIVE_PATTERNS`
|
||||
- **Description:** Installed apm-cli 0.28.0 source — ground truth for what apm deploys from a hook, instruction or prompt file and what it silently skips or only warns on; each Must/Should traces to the research docs' Authoring checklists or audit-only lists, or to ADR-0029, with tier moves annotated inline, and the `**/*.instructions.md` local-discovery glob behind the template-suffix Gotcha is `primitives/discovery.py` `LOCAL_PRIMITIVE_PATTERNS`; the per-target event rename maps are `integration/hook_integrator.py` `_HOOK_EVENT_MAP`; and Step 4.2's render relies on `apm install <local path>` deploying the working tree to every `--target`, verified against 0.28.0
|
||||
- **Contributing files:** SKILL.md, references/hook.md, references/instruction.md, references/prompt.md
|
||||
- **Status:** `extracted`
|
||||
|
||||
|
||||
Reference in New Issue
Block a user