@primitive.ai/prim 0.1.0-alpha.68 → 0.1.0-alpha.69

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 (44) hide show
  1. package/README.md +39 -1
  2. package/SKILL.md +1 -1
  3. package/dist/{chunk-XPVNH3J6.js → chunk-2KW7DVFJ.js} +121 -130
  4. package/dist/chunk-3EEFL6NJ.js +529 -0
  5. package/dist/chunk-4A2XB2PC.js +310 -0
  6. package/dist/{chunk-G5D3FF3D.js → chunk-BQUJ4AFJ.js} +1 -83
  7. package/dist/chunk-CUE2LKLR.js +155 -0
  8. package/dist/chunk-FI3LIRCB.js +262 -0
  9. package/dist/{chunk-CPSE3Y3T.js → chunk-H64F6QHV.js} +27 -8
  10. package/dist/{chunk-I5BHJQH2.js → chunk-KKP2NYZ3.js} +206 -30
  11. package/dist/chunk-LEMX3IOG.js +79 -0
  12. package/dist/{chunk-U6L2RU67.js → chunk-LMRYZL3D.js} +52 -45
  13. package/dist/{chunk-XUAP572Z.js → chunk-RO3F6JYV.js} +8 -7
  14. package/dist/{chunk-TDRXHBEX.js → chunk-TJTVHDJ5.js} +41 -18
  15. package/dist/{chunk-TCDUH7AN.js → chunk-WB7AUZ4C.js} +17 -0
  16. package/dist/{chunk-UN5O5SYG.js → chunk-YWO7O6QG.js} +14 -53
  17. package/dist/chunk-Z7YPFWAZ.js +917 -0
  18. package/dist/{chunk-BDGQEJA5.js → chunk-ZOSNEO5N.js} +2 -2
  19. package/dist/daemon/server.js +11634 -391
  20. package/dist/hook-runtime/daemon/server.js +13353 -0
  21. package/dist/hook-runtime/hooks/post-commit.js +1128 -0
  22. package/dist/hook-runtime/hooks/post-rewrite.js +1148 -0
  23. package/dist/hook-runtime/hooks/post-tool-use.js +7586 -0
  24. package/dist/hook-runtime/hooks/pre-commit.js +1314 -0
  25. package/dist/hook-runtime/hooks/pre-tool-use.js +7099 -0
  26. package/dist/hook-runtime/hooks/prim-hook.js +7691 -0
  27. package/dist/hook-runtime/hooks/session-end.js +495 -0
  28. package/dist/hook-runtime/hooks/session-start.js +11284 -0
  29. package/dist/hook-runtime/index.js +42775 -0
  30. package/dist/hook-runtime/statusline-main.js +765 -0
  31. package/dist/hooks/post-commit.js +7 -4
  32. package/dist/hooks/post-rewrite.js +7 -4
  33. package/dist/hooks/post-tool-use.js +21 -19
  34. package/dist/hooks/pre-commit.js +4 -3
  35. package/dist/hooks/pre-tool-use.js +59 -18
  36. package/dist/hooks/prim-hook.js +39 -56
  37. package/dist/hooks/session-end.js +3 -2
  38. package/dist/hooks/session-start.js +15 -12
  39. package/dist/index.js +15050 -2479
  40. package/dist/statusline-main.js +477 -89
  41. package/package.json +11 -5
  42. package/dist/chunk-K3AYW6VZ.js +0 -300
  43. package/dist/chunk-RTLFE6EZ.js +0 -518
  44. package/dist/chunk-UTKQTZHL.js +0 -88
@@ -2,21 +2,24 @@
2
2
  import {
3
3
  commitAttributionFromEnvironment,
4
4
  toCommitMove
5
- } from "../chunk-CPSE3Y3T.js";
5
+ } from "../chunk-H64F6QHV.js";
6
6
  import {
7
7
  appendMove,
8
8
  resolveOrg
9
- } from "../chunk-UN5O5SYG.js";
9
+ } from "../chunk-YWO7O6QG.js";
10
10
  import {
11
11
  getOrCreateWorkspaceId
12
12
  } from "../chunk-UVIWZWM6.js";
