@alessandroraffa/tangyr 0.21.3 → 0.21.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +61 -8
- package/mappings/hook-events.yaml +44 -34
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -25777,7 +25777,11 @@ function compileCursorHooks(sourceHooksJson, mappings, lossReport, sourceLabel)
|
|
|
25777
25777
|
}
|
|
25778
25778
|
const untranslatable = /* @__PURE__ */ new Set();
|
|
25779
25779
|
hooks[mapping.target_event] = entries.map((entry) => {
|
|
25780
|
-
const matcher = entry.matcher === void 0 ? void 0 :
|
|
25780
|
+
const matcher = entry.matcher === void 0 ? void 0 : translateMatcher(
|
|
25781
|
+
entry.matcher,
|
|
25782
|
+
CURSOR_TOOL_NAMES,
|
|
25783
|
+
untranslatable
|
|
25784
|
+
);
|
|
25781
25785
|
return {
|
|
25782
25786
|
type: "command",
|
|
25783
25787
|
command: entry.command,
|
|
@@ -25815,6 +25819,23 @@ function compileCursorHooks(sourceHooksJson, mappings, lossReport, sourceLabel)
|
|
|
25815
25819
|
}
|
|
25816
25820
|
return { payload: hooks, translated, dropped, droppedEvents };
|
|
25817
25821
|
}
|
|
25822
|
+
function translateCopilotMatchers(payload, untranslatable) {
|
|
25823
|
+
const entries = Array.isArray(payload) ? payload : [payload];
|
|
25824
|
+
const translated = entries.map((entry) => {
|
|
25825
|
+
if (!isRecord(entry) || typeof entry.matcher !== "string") {
|
|
25826
|
+
return entry;
|
|
25827
|
+
}
|
|
25828
|
+
return {
|
|
25829
|
+
...entry,
|
|
25830
|
+
matcher: translateMatcher(
|
|
25831
|
+
entry.matcher,
|
|
25832
|
+
COPILOT_TOOL_NAMES,
|
|
25833
|
+
untranslatable
|
|
25834
|
+
)
|
|
25835
|
+
};
|
|
25836
|
+
});
|
|
25837
|
+
return Array.isArray(payload) ? translated : translated[0];
|
|
25838
|
+
}
|
|
25818
25839
|
function compileOpenCodeHooks(sourceHooksJson, lossReport, sourceLabel) {
|
|
25819
25840
|
const sourceHooks = isRecord(sourceHooksJson) && isRecord(sourceHooksJson.hooks) ? sourceHooksJson.hooks : {};
|
|
25820
25841
|
for (const eventName of Object.keys(sourceHooks)) {
|
|
@@ -25918,8 +25939,22 @@ function compileCopilotHooks(sourceHooksJson, mappings, lossReport, sourceLabel)
|
|
|
25918
25939
|
sourceEvent
|
|
25919
25940
|
);
|
|
25920
25941
|
if (mapping.status === "mapped" && mapping.target_event) {
|
|
25921
|
-
|
|
25942
|
+
const untranslatable = /* @__PURE__ */ new Set();
|
|
25943
|
+
hooks[mapping.target_event] = translateCopilotMatchers(
|
|
25944
|
+
payload,
|
|
25945
|
+
untranslatable
|
|
25946
|
+
);
|
|
25922
25947
|
translated += 1;
|
|
25948
|
+
if (untranslatable.size > 0) {
|
|
25949
|
+
addInformational(
|
|
25950
|
+
lossReport,
|
|
25951
|
+
"copilot",
|
|
25952
|
+
"hooks",
|
|
25953
|
+
sourceLabel,
|
|
25954
|
+
"warning",
|
|
25955
|
+
`${sourceEvent}: ${[...untranslatable].map((m) => `'${m}'`).join(", ")} ${untranslatable.size === 1 ? "names a tool" : "name tools"} with no known Copilot equivalent and ${untranslatable.size === 1 ? "was" : "were"} written through unchanged. Copilot matches on its own tool names \u2014 measured: bash, view, create, edit, grep \u2014 and the match is a full, case-sensitive regex, so a hook scoped to a name it does not use is accepted and never runs. To fix: add the name to COPILOT_TOOL_NAMES in the compiler once its Copilot equivalent has been measured.`
|
|
25956
|
+
);
|
|
25957
|
+
}
|
|
25923
25958
|
if (mapping.severity || mapping.reason) {
|
|
25924
25959
|
addInformational(
|
|
25925
25960
|
lossReport,
|
|
@@ -25963,21 +25998,39 @@ var CURSOR_TOOL_NAMES = {
|
|
|
25963
25998
|
Write: "Write",
|
|
25964
25999
|
Grep: "Grep"
|
|
25965
26000
|
};
|
|
25966
|
-
|
|
26001
|
+
var COPILOT_TOOL_NAMES = {
|
|
26002
|
+
Bash: "bash",
|
|
26003
|
+
Read: "view",
|
|
26004
|
+
Write: "create",
|
|
26005
|
+
Edit: "edit",
|
|
26006
|
+
MultiEdit: "edit",
|
|
26007
|
+
Grep: "grep",
|
|
26008
|
+
// Copilot's own names map to themselves, so a kit written against this
|
|
26009
|
+
// mapping is not reported as using something unknown.
|
|
26010
|
+
bash: "bash",
|
|
26011
|
+
view: "view",
|
|
26012
|
+
create: "create",
|
|
26013
|
+
edit: "edit",
|
|
26014
|
+
grep: "grep"
|
|
26015
|
+
};
|
|
26016
|
+
function translateMatcher(matcher, table, untranslatable) {
|
|
25967
26017
|
const translated = [];
|
|
25968
26018
|
for (const token of matcher.split("|")) {
|
|
25969
26019
|
const trimmed = token.trim();
|
|
25970
26020
|
if (!trimmed) continue;
|
|
25971
|
-
const mapped =
|
|
25972
|
-
if (mapped
|
|
25973
|
-
|
|
25974
|
-
if (!translated.includes(trimmed)) translated.push(trimmed);
|
|
26021
|
+
const mapped = table[trimmed];
|
|
26022
|
+
if (mapped !== void 0) {
|
|
26023
|
+
if (!translated.includes(mapped)) translated.push(mapped);
|
|
25975
26024
|
continue;
|
|
25976
26025
|
}
|
|
25977
|
-
if (
|
|
26026
|
+
if (PLAIN_TOOL_NAME.test(trimmed)) {
|
|
26027
|
+
untranslatable.add(trimmed);
|
|
26028
|
+
}
|
|
26029
|
+
if (!translated.includes(trimmed)) translated.push(trimmed);
|
|
25978
26030
|
}
|
|
25979
26031
|
return translated.join("|");
|
|
25980
26032
|
}
|
|
26033
|
+
var PLAIN_TOOL_NAME = /^[A-Za-z][A-Za-z0-9_-]*$/u;
|
|
25981
26034
|
function extractHookCommands(payload) {
|
|
25982
26035
|
const entries = Array.isArray(payload) ? payload : [payload];
|
|
25983
26036
|
const found = [];
|
|
@@ -12,7 +12,7 @@ notes:
|
|
|
12
12
|
- Source events below are the events the canonical agent-coding kit registers, plus SessionStart.
|
|
13
13
|
- An event a kit registers but this file does not list is not silently dropped — the compilers report it as unmapped and name this file. Keeping the two in step is the point of that report.
|
|
14
14
|
- SessionStart, UserPromptSubmit and PostToolUseFailure were added on 2026-09-04. UserPromptSubmit and PostToolUseFailure were already registered by the kit and were being dropped for every non-claude-code target with no reason attached, because an event absent from this file was indistinguishable from one deliberately dropped.
|
|
15
|
-
- Copilot event coverage
|
|
15
|
+
- Copilot event coverage was settled on 2026-09-07 and no longer needs a probe: the CLI ships a JSON schema (schemas/api.schema.json, definition HookType) enumerating seventeen hook events with descriptions, and one live session confirmed the file is loaded and fires. The note this replaces said no stable denominator was published; the vendor ships one inside the tool.
|
|
16
16
|
- Codex hook support is currently a macOS/Linux baseline; Windows remains unsupported unless vendor documentation changes.
|
|
17
17
|
|
|
18
18
|
source_events:
|
|
@@ -42,53 +42,63 @@ targets:
|
|
|
42
42
|
|
|
43
43
|
copilot:
|
|
44
44
|
delivery: mapped
|
|
45
|
-
|
|
45
|
+
# Measured on 2026-09-07 against GitHub Copilot CLI 1.0.83, which ships a
|
|
46
|
+
# JSON schema documenting its hook contract — schemas/api.schema.json,
|
|
47
|
+
# definition HookType — and which was probed live in a real agent turn.
|
|
48
|
+
# These are results, not a reading of a binary.
|
|
49
|
+
#
|
|
50
|
+
# The event enum has seventeen values, all camelCase, each with a written
|
|
51
|
+
# description: preToolUse, preMcpToolCall, postToolUse, postToolUseFailure,
|
|
52
|
+
# userPromptSubmitted, userPromptTransformed, sessionStart, sessionEnd,
|
|
53
|
+
# postResult, prePRDescription, errorOccurred, agentStop, subagentStart,
|
|
54
|
+
# subagentStop, preCompact, permissionRequest, notification.
|
|
55
|
+
#
|
|
56
|
+
# Every source event below has an equivalent. The entries this replaces
|
|
57
|
+
# said otherwise: six were marked `probe` with the reason "not probeable on
|
|
58
|
+
# the machine this mapping was last measured on", and PreCompact was a
|
|
59
|
+
# `drop` claiming "no documented user-level equivalent" for an event the
|
|
60
|
+
# vendor's own schema documents. `Stop` pointed at sessionEnd — the session
|
|
61
|
+
# ending — where agentStop is the agent stopping, which is what it means.
|
|
62
|
+
#
|
|
63
|
+
# The file shape was already right and is unchanged: Copilot accepts Claude
|
|
64
|
+
# Code's nested matcher/hooks structure under a top-level `hooks` object,
|
|
65
|
+
# and its log says so when it does not. What made a kit's hooks reach
|
|
66
|
+
# Copilot and do nothing is the matcher: Copilot matches on its own tool
|
|
67
|
+
# names — measured bash, view, create, edit, grep — with a full,
|
|
68
|
+
# case-sensitive regex, so `Bash` never matched `bash`. Translation lives
|
|
69
|
+
# in COPILOT_TOOL_NAMES in compiler/hooks.ts.
|
|
70
|
+
#
|
|
71
|
+
# One limit worth recording: in prompt mode (-p) repository hooks under
|
|
72
|
+
# .github/hooks/ load only once the folder is trusted. User-level hooks in
|
|
73
|
+
# ~/.copilot/hooks/ have no such gate, which is how this was probed.
|
|
46
74
|
source_to_target:
|
|
47
75
|
SessionStart:
|
|
48
|
-
status:
|
|
49
|
-
|
|
50
|
-
Not probed, and not probeable on the machine this mapping was last measured on
|
|
51
|
-
(2026-09-04): no Copilot CLI is installed there, and ~/.copilot/hooks is empty, so no
|
|
52
|
-
hook can be made to fire from a terminal. To settle it: install the Copilot CLI, register
|
|
53
|
-
a hook per event that appends its payload to a file, and drive one session that submits a
|
|
54
|
-
prompt, runs a tool, fails a tool and ends.
|
|
76
|
+
status: mapped
|
|
77
|
+
target_event: sessionStart
|
|
55
78
|
UserPromptSubmit:
|
|
56
|
-
status:
|
|
57
|
-
|
|
58
|
-
Not probed, and not probeable on the machine this mapping was last measured on
|
|
59
|
-
(2026-09-04): no Copilot CLI is installed there, and ~/.copilot/hooks is empty, so no
|
|
60
|
-
hook can be made to fire from a terminal. To settle it: install the Copilot CLI, register
|
|
61
|
-
a hook per event that appends its payload to a file, and drive one session that submits a
|
|
62
|
-
prompt, runs a tool, fails a tool and ends.
|
|
63
|
-
PostToolUseFailure:
|
|
64
|
-
status: probe
|
|
65
|
-
reason: >-
|
|
66
|
-
Not probed, and not probeable on the machine this mapping was last measured on
|
|
67
|
-
(2026-09-04): no Copilot CLI is installed there, and ~/.copilot/hooks is empty, so no
|
|
68
|
-
hook can be made to fire from a terminal. To settle it: install the Copilot CLI, register
|
|
69
|
-
a hook per event that appends its payload to a file, and drive one session that submits a
|
|
70
|
-
prompt, runs a tool, fails a tool and ends.
|
|
79
|
+
status: mapped
|
|
80
|
+
target_event: userPromptSubmitted
|
|
71
81
|
PreToolUse:
|
|
72
82
|
status: mapped
|
|
73
83
|
target_event: preToolUse
|
|
74
84
|
PostToolUse:
|
|
75
85
|
status: mapped
|
|
76
86
|
target_event: postToolUse
|
|
87
|
+
PostToolUseFailure:
|
|
88
|
+
status: mapped
|
|
89
|
+
target_event: postToolUseFailure
|
|
77
90
|
PreCompact:
|
|
78
|
-
status:
|
|
79
|
-
|
|
80
|
-
reason: No documented user-level equivalent in the active baseline.
|
|
91
|
+
status: mapped
|
|
92
|
+
target_event: preCompact
|
|
81
93
|
SubagentStart:
|
|
82
|
-
status:
|
|
83
|
-
|
|
94
|
+
status: mapped
|
|
95
|
+
target_event: subagentStart
|
|
84
96
|
SubagentStop:
|
|
85
|
-
status:
|
|
86
|
-
|
|
97
|
+
status: mapped
|
|
98
|
+
target_event: subagentStop
|
|
87
99
|
Stop:
|
|
88
100
|
status: mapped
|
|
89
|
-
target_event:
|
|
90
|
-
severity: warning
|
|
91
|
-
reason: Closest documented session-end lifecycle event, not a one-to-one semantic equivalent.
|
|
101
|
+
target_event: agentStop
|
|
92
102
|
|
|
93
103
|
codex:
|
|
94
104
|
delivery: partial
|