Skip to content

fix(copilotcli): map userPromptTransformed, honor every documented matcher event, read portable hook fields and skill invocation flags - #2466

Merged
dyoshikawa merged 2 commits into
mainfrom
resolve-scrap-issue-2402-copilotcli
Jul 29, 2026
Merged

fix(copilotcli): map userPromptTransformed, honor every documented matcher event, read portable hook fields and skill invocation flags#2466
dyoshikawa merged 2 commits into
mainfrom
resolve-scrap-issue-2402-copilotcli

Conversation

@dyoshikawa

Copy link
Copy Markdown
Owner

Background

Addresses gaps 2-5 of #2402. Gap 1 is deliberately left open (see below), so this PR does not close the issue.

Every gap was checked against the authoritative github/docs markdown source rather than the rendered SPA.

Gap 2 — userPromptTransformed had no canonical mapping

The hooks reference lists it in the 14-event set. Rather than adding a new canonical event, it maps to the existing canonical userPromptExpansion — the same concept Qwen Code's UserPromptExpansion already maps to (a mutation-only hook that runs on the transformed prompt and can rewrite model-facing content). It is now authorable from .rulesync/hooks.jsonc and imports as a known event instead of an unknown passthrough.

Gap 3 — matcher dropped on four matcher-aware events

The hooks reference documents matcher on six events, each filtering a different field: preToolUse / postToolUse / permissionRequest (tool name), notification (notification type), preCompact (trigger, manual or auto) and subagentStart (agent name). COPILOTCLI_MATCHER_EVENTS was hard-coded to the first two, so a matcher on the other four was silently discarded — and the drop warning named only preToolUse/postToolUse, which was factually wrong. The set now covers all six and the warning is derived from it.

Gap 4 — portable command and the timeout alias not read on import

Upstream: command is the "cross-platform fallback ... copied to both bash and powershell" when those are absent, and timeout is an "alias for timeoutSec ... used only when timeoutSec is absent". Neither was in the entry schema, so importing an existing .github/hooks/*.json written in the portable form produced a hook definition with no command at all, and a timeout-only entry lost its timeout. Both are now accepted on import with upstream's precedence (an explicit shell field wins over command; timeoutSec wins over timeout). Generate is unchanged and still writes the platform-specific shell field.

Gap 5 — skill invocation flags dropped

user-invocable (default true) and disable-model-invocation (default false) are documented skill frontmatter and actively honored upstream (v1.0.71 marks disabled skills in skill list; v1.0.74 "fully honors" the disable flag). Both are added to CopilotcliSkillFrontmatterSchema and to the copilotcli section of RulesyncSkillFrontmatter, and copied in both directions. A false value survives rather than being treated as absent.

Gap 1 (.claude/commands/*.md) — left open, needs a maintainer decision

The surface is real and correctly quoted in the issue. But supporting it means the copilotcli target writes into .claude/commands/, a directory that today only the claudecode target owns — so enabling copilotcli alone would materialize Claude Code files, and enabling both targets would have two different products' command frontmatter fighting over the same path. That is a scope call about directory ownership across products, not a template-following addition, so it is not implemented here. Worth noting that upstream also documents commands as having lower priority than skills of the same name, and rulesync already emits the Copilot CLI skills surface at .github/skills/.

Verification

  • Full pnpm cicheck green.
  • npx vitest run --config vitest.e2e.config.ts src/e2e/e2e-hooks.spec.ts src/e2e/e2e-skills.spec.ts — 202 passed.
  • New unit tests cover the four newly matcher-aware events, the userPromptTransformed round-trip, the portable command / timeout precedence rules, and both skill flags including the false case.

…tcher event, read portable hook fields and skill invocation flags

Four verified drifts against the Copilot CLI reference docs:

- userPromptTransformed had no canonical mapping; it now maps to the existing canonical userPromptExpansion event (the same concept Qwen Code's UserPromptExpansion maps to), so it is authorable and imports as a known event.
- matcher was only emitted on preToolUse/postToolUse, but the hooks reference documents it on permissionRequest, notification, preCompact and subagentStart too; a matcher on those was silently discarded and the drop warning was factually wrong.
- The portable command field and the timeout alias were not read on import, so an existing .github/hooks/*.json using them imported with no command or no timeout at all.
- The skill user-invocable and disable-model-invocation flags were dropped on generate.

The .claude/commands/ surface reported in the same issue is left open: it would make copilotcli write into Claude Code's directory, which is a maintainer call.
… selector, not the build machine

Generate hard-coded bash on Unix and powershell on Windows, so the same canonical config produced different output per machine — and an imported portable command entry came back out narrowed to one shell. The shell selector now chooses the field, and an entry without one writes upstream's portable command field, which Copilot CLI copies to both shells. Import records shell for shell-specific entries so they still round-trip.
@dyoshikawa
dyoshikawa merged commit 6d74826 into main Jul 29, 2026
9 checks passed
@dyoshikawa
dyoshikawa deleted the resolve-scrap-issue-2402-copilotcli branch July 29, 2026 02:04
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.

2 participants