13
+ import "../chunk-FI3LIRCB.js";
14
+ import "../chunk-LEMX3IOG.js";
13
15
  import {
14
16
  githubRepositoryFullName,
15
17
  isRepoActiveForCapture,
16
18
  repoSyncId,
17
19
  resolveRepositoryContext
18
- } from "../chunk-TDRXHBEX.js";
19
- import "../chunk-RTLFE6EZ.js";
20
+ } from "../chunk-TJTVHDJ5.js";
21
+ import "../chunk-Z7YPFWAZ.js";
22
+ import "../chunk-3EEFL6NJ.js";
20
23
 
21
24
  // src/hooks/post-commit.ts
22
25
  import { execFileSync, spawn } from "child_process";
@@ -2,21 +2,24 @@
2
2
  import {
3
3
  canonicalRewritePairs,
4
4
  toRewriteMove
5
- } from "../chunk-CPSE3Y3T.js";
5
+ } from "../chunk-H64F6QHV.js";
6
6
  import {
7
7
  appendMove,
8
8
  resolveOrg
9
- } from "../chunk-UN5O5SYG.js";
9
+ } from "../chunk-YWO7O6QG.js";
10
10
  import {
11
11
  getOrCreateWorkspaceId
12
12
  } from "../chunk-UVIWZWM6.js";
13
+ import "../chunk-FI3LIRCB.js";
14
+ import "../chunk-LEMX3IOG.js";
13
15
  import {
14
16
  githubRepositoryFullName,
15
17
  isRepoActiveForCapture,
16
18
  repoSyncId,
17
19
  resolveRepositoryContext
18
- } from "../chunk-TDRXHBEX.js";
19
- import "../chunk-RTLFE6EZ.js";
20
+ } from "../chunk-TJTVHDJ5.js";
21
+ import "../chunk-Z7YPFWAZ.js";
22
+ import "../chunk-3EEFL6NJ.js";
20
23
 
21
24
  // src/hooks/post-rewrite.ts
22
25
  import { execFileSync, spawn } from "child_process";
@@ -5,44 +5,47 @@ import {
5
5
  import {
6
6
  enrichHookPayloadWithFileRefs,
7
7
  preserveHookFileMetadata
8
- } from "../chunk-BDGQEJA5.js";
8
+ } from "../chunk-ZOSNEO5N.js";
9
9
  import {
10
10
  postToolInvocationId,
11
11
  toMove,
12
12
  toolOutcomeFor
13
- } from "../chunk-CPSE3Y3T.js";
13
+ } from "../chunk-H64F6QHV.js";
14
14
  import {
15
15
  appendMove,
16
16
  resolveOrg
17
- } from "../chunk-UN5O5SYG.js";
17
+ } from "../chunk-YWO7O6QG.js";
18
18
  import {
19
19
  getOrCreateWorkspaceId
20
20
  } from "../chunk-UVIWZWM6.js";
21
- import {
22
- scrubFromCwd
23
- } from "../chunk-G5D3FF3D.js";
21
+ import "../chunk-BQUJ4AFJ.js";
24
22
  import {
25
23
  appendCodexContext,
26
24
  prepareCodexContext
27
- } from "../chunk-I5BHJQH2.js";
25
+ } from "../chunk-KKP2NYZ3.js";
26
+ import "../chunk-4A2XB2PC.js";
27
+ import {
28
+ scrubFromCwd
29
+ } from "../chunk-FI3LIRCB.js";
28
30
  import {
29
31
  bold,
30
- color,
31
- warmBinCache
32
- } from "../chunk-K3AYW6VZ.js";
32
+ color
33
+ } from "../chunk-LEMX3IOG.js";
33
34
  import {
34
35
  isRepoActiveForCapture,
35
36
  repoSyncId,
36
37
  resolveRepositoryContext
37
- } from "../chunk-TDRXHBEX.js";
38
+ } from "../chunk-TJTVHDJ5.js";
38
39
  import {
39
- getClient
40
- } from "../chunk-RTLFE6EZ.js";
40
+ getClient,
41
+ terminalSafeLine
42
+ } from "../chunk-Z7YPFWAZ.js";
41
43
  import {
42
44
  normalizeEnvelope,
43
45
  parseAgent
44
- } from "../chunk-TCDUH7AN.js";
45
- import "../chunk-UTKQTZHL.js";
46
+ } from "../chunk-WB7AUZ4C.js";
47
+ import "../chunk-CUE2LKLR.js";
48
+ import "../chunk-3EEFL6NJ.js";
46
49
 
47
50
  // src/hooks/post-tool-use.ts
48
51
  import { readFileSync } from "fs";
@@ -66,7 +69,7 @@ function renderVerdictFooter(ctx) {
66
69
  const successPrefix = color("\u2713 Conflict caught before merge", "green");
67
70
  const savedCount = `${String(ctx.decisionsSaved)}${ctx.decisionsSavedTruncated ? "+" : ""}`;
68
71
  const savedFragment = `${savedCount} decisions saved`;
69
- const intentFragment = `${bold(ctx.author)}'s intent preserved`;
72
+ const intentFragment = `${bold(terminalSafeLine(ctx.author))}'s intent preserved`;
70
73
  return `${successPrefix} \xB7 ${savedFragment} \xB7 ${intentFragment}`;
71
74
  }
72
75
  function isVerdictFooterContext(value) {
@@ -138,7 +141,6 @@ function debug(msg) {
138
141
  }
139
142
  }
140
143
  async function main() {
141
- warmBinCache();
142
144
  const agent = parseAgent(process.argv);
143
145
  let raw;
144
146
  try {
@@ -211,12 +213,12 @@ async function main() {
211
213
  const identity = getOrCreateWorkspaceId(cwd);
212
214
  const workspaceId = identity.status === "ready" ? identity.workspaceId : void 0;
213
215
  const base = toMove(enriched, resolveCliVersion(), agent, workspaceId, repository, invocationId);
214
- const scrubbed = scrubFromCwd(enriched, cwd);
216
+ const scrubbed = await scrubFromCwd(enriched, cwd);
215
217
  const move = {
216
218
  ...base,
217
219
  payload: preserveHookFileMetadata(scrubbed, resolution)
218
220
  };
219
- const { orgId } = resolveOrg({ sessionId: move.sessionId, cwd: move.env.cwd });
221
+ const { orgId } = resolveOrg({ sessionId: move.sessionId, cwd });
220
222
  let verdictFooter = false;
221
223
  try {
222
224
  const result = await deliverPostToolMove(move, orgId);
@@ -2,9 +2,10 @@
2
2
  import {
3
3
  checkAffectedDecisions,
4
4
  formatDecisionsWarning
5
- } from "../chunk-XUAP572Z.js";
6
- import "../chunk-RTLFE6EZ.js";
7
- import "../chunk-UTKQTZHL.js";
5
+ } from "../chunk-RO3F6JYV.js";
6
+ import "../chunk-Z7YPFWAZ.js";
7
+ import "../chunk-CUE2LKLR.js";
8
+ import "../chunk-3EEFL6NJ.js";
8
9
 
9
10
  // src/hooks/pre-commit.ts
10
11
  import { execSync } from "child_process";
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- DEFAULT_RULES,
4
3
  analyzeShellTargets,
5
4
  buildCodexOutput,
6
5
  buildHermesOutput,
@@ -10,32 +9,38 @@ import {
10
9
  failOpenCodex,
11
10
  failOpenHermes,
12
11
  failOpenOutput,
13
- readHookMode,
14
- scrub
15
- } from "../chunk-G5D3FF3D.js";
12
+ readHookMode
13
+ } from "../chunk-BQUJ4AFJ.js";
16
14
  import {
17
15
  appendCodexContext,
18
16
  hasVisibleCodexMessage,
19
17
  prepareCodexContext
20
- } from "../chunk-I5BHJQH2.js";
18
+ } from "../chunk-KKP2NYZ3.js";
21
19
  import {
22
- packageVersion,
23
- warmBinCache
24
- } from "../chunk-K3AYW6VZ.js";
20
+ packageVersion
21
+ } from "../chunk-4A2XB2PC.js";
22
+ import {
23
+ DEFAULT_RULES,
24
+ scrub
25
+ } from "../chunk-FI3LIRCB.js";
26
+ import {
27
+ boundedHealthError
28
+ } from "../chunk-LEMX3IOG.js";
25
29
  import {
26
30
  canonicalGitRoot,
27
31
  canonicalRepositoryPath,
28
32
  isRepoActive,
29
33
  repoSyncId
30
- } from "../chunk-TDRXHBEX.js";
34
+ } from "../chunk-TJTVHDJ5.js";
31
35
  import {
32
36
  getClient
33
- } from "../chunk-RTLFE6EZ.js";
37
+ } from "../chunk-Z7YPFWAZ.js";
34
38
  import {
35
39
  normalizeEnvelope,
36
40
  parseAgent
37
- } from "../chunk-TCDUH7AN.js";
38
- import "../chunk-UTKQTZHL.js";
41
+ } from "../chunk-WB7AUZ4C.js";
42
+ import "../chunk-CUE2LKLR.js";
43
+ import "../chunk-3EEFL6NJ.js";
39
44
 
40
45
  // src/hooks/preflight-v3.ts
41
46
  import { Buffer as Buffer2 } from "buffer";
@@ -45,6 +50,9 @@ var MAX_PREFLIGHT_PATHS = 32;
45
50
  var MAX_PROPOSAL_BYTES = 6144;
46
51
  var MAX_CLIENT_VERSION_CHARS = 32;
47
52
  var CLIENT_VERSION_RE = /^[A-Za-z0-9][A-Za-z0-9._+-]*$/;
53
+ var MAX_DECISION_DISCLOSURES = 16;
54
+ var DISCLOSED_DECISION_ID_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/u;
55
+ var DISCLOSED_DECISION_SHORT_ID_RE = /^[0-9a-f]{8}$/u;
48
56
  function boundedClientVersion(raw) {
49
57
  return typeof raw === "string" && raw.length <= MAX_CLIENT_VERSION_CHARS && CLIENT_VERSION_RE.test(raw) ? raw : "unknown";
50
58
  }
@@ -94,8 +102,26 @@ function parsePreflightResponse(value) {
94
102
  if (response.protocolVersion !== PREFLIGHT_PROTOCOL_VERSION || typeof response.verdict !== "string" || !verdicts.has(response.verdict) || typeof response.reasonCode !== "string" || typeof response.message !== "string" || !Array.isArray(response.conflicts) || !Array.isArray(response.bypassed)) {
95
103
  return null;
96
104
  }
105
+ const disclosures = response.decisionDisclosures;
106
+ if (disclosures !== void 0) {
107
+ if (!Array.isArray(disclosures) || disclosures.length === 0 || disclosures.length > MAX_DECISION_DISCLOSURES) {
108
+ return null;
109
+ }
110
+ const seen = /* @__PURE__ */ new Set();
111
+ for (const value2 of disclosures) {
112
+ if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) return null;
113
+ const disclosure = value2;
114
+ if (Object.keys(disclosure).length !== 3 || !Object.hasOwn(disclosure, "decisionId") || !Object.hasOwn(disclosure, "shortId") || !Object.hasOwn(disclosure, "participation") || typeof disclosure.decisionId !== "string" || !DISCLOSED_DECISION_ID_RE.test(disclosure.decisionId) || typeof disclosure.shortId !== "string" || !DISCLOSED_DECISION_SHORT_ID_RE.test(disclosure.shortId) || disclosure.participation !== "candidate" && disclosure.participation !== "reconcile_bypass" || seen.has(disclosure.decisionId)) {
115
+ return null;
116
+ }
117
+ seen.add(disclosure.decisionId);
118
+ }
119
+ }
97
120
  return response;
98
121
  }
122
+ function decisionDisclosureContext(response) {
123
+ return response.decisionDisclosures?.map(({ decisionId }) => `[primitive] hidden Decision: prim decisions show ${decisionId}`).join("\n") ?? "";
124
+ }
99
125
  async function requestPreflight(request, signal = AbortSignal.timeout(PREFLIGHT_TIMEOUT_MS)) {
100
126
  const response = await getClient().post("/api/cli/decisions/conflict-check", request, {
101
127
  signal,
@@ -105,6 +131,8 @@ async function requestPreflight(request, signal = AbortSignal.timeout(PREFLIGHT_
105
131
  }
106
132
  function resultForPreflight(response) {
107
133
  const verdict = response.verdict === "block" ? "deny" : response.verdict;
134
+ const message = boundedHealthError(response.message) ?? "";
135
+ const unavailable = message || boundedHealthError(response.reasonCode);
108
136
  const safe = /^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/;
109
137
  const directives = response.conflicts.flatMap((value) => {
110
138
  if (!value || typeof value !== "object") return [];
@@ -112,14 +140,15 @@ function resultForPreflight(response) {
112
140
  const id = typeof shortId === "string" && safe.test(shortId) ? `dec_${shortId}` : typeof decisionId === "string" && safe.test(decisionId) ? decisionId : void 0;
113
141
  return id ? [`To reconcile, run: prim reconcile ${id}`] : [];
114
142
  });
115
- const reason = [response.message, ...new Set(directives)].filter(Boolean).join("\n");
143
+ const reason = [message, ...new Set(directives)].filter(Boolean).join("\n");
144
+ const disclosureContext = decisionDisclosureContext(response);
116
145
  return {
117
146
  verdict,
118
147
  conflicts: response.conflicts,
119
148
  reason,
120
- additionalContext: ["warn", "ask", "block"].includes(response.verdict) ? reason : "",
149
+ additionalContext: disclosureContext || (["warn", "ask", "block"].includes(response.verdict) ? reason : ""),
121
150
  truncated: false,
122
- unavailable: response.verdict === "unavailable" ? response.message || response.reasonCode : void 0
151
+ unavailable: response.verdict === "unavailable" ? unavailable : void 0
123
152
  };
124
153
  }
125
154
  function unverifiedResult(message) {
@@ -175,6 +204,18 @@ function invocationId(envelope) {
175
204
  const value = agent === "hermes" ? envelope.extra?.tool_call_id : envelope.tool_use_id;
176
205
  return typeof value === "string" && value.length > 0 ? value : void 0;
177
206
  }
207
+ function hermesAdvisory(result, aggregate) {
208
+ const parts = [];
209
+ if (aggregate === "warn") parts.push(result.reason);
210
+ if (result.verdict === "unavailable") {
211
+ parts.push(result.unavailable ?? result.reason);
212
+ }
213
+ if (result.additionalContext && result.additionalContext !== result.reason) {
214
+ parts.push(result.additionalContext);
215
+ }
216
+ const message = [...new Set(parts.filter(Boolean))].join("\n");
217
+ return message.startsWith("[primitive]") ? message : message ? `[primitive] ${message}` : "";
218
+ }
178
219
  async function emitUnverified(message, envelope) {
179
220
  const result = unverifiedResult(message);
180
221
  if (agent === "hermes") {
@@ -200,7 +241,6 @@ async function emitUnverified(message, envelope) {
200
241
  }
201
242
  }
202
243
  async function main() {
203
- warmBinCache();
204
244
  let raw;
205
245
  try {
206
246
  raw = await readStdin();
@@ -286,8 +326,9 @@ async function main() {
286
326
  result.verdict === "unavailable" ? "allow" : result.verdict,
287
327
  mode
288
328
  );
289
- if (agent === "hermes" && (aggregate === "warn" || result.verdict === "unavailable")) {
290
- process.stderr.write(`[primitive] ${result.reason || result.unavailable}
329
+ if (agent === "hermes" && aggregate !== "deny" && aggregate !== "ask") {
330
+ const advisory = hermesAdvisory(result, aggregate);
331
+ if (advisory) process.stderr.write(`${advisory}
291
332
  `);
292
333
  }
293
334
  let output = agent === "hermes" ? buildHermesOutput(aggregate, [result]) : agent === "codex" ? buildCodexOutput(aggregate, [result]) : buildHookOutput(aggregate, [result]);
@@ -8,43 +8,45 @@ import {
8
8
  acknowledgeDecisionFeedback,
9
9
  leaseDecisionFeedback,
10
10
  renderFeedback
11
- } from "../chunk-U6L2RU67.js";
11
+ } from "../chunk-LMRYZL3D.js";
12
12
  import {
13
13
  enrichHookPayloadWithFileRefs,
14
14
  preserveHookFileMetadata
15
- } from "../chunk-BDGQEJA5.js";
15
+ } from "../chunk-ZOSNEO5N.js";
16
16
  import {
17
17
  postToolInvocationId,
18
18
  shouldFlushAfter,
19
19
  toMove
20
- } from "../chunk-CPSE3Y3T.js";
20
+ } from "../chunk-H64F6QHV.js";
21
21
  import {
22
22
  appendMove,
23
23
  resolveOrg
24
- } from "../chunk-UN5O5SYG.js";
24
+ } from "../chunk-YWO7O6QG.js";
25
25
  import {
26
26
  getOrCreateWorkspaceId
27
27
  } from "../chunk-UVIWZWM6.js";
28
- import {
29
- scrubFromCwd
30
- } from "../chunk-G5D3FF3D.js";
28
+ import "../chunk-BQUJ4AFJ.js";
31
29
  import {
32
30
  prepareCodexContext
33
- } from "../chunk-I5BHJQH2.js";
31
+ } from "../chunk-KKP2NYZ3.js";
32
+ import "../chunk-4A2XB2PC.js";
34
33
  import {
35
- warmBinCache
36
- } from "../chunk-K3AYW6VZ.js";
34
+ scrubFromCwd,
35
+ writeHookDebug
36
+ } from "../chunk-FI3LIRCB.js";
37
+ import "../chunk-LEMX3IOG.js";
37
38
  import {
38
39
  isRepoActiveForCapture,
39
40
  repoSyncId,
40
41
  resolveRepositoryContext
41
- } from "../chunk-TDRXHBEX.js";
42
- import "../chunk-RTLFE6EZ.js";
42
+ } from "../chunk-TJTVHDJ5.js";
43
+ import "../chunk-Z7YPFWAZ.js";
43
44
  import {
44
45
  normalizeEnvelope,
45
46
  parseAgent
46
- } from "../chunk-TCDUH7AN.js";
47
- import "../chunk-UTKQTZHL.js";
47
+ } from "../chunk-WB7AUZ4C.js";
48
+ import "../chunk-CUE2LKLR.js";
49
+ import "../chunk-3EEFL6NJ.js";
48
50
 
49
51
  // src/hooks/prim-hook.ts
50
52
  import { spawn } from "child_process";
@@ -54,14 +56,13 @@ import { fileURLToPath } from "url";
54
56
 
55
57
  // src/hooks/codex-message-context.ts
56
58
  var defaultDeps = { prepare: prepareCodexContext };
57
- var STOP_BACKSTOP_INSTRUCTION = "A new Primitive Decision arrived during this turn. Incorporate it into the active task and proactively tell the user about it before finishing.";
58
59
  async function processCodexMessageContext(envelope, deps = defaultDeps) {
59
60
  const event = envelope.hook_event_name;
60
- if (event !== "UserPromptSubmit" && event !== "Stop") return { output: {} };
61
+ if (event === "Stop") return { output: {} };
62
+ if (event !== "UserPromptSubmit") return { output: {} };
61
63
  if (typeof envelope.session_id !== "string" || envelope.session_id.length === 0) {
62
64
  return { output: {} };
63
65
  }
64
- if (event === "Stop" && envelope.stop_hook_active === true) return { output: {} };
65
66
  let prepared;
66
67
  try {
67
68
  prepared = await deps.prepare({
@@ -71,31 +72,15 @@ async function processCodexMessageContext(envelope, deps = defaultDeps) {
71
72
  } catch {
72
73
  return { output: {} };
73
74
  }
74
- if (event === "UserPromptSubmit") {
75
- return {
76
- output: prepared.context ? {
77
- hookSpecificOutput: {
78
- hookEventName: "UserPromptSubmit",
79
- additionalContext: prepared.context
80
- }
81
- } : {},
82
- // Even an empty prompt response is a successful handoff. Committing it
83
- // advances verified feed state and report dedup without inventing output.
84
- acknowledge: async () => {
85
- await prepared.acknowledge(true);
86
- }
87
- };
88
- }
89
- if (!prepared.decisionDigest) {
90
- return { output: {} };
91
- }
92
75
  return {
93
- output: {
94
- decision: "block",
95
- reason: `${prepared.context ?? prepared.decisionDigest}
96
-
97
- ${STOP_BACKSTOP_INSTRUCTION}`
98
- },
76
+ output: prepared.context ? {
77
+ hookSpecificOutput: {
78
+ hookEventName: "UserPromptSubmit",
79
+ additionalContext: prepared.context
80
+ }
81
+ } : {},
82
+ // Even an empty prompt response is a successful handoff. Committing it
83
+ // advances verified feed state and report dedup without inventing output.
99
84
  acknowledge: async () => {
100
85
  await prepared.acknowledge(true);
101
86
  }
@@ -124,15 +109,8 @@ function spawnBackgroundFlush() {
124
109
  stdio: "ignore"
125
110
  }).unref();
126
111
  }
127
- function debug(area, error) {
128
- if (!process.env.PRIM_HOOK_DEBUG) return;
129
- const detail = error instanceof Error ? error.message : String(error);
130
- process.stderr.write(`[prim-hook] ${area} failed: ${detail}
131
- `);
132
- }
133
112
  async function main() {
134
113
  const feedbackSignal = AbortSignal.timeout(FEEDBACK_DEADLINE_MS);
135
- warmBinCache();
136
114
  const agent = parseAgent(process.argv);
137
115
  let raw;
138
116
  let parsed;
@@ -140,7 +118,7 @@ async function main() {
140
118
  raw = readFileSync(0, "utf-8");
141
119
  parsed = normalizeEnvelope(JSON.parse(raw), agent);
142
120
  } catch (error) {
143
- debug("capture", error);
121
+ writeHookDebug("capture failed", error);
144
122
  await emitOutput(buildHookOutput({}));
145
123
  return;
146
124
  }
@@ -167,18 +145,18 @@ async function main() {
167
145
  repository,
168
146
  invocationId
169
147
  );
170
- const scrubbed = scrubFromCwd(enriched, cwd);
148
+ const scrubbed = await scrubFromCwd(enriched, cwd);
171
149
  const move = {
172
150
  ...base,
173
151
  payload: enrichment ? preserveHookFileMetadata(scrubbed, enrichment.resolution) : scrubbed
174
152
  };
175
- const { orgId } = resolveOrg({ sessionId: move.sessionId, cwd: move.env.cwd });
153
+ const { orgId } = resolveOrg({ sessionId: move.sessionId, cwd });
176
154
  appendMove(move, orgId);
177
155
  if (shouldFlushAfter(move.eventType)) {
178
156
  spawnBackgroundFlush();
179
157
  }
180
158
  } catch (error) {
181
- debug("capture", error);
159
+ writeHookDebug("capture failed", error);
182
160
  }
183
161
  if (isCodexContextEvent) {
184
162
  const result = await processCodexMessageContext(parsed);
@@ -193,20 +171,25 @@ async function main() {
193
171
  }
194
172
  const lease = await leaseDecisionFeedback(
195
173
  { workspaceId, currentSessionId: sessionId, signal: feedbackSignal },
196
- { onError: (error) => debug("feedback", error) }
174
+ { onError: (error) => writeHookDebug("feedback failed", error) }
197
175
  );
198
176
  const rendered = lease ? renderFeedback(lease) : void 0;
199
177
  await emitOutput(
200
178
  buildHookOutput({ systemMessage: rendered?.systemMessage }),
201
179
  rendered ? async () => {
202
180
  await acknowledgeDecisionFeedback(
203
- { workspaceId, deliveries: rendered.deliveries, signal: feedbackSignal },
204
- { onError: (error) => debug("feedback", error) }
181
+ {
182
+ protocolVersion: rendered.protocolVersion,
183
+ workspaceId,
184
+ deliveries: rendered.deliveries,
185
+ signal: feedbackSignal
186
+ },
187
+ { onError: (error) => writeHookDebug("feedback failed", error) }
205
188
  );
206
189
  } : void 0
207
190
  );
208
191
  }
209
192
  void main().catch(async (error) => {
210
- debug("capture", error);
193
+ writeHookDebug("capture failed", error);
211
194
  if (!outputAttempted) await emitOutput(buildHookOutput({}));
212
195
  });
@@ -2,10 +2,11 @@
2
2
  import {
3
3
  normalizeEnvelope,
4
4
  parseAgent
5
- } from "../chunk-TCDUH7AN.js";
5
+ } from "../chunk-WB7AUZ4C.js";
6
6
  import {
7
7
  daemonRequest
8
- } from "../chunk-UTKQTZHL.js";
8
+ } from "../chunk-CUE2LKLR.js";
9
+ import "../chunk-3EEFL6NJ.js";
9
10
 
10
11
  // src/hooks/session-end.ts
11
12
  var STDIN_TIMEOUT_MS = 1e3;
@@ -4,8 +4,9 @@ import {
4
4
  ensureEffectivePostCommitHook,
5
5
  ensureEffectivePostRewriteHook,
6
6
  hasUsableCodexGuidance,
7
- refreshClaudePlugins
8
- } from "../chunk-XPVNH3J6.js";
7
+ refreshClaudePlugins,
8
+ warmBinCache
9
+ } from "../chunk-2KW7DVFJ.js";
9
10
  import {
10
11
  buildHookOutput,
11
12
  handoffHookOutput
@@ -15,33 +16,34 @@ import {
15
16
  acknowledgeDecisionFeedback,
16
17
  leaseDecisionFeedback,
17
18
  renderFeedback
18
- } from "../chunk-U6L2RU67.js";
19
+ } from "../chunk-LMRYZL3D.js";
19
20
  import {
20
21
  getOrCreateWorkspaceId
21
22
  } from "../chunk-UVIWZWM6.js";
22
23
  import {
23
24
  prepareCodexContext
24
- } from "../chunk-I5BHJQH2.js";
25
+ } from "../chunk-KKP2NYZ3.js";
25
26
  import {
26
- binFile,
27
- warmBinCache
28
- } from "../chunk-K3AYW6VZ.js";
27
+ binFile
28
+ } from "../chunk-4A2XB2PC.js";
29
29
  import {
30
30
  gitToplevel,
31
31
  isRepoActiveForCapture,
32
32
  repoActiveFlag,
33
33
  setRepoActive
34
- } from "../chunk-TDRXHBEX.js";
34
+ } from "../chunk-TJTVHDJ5.js";
35
35
  import {
36
+ getSiteUrl,
36
37
  isSessionEnded
37
- } from "../chunk-RTLFE6EZ.js";
38
+ } from "../chunk-Z7YPFWAZ.js";
38
39
  import {
39
40
  normalizeEnvelope,
40
41
  parseAgent
41
- } from "../chunk-TCDUH7AN.js";
42
+ } from "../chunk-WB7AUZ4C.js";
42
43
  import {
43
44
  daemonRequest
44
- } from "../chunk-UTKQTZHL.js";
45
+ } from "../chunk-CUE2LKLR.js";
46
+ import "../chunk-3EEFL6NJ.js";
45
47
 
46
48
  // src/daemon/self-heal.ts
47
49
  import { spawn } from "child_process";
@@ -139,7 +141,7 @@ async function processSessionStart(raw, agent, feedbackSignal) {
139
141
  kickDaemonEnsure();
140
142
  await daemonRequest(
141
143
  "session_start",
142
- { sessionId: envelope.session_id },
144
+ { sessionId: envelope.session_id, callerEnv: getSiteUrl() },
143
145
  { timeoutMs: DAEMON_TIMEOUT_MS }
144
146
  );
145
147
  const cwd = envelope.cwd ?? process.cwd();
@@ -212,6 +214,7 @@ async function processSessionStart(raw, agent, feedbackSignal) {
212
214
  }),
213
215
  acknowledge: rendered ? async () => {
214
216
  await acknowledgeDecisionFeedback({
217
+ protocolVersion: rendered.protocolVersion,
215
218
  workspaceId: identity.workspaceId,
216
219
  deliveries: rendered.deliveries,
217
220
  signal