@primitive.ai/prim 0.1.0-alpha.90 → 0.1.0-alpha.92

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.
Files changed (45) hide show
  1. package/README.md +20 -12
  2. package/SKILL.md +6 -6
  3. package/dist/chunk-26P57LAR.js +1491 -0
  4. package/dist/{chunk-LMRYZL3D.js → chunk-5AFRMOPX.js} +1 -1
  5. package/dist/{chunk-RO3F6JYV.js → chunk-5GYQ4J3D.js} +2 -2
  6. package/dist/chunk-5HRR4AOR.js +264 -0
  7. package/dist/{chunk-3EEFL6NJ.js → chunk-67VNLLBN.js} +261 -1
  8. package/dist/{chunk-UZPBB7V4.js → chunk-ADUTW66W.js} +60 -48
  9. package/dist/{chunk-LEMX3IOG.js → chunk-BTNNEH2W.js} +1 -1
  10. package/dist/{chunk-YWO7O6QG.js → chunk-FBAYCS3X.js} +2 -2
  11. package/dist/{chunk-R26A7TWY.js → chunk-FKXFUUWJ.js} +1 -1
  12. package/dist/chunk-H4UNYFUC.js +196 -0
  13. package/dist/{chunk-CUE2LKLR.js → chunk-KFXF2V5G.js} +1 -1
  14. package/dist/{chunk-6IWNH776.js → chunk-LFFLHSQO.js} +4 -3
  15. package/dist/{chunk-C7T7B45R.js → chunk-LGGMJYY4.js} +150 -21
  16. package/dist/{chunk-MAZWKJGL.js → chunk-M6RIJVRE.js} +42 -232
  17. package/dist/{chunk-2JRX7ZR4.js → chunk-NAHHFSLH.js} +16 -5
  18. package/dist/{chunk-FI3LIRCB.js → chunk-OAAP2MY6.js} +2 -2
  19. package/dist/{chunk-Z7YPFWAZ.js → chunk-PCVGBE5B.js} +10 -268
  20. package/dist/chunk-WX52U7Z2.js +112 -0
  21. package/dist/{chunk-PPQYQEIR.js → chunk-ZB4F75SZ.js} +28 -0
  22. package/dist/daemon/server.js +30 -21
  23. package/dist/hook-runtime/daemon/server.js +30 -21
  24. package/dist/hook-runtime/hooks/post-commit.js +20 -20
  25. package/dist/hook-runtime/hooks/post-rewrite.js +20 -20
  26. package/dist/hook-runtime/hooks/post-tool-use.js +666 -147
  27. package/dist/hook-runtime/hooks/pre-tool-use.js +659 -111
  28. package/dist/hook-runtime/hooks/prim-hook.js +627 -111
  29. package/dist/hook-runtime/hooks/session-end.js +610 -27
  30. package/dist/hook-runtime/hooks/session-start.js +1132 -533
  31. package/dist/hook-runtime/index.js +764 -267
  32. package/dist/hook-runtime/statusline-main.js +48 -4
  33. package/dist/hooks/post-commit.js +11 -9
  34. package/dist/hooks/post-rewrite.js +11 -9
  35. package/dist/hooks/post-tool-use.js +73 -48
  36. package/dist/hooks/pre-commit.js +4 -4
  37. package/dist/hooks/pre-tool-use.js +46 -44
  38. package/dist/hooks/prim-hook.js +47 -25
  39. package/dist/hooks/session-end.js +15 -26
  40. package/dist/hooks/session-start.js +59 -32
  41. package/dist/index.js +561 -1430
  42. package/dist/statusline-main.js +48 -4
  43. package/package.json +1 -1
  44. package/dist/chunk-PMRDE2DA.js +0 -310
  45. package/dist/chunk-WB7AUZ4C.js +0 -52
@@ -524,7 +524,7 @@ var PRIM_REPO_SYNC_REPOSITORY_KEY = "prim.repoSyncRepository";
524
524
  var PRIM_REPO_BINDING_STATE_KEY = "prim.repoBindingState";
525
525
  var GIT_TIMEOUT_MS2 = 1e3;
526
526
  var REPO_SYNC_ID_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/;
527
- var PROJECT_INSTALL_FILES = [".claude/settings.json", ".codex/hooks.json"];
527
+ var PROJECT_INSTALL_FILES = [".claude/settings.json", ".codex/hooks.json", ".cursor/hooks.json"];
528
528
  var PRIM_HOOK_BINS = ["prim-hook", "prim-pre-tool-use", "prim-post-tool-use"];
529
529
  function repoActiveFlag(cwd) {
530
530
  try {
@@ -731,9 +731,8 @@ function debug(msg) {
731
731
  `);
732
732
  }
733
733
  }
734
- async function renderStatusline() {
734
+ async function renderStatusline(cwd = process.cwd()) {
735
735
  const version = readPackageVersion();
736
- const cwd = process.cwd();
737
736
  let ingestion;
738
737
  const resolveIngestion = () => {
739
738
  ingestion ??= decisionIngestionStatus(cwd);
@@ -754,10 +753,55 @@ async function renderStatusline() {
754
753
  });
755
754
  }
756
755
 
756
+ // src/hooks/hook-stdin.ts
757
+ var DEFAULT_MAX_BYTES = 1024 * 1024;
758
+ function readHookStdin(timeoutMs = 1e3, maxBytes = DEFAULT_MAX_BYTES) {
759
+ return new Promise((resolve4, reject) => {
760
+ const chunks = [];
761
+ let bytes = 0;
762
+ let settled = false;
763
+ const finish = (error) => {
764
+ if (settled) return;
765
+ settled = true;
766
+ clearTimeout(timer);
767
+ process.stdin.removeAllListeners("data");
768
+ process.stdin.removeAllListeners("end");
769
+ process.stdin.removeAllListeners("error");
770
+ if (error) reject(error);
771
+ else resolve4(Buffer.concat(chunks, bytes).toString("utf-8"));
772
+ };
773
+ const timer = setTimeout(() => finish(new Error("stdin read timeout")), timeoutMs);
774
+ process.stdin.on("data", (chunk) => {
775
+ bytes += chunk.length;
776
+ if (bytes > maxBytes) {
777
+ finish(new Error("stdin envelope exceeds size limit"));
778
+ return;
779
+ }
780
+ chunks.push(chunk);
781
+ });
782
+ process.stdin.on("end", () => finish());
783
+ process.stdin.on("error", (error) => finish(error));
784
+ });
785
+ }
786
+
757
787
  // src/statusline-main.ts
788
+ async function inputCwd() {
789
+ try {
790
+ const raw = await readHookStdin(200, 64 * 1024);
791
+ const parsed = JSON.parse(raw);
792
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return;
793
+ const input = parsed;
794
+ if (typeof input.cwd === "string" && input.cwd.length > 0) return input.cwd;
795
+ if (input.workspace && typeof input.workspace === "object" && !Array.isArray(input.workspace)) {
796
+ const current = input.workspace.current_dir;
797
+ if (typeof current === "string" && current.length > 0) return current;
798
+ }
799
+ } catch {
800
+ }
801
+ }
758
802
  async function main() {
759
803
  try {
760
- process.stdout.write(await renderStatusline());
804
+ process.stdout.write(await renderStatusline(await inputCwd() ?? process.cwd()));
761
805
  } catch {
762
806
  process.stdout.write(`primitive ${readPackageVersion()} (daemon: unavailable)`);
763
807
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@primitive.ai/prim",
3
- "version": "0.1.0-alpha.90",
3
+ "version": "0.1.0-alpha.92",
4
4
  "description": "CLI for Primitive's decision graph — passive decision capture, conflict gate, and team presence",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,310 +0,0 @@
1
- import {
2
- stripControlChars
3
- } from "./chunk-Z7YPFWAZ.js";
4
-
5
- // src/lib/bin-path.ts
6
- import { existsSync, readFileSync } from "fs";
7
- import { dirname, isAbsolute, join } from "path";
8
- import { fileURLToPath } from "url";
9
-
10
- // src/lib/semver.ts
11
- function parseSemver(value) {
12
- if (typeof value !== "string" || value.length > 256) return;
13
- const match = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/u.exec(
14
- value
15
- );
16
- if (!match) return;
17
- const prerelease = match[4]?.split(".") ?? [];
18
- if (prerelease.some((part) => /^\d+$/u.test(part) && part.length > 1 && part.startsWith("0"))) {
19
- return;
20
- }
21
- return { core: [BigInt(match[1]), BigInt(match[2]), BigInt(match[3])], prerelease };
22
- }
23
- function compareSemver(left, right) {
24
- const a = parseSemver(left);
25
- const b = parseSemver(right);
26
- if (!a || !b) return;
27
- for (let i = 0; i < a.core.length; i += 1) {
28
- if (a.core[i] !== b.core[i]) return a.core[i] < b.core[i] ? -1 : 1;
29
- }
30
- if (a.prerelease.length === 0 || b.prerelease.length === 0) {
31
- return a.prerelease.length === b.prerelease.length ? 0 : a.prerelease.length === 0 ? 1 : -1;
32
- }
33
- for (let i = 0; i < Math.max(a.prerelease.length, b.prerelease.length); i += 1) {
34
- const x = a.prerelease[i];
35
- const y = b.prerelease[i];
36
- if (x === void 0 || y === void 0) return x === void 0 ? -1 : 1;
37
- if (x === y) continue;
38
- const xNumeric = /^\d+$/u.test(x);
39
- const yNumeric = /^\d+$/u.test(y);
40
- if (xNumeric && yNumeric) return BigInt(x) < BigInt(y) ? -1 : 1;
41
- if (xNumeric !== yNumeric) return xNumeric ? -1 : 1;
42
- return x < y ? -1 : 1;
43
- }
44
- return 0;
45
- }
46
-
47
- // src/lib/bin-path.ts
48
- var PKG_NAME = "@primitive.ai/prim";
49
- var ROOT_WALK_LIMIT = 6;
50
- var STABLE_HOOK_LAUNCHER_NAME = "prim-hook-launcher-v1";
51
- var resolvedRoot;
52
- function locateRoot() {
53
- if (resolvedRoot !== void 0) {
54
- return resolvedRoot;
55
- }
56
- let dir = dirname(fileURLToPath(import.meta.url));
57
- for (let depth = 0; depth < ROOT_WALK_LIMIT; depth++) {
58
- const manifestPath = join(dir, "package.json");
59
- if (existsSync(manifestPath)) {
60
- try {
61
- const manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
62
- if (manifest.name === PKG_NAME && manifest.bin) {
63
- resolvedRoot = { dir, version: manifest.version, bin: manifest.bin };
64
- return resolvedRoot;
65
- }
66
- } catch {
67
- }
68
- }
69
- const parent = dirname(dir);
70
- if (parent === dir) {
71
- break;
72
- }
73
- dir = parent;
74
- }
75
- resolvedRoot = null;
76
- return resolvedRoot;
77
- }
78
- function binFile(bin) {
79
- const root = locateRoot();
80
- const rel = root?.bin[bin];
81
- if (!root || !rel) {
82
- return null;
83
- }
84
- return isAbsolute(rel) ? rel : join(root.dir, rel);
85
- }
86
- function packageVersion() {
87
- return locateRoot()?.version ?? null;
88
- }
89
- function packageRoot() {
90
- return locateRoot()?.dir ?? null;
91
- }
92
- function shellQuote(value) {
93
- return `'${value.replaceAll("'", `'"'"'`)}'`;
94
- }
95
- function shellWord(value) {
96
- return /^[A-Za-z0-9_@%+=:,./-]+$/u.test(value) ? value : shellQuote(value);
97
- }
98
- function pinnedNpxArgs(bin, args = [], options = {}) {
99
- const version = packageVersion();
100
- if (!version) throw new Error("cannot determine Primitive package version");
101
- return [
102
- "--yes",
103
- "--ignore-scripts",
104
- ...options.preferOnline ? ["--prefer-online"] : [],
105
- "-p",
106
- `${PKG_NAME}@${version}`,
107
- bin,
108
- ...args
109
- ];
110
- }
111
- function pinnedNpxCommand(bin, args = [], options = {}) {
112
- return ["npx", ...pinnedNpxArgs(bin, args, options)].map(shellWord).join(" ");
113
- }
114
- function pinnedHookCommand(bin, args = "") {
115
- const suffix = args ? ` ${args}` : "";
116
- const fallback = `${pinnedNpxCommand(bin)}${suffix}`;
117
- const file = binFile(bin);
118
- if (!file) return fallback;
119
- return `if [ -x ${shellQuote(process.execPath)} ] && [ -f ${shellQuote(file)} ]; then ${shellQuote(process.execPath)} ${shellQuote(file)}${suffix}; else ${fallback}; fi`;
120
- }
121
- var STABLE_HOOK_ARGUMENTS_RE = /^[-A-Za-z0-9_ ]*$/u;
122
- var STABLE_HOOK_BIN_RE = /^[A-Za-z0-9][A-Za-z0-9-]*$/u;
123
- function stableHookCommand(bin, args = "") {
124
- if (!STABLE_HOOK_BIN_RE.test(bin) || !STABLE_HOOK_ARGUMENTS_RE.test(args)) {
125
- throw new Error("invalid stable hook command");
126
- }
127
- const resolver = [
128
- // #242 and earlier identify managed commands by this package marker. Keep
129
- // it as inert data during the rolling window so an older uninstall or
130
- // reinstall can remove the stable entry without invoking npm or PATH.
131
- `prim_legacy_reader='-p ${PKG_NAME}@stable prim-shim.sh ${bin} '; `,
132
- 'prim_absolute() { case "$1" in /*) ;; *) return 1 ;; esac; case "$1" in [[:space:]]*|*[[:space:]]|*//*|*/./*|*/../*|*/.|*/..|?*/) return 1 ;; esac; }; ',
133
- 'prim_config=${PRIM_CONFIG_DIR:-}; if ! prim_absolute "$prim_config"; then prim_config=${XDG_CONFIG_HOME:-}; if prim_absolute "$prim_config"; then ',
134
- 'case "$prim_config" in /) prim_config=/prim ;; *) prim_config="$prim_config/prim" ;; esac; ',
135
- 'else prim_home=${HOME:-}; prim_absolute "$prim_home" || exit 78; case "$prim_home" in /) prim_config=/.config/prim ;; *) prim_config="$prim_home/.config/prim" ;; esac; ',
136
- "fi; fi; ",
137
- `case "$prim_config" in /) prim_launcher=/${STABLE_HOOK_LAUNCHER_NAME} ;; *) prim_launcher="$prim_config/${STABLE_HOOK_LAUNCHER_NAME}" ;; esac; `,
138
- 'exec "$prim_launcher" "$@"'
139
- ].join("");
140
- const suffix = args ? ` ${args}` : "";
141
- return `/bin/sh -c ${shellQuote(resolver)} ${STABLE_HOOK_LAUNCHER_NAME} ${bin}${suffix}`;
142
- }
143
- function detachedHookShimCommand(bin, args = "") {
144
- return `payload=$(cat); { trap '' HUP; printf '%s' "$payload" | { ${stableHookCommand(bin, args)}; }; } </dev/null >/dev/null 2>&1 &`;
145
- }
146
- function commandMatchesBin(command, bin) {
147
- if (!command) {
148
- return false;
149
- }
150
- const c = command.trim();
151
- if (c === bin || c.startsWith(`${bin} `)) {
152
- return true;
153
- }
154
- const exactBin = new RegExp(`(?:^|\\s)${bin.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?:\\s|;|$)`);
155
- return c.includes(`command -v ${bin} `) || c.includes(`-p ${PKG_NAME}@`) && exactBin.test(c) || c.includes(STABLE_HOOK_LAUNCHER_NAME) && exactBin.test(c);
156
- }
157
- function exactPinnedNpxVersion(command, bin) {
158
- const escapedBin = bin.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
159
- const shellQuoted = `'(?:[^']|'"'"')*'`;
160
- const safeArgs = "(?: [A-Za-z0-9_@%+=:,./-]+)*";
161
- const direct = new RegExp(
162
- `^npx --yes --ignore-scripts -p @primitive\\.ai/prim@(?<version>[0-9A-Za-z.+-]+) ${escapedBin}${safeArgs}$`,
163
- "u"
164
- ).exec(command);
165
- const wrapped = new RegExp(
166
- `^if \\[ -x (?<node>${shellQuoted}) \\] && \\[ -f (?<entry>${shellQuoted}) \\]; then \\k<node> \\k<entry>(?<args>${safeArgs}); else npx --yes --ignore-scripts -p @primitive\\.ai/prim@(?<version>[0-9A-Za-z.+-]+) ${escapedBin}\\k<args>; fi$`,
167
- "u"
168
- ).exec(command);
169
- const version = direct?.groups?.version ?? wrapped?.groups?.version;
170
- return version && compareSemver(version, version) !== void 0 ? version : void 0;
171
- }
172
- function hookCommandResolution(command, bin) {
173
- const trimmed = command?.trim();
174
- if (!trimmed || !commandMatchesBin(trimmed, bin)) return void 0;
175
- if (trimmed.includes(STABLE_HOOK_LAUNCHER_NAME)) return { kind: "stable_launcher" };
176
- const version = exactPinnedNpxVersion(trimmed, bin);
177
- return version ? { kind: "exact_npx_fallback", version } : { kind: "legacy_path" };
178
- }
179
- function hookCommandResolutions(commands, bins) {
180
- const resolutions = [];
181
- for (const command of commands) {
182
- for (const bin of bins) {
183
- const resolution = hookCommandResolution(command, bin);
184
- if (resolution) resolutions.push(resolution);
185
- }
186
- }
187
- return resolutions;
188
- }
189
-
190
- // src/lib/presence.ts
191
- var DECISION_ORIGIN = "https://app.getprimitive.ai";
192
- function validDecisionUrl(value) {
193
- if (typeof value !== "string" || stripControlChars(value) !== value) {
194
- return void 0;
195
- }
196
- try {
197
- const url = new URL(value);
198
- if (url.origin !== DECISION_ORIGIN || url.username !== "" || url.password !== "" || url.search !== "" || url.hash !== "" || !/^\/decisions\/[^/]+$/u.test(url.pathname)) {
199
- return void 0;
200
- }
201
- return url.href;
202
- } catch {
203
- return void 0;
204
- }
205
- }
206
- function decisionLink(label, decisionUrl, plain) {
207
- const url = validDecisionUrl(decisionUrl);
208
- if (plain || !url) {
209
- return label;
210
- }
211
- return `\x1B]8;;${url}\x07\x1B[34;4m${label}\x1B[0m\x1B]8;;\x07`;
212
- }
213
- function formatLabeled(labels, cap) {
214
- if (labels === void 0) {
215
- return "\u2014";
216
- }
217
- if (labels.length === 0) {
218
- return "just you";
219
- }
220
- if (labels.length <= cap) {
221
- return labels.join(", ");
222
- }
223
- return `${labels.slice(0, cap).join(", ")} +${String(labels.length - cap)}`;
224
- }
225
- function formatTeammates(names, cap) {
226
- return formatLabeled(names?.map(stripControlChars), cap);
227
- }
228
- function formatTeammatesWithArea(teammates, cap, plainLinks = false) {
229
- return formatLabeled(
230
- teammates?.map((t) => {
231
- const name = stripControlChars(t.name);
232
- const area = stripControlChars(t.area ?? "").trim();
233
- const label = area ? `${name} - ${area}` : name;
234
- return decisionLink(label, t.decisionUrl, plainLinks);
235
- }),
236
- cap
237
- );
238
- }
239
-
240
- // src/lib/statusline-render.ts
241
- function repositoryBindingDiagnosticLabel(state) {
242
- if (state === "unbound") return "GitHub repo connection: required (run `prim github connect`)";
243
- if (state === "invalid") return "GitHub repo connection: invalid (run `prim doctor`)";
244
- return void 0;
245
- }
246
- var STATUSLINE_NAME_CAP = 3;
247
- function formatStatusline(version, snapshot, resolveIngestionStatus, options = {}) {
248
- const ingestionSuffix = (status) => status === void 0 ? "" : ` \xB7 Decision ingestion ${status}`;
249
- const ingestionStatus = snapshot === null || snapshot.healthy === false ? options.includeIngestionWhenUnavailable ? resolveIngestionStatus() : void 0 : resolveIngestionStatus();
250
- if (snapshot?.healthy === false && snapshot.needsReauth) {
251
- return `primitive ${version} (daemon: paused \xB7 run \`prim auth login\`${ingestionSuffix(ingestionStatus)})`;
252
- }
253
- const repositoryLabel = repositoryBindingDiagnosticLabel(
254
- snapshot !== null && snapshot.healthy !== false || options.includeIngestionWhenUnavailable === true ? options.resolveRepositoryBindingState?.() : void 0
255
- );
256
- const repositorySuffix = repositoryLabel ? ` \xB7 ${repositoryLabel}` : "";
257
- if (!snapshot) {
258
- return `primitive ${version} (daemon: down${repositorySuffix}${ingestionSuffix(ingestionStatus)})`;
259
- }
260
- if (snapshot.healthy === false) {
261
- if (snapshot.ingestion?.healthy === false) {
262
- const pending = snapshot.ingestion.pendingCount;
263
- const qualifier = snapshot.ingestion.pendingSampled ? "at least " : "";
264
- return `primitive ${version} (daemon: degraded \xB7 delivery: stalled${typeof pending === "number" ? ` \xB7 ${qualifier}${String(pending)} pending` : ""}${repositorySuffix}${ingestionSuffix(ingestionStatus)})`;
265
- }
266
- if (snapshot.heartbeat?.healthy === false) {
267
- return `primitive ${version} (daemon: degraded \xB7 presence: unavailable${repositorySuffix}${ingestionSuffix(ingestionStatus)})`;
268
- }
269
- return `primitive ${version} (daemon: starting${repositorySuffix}${ingestionSuffix(ingestionStatus)})`;
270
- }
271
- if (snapshot.envMismatch) {
272
- return `primitive ${version} (daemon: live, Decision ingestion ${ingestionStatus}${repositorySuffix} \xB7 presence: other env)`;
273
- }
274
- if (snapshot.principalMismatch) {
275
- return `primitive ${version} (daemon: live, Decision ingestion ${ingestionStatus}${repositorySuffix} \xB7 presence: other account)`;
276
- }
277
- if (snapshot.presenceStale) {
278
- return `primitive ${version} (daemon: live, Decision ingestion ${ingestionStatus}${repositorySuffix} \xB7 presence: stale)`;
279
- }
280
- let team;
281
- if (snapshot.onlineTeammates !== void 0) {
282
- team = `team: ${formatTeammatesWithArea(snapshot.onlineTeammates, STATUSLINE_NAME_CAP, options.plainLinks === true)}`;
283
- } else if (snapshot.onlineNames !== void 0) {
284
- team = `team: ${formatTeammates(snapshot.onlineNames, STATUSLINE_NAME_CAP)}`;
285
- } else if (typeof snapshot.onlineCount === "number") {
286
- team = `team: ${String(snapshot.onlineCount)} online`;
287
- } else {
288
- team = "team: \u2014";
289
- }
290
- return `primitive ${version} (daemon: live, Decision ingestion ${ingestionStatus}${repositorySuffix} \xB7 ${team})`;
291
- }
292
-
293
- export {
294
- compareSemver,
295
- STABLE_HOOK_LAUNCHER_NAME,
296
- binFile,
297
- packageVersion,
298
- packageRoot,
299
- pinnedNpxArgs,
300
- pinnedNpxCommand,
301
- pinnedHookCommand,
302
- stableHookCommand,
303
- detachedHookShimCommand,
304
- commandMatchesBin,
305
- hookCommandResolution,
306
- hookCommandResolutions,
307
- formatTeammates,
308
- repositoryBindingDiagnosticLabel,
309
- formatStatusline
310
- };
@@ -1,52 +0,0 @@
1
- // src/hooks/agent.ts
2
- function parseAgent(argv) {
3
- const i = argv.indexOf("--agent");
4
- const value = i !== -1 ? argv[i + 1] : void 0;
5
- if (value === "codex" || value === "hermes") {
6
- return value;
7
- }
8
- return "claude_code";
9
- }
10
-
11
- // src/hooks/normalize.ts
12
- import { createHash } from "crypto";
13
- var HERMES_EVENT_MAP = {
14
- on_session_start: "SessionStart",
15
- on_session_end: "SessionEnd",
16
- pre_llm_call: "UserPromptSubmit",
17
- post_llm_call: "Stop",
18
- pre_tool_call: "PreToolUse",
19
- post_tool_call: "PostToolUse",
20
- subagent_stop: "SubagentStop"
21
- };
22
- function normalizeEnvelope(parsed, agent) {
23
- if (agent === "codex") {
24
- const event = parsed.hook_event_name;
25
- if ((event === "PreToolUse" || event === "PostToolUse") && (typeof parsed.tool_use_id !== "string" || parsed.tool_use_id.length === 0)) {
26
- const stableToolIdentity = JSON.stringify([
27
- parsed.session_id ?? null,
28
- parsed.turn_id ?? null,
29
- parsed.tool_name ?? null,
30
- parsed.tool_input ?? null
31
- ]);
32
- return {
33
- ...parsed,
34
- tool_use_id: `codex:fallback:v1:${createHash("sha256").update(stableToolIdentity).digest("hex")}`
35
- };
36
- }
37
- return parsed;
38
- }
39
- if (agent !== "hermes") {
40
- return parsed;
41
- }
42
- const raw = parsed.hook_event_name;
43
- if (typeof raw === "string" && raw in HERMES_EVENT_MAP) {
44
- return { ...parsed, hook_event_name: HERMES_EVENT_MAP[raw] };
45
- }
46
- return parsed;
47
- }
48
-
49
- export {
50
- parseAgent,
51
- normalizeEnvelope
52
- };