@primitive.ai/prim 0.1.0-alpha.67 → 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 (45) 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-KKP2NYZ3.js +505 -0
  11. package/dist/{chunk-JQFN6LBO.js → chunk-LEMX3IOG.js} +6 -37
  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-XGADQPCI.js +26 -0
  17. package/dist/{chunk-UN5O5SYG.js → chunk-YWO7O6QG.js} +14 -53
  18. package/dist/chunk-Z7YPFWAZ.js +917 -0
  19. package/dist/{chunk-BDGQEJA5.js → chunk-ZOSNEO5N.js} +2 -2
  20. package/dist/daemon/server.js +11804 -470
  21. package/dist/hook-runtime/daemon/server.js +13353 -0
  22. package/dist/hook-runtime/hooks/post-commit.js +1128 -0
  23. package/dist/hook-runtime/hooks/post-rewrite.js +1148 -0
  24. package/dist/hook-runtime/hooks/post-tool-use.js +7586 -0
  25. package/dist/hook-runtime/hooks/pre-commit.js +1314 -0
  26. package/dist/hook-runtime/hooks/pre-tool-use.js +7099 -0
  27. package/dist/hook-runtime/hooks/prim-hook.js +7691 -0
  28. package/dist/hook-runtime/hooks/session-end.js +495 -0
  29. package/dist/hook-runtime/hooks/session-start.js +11284 -0
  30. package/dist/hook-runtime/index.js +42775 -0
  31. package/dist/hook-runtime/statusline-main.js +765 -0
  32. package/dist/hooks/post-commit.js +7 -4
  33. package/dist/hooks/post-rewrite.js +7 -4
  34. package/dist/hooks/post-tool-use.js +64 -32
  35. package/dist/hooks/pre-commit.js +4 -3
  36. package/dist/hooks/pre-tool-use.js +118 -38
  37. package/dist/hooks/prim-hook.js +72 -27
  38. package/dist/hooks/session-end.js +5 -4
  39. package/dist/hooks/session-start.js +36 -25
  40. package/dist/index.js +15039 -2555
  41. package/dist/statusline-main.js +488 -96
  42. package/package.json +11 -5
  43. package/dist/chunk-CZ24W5QU.js +0 -123
  44. package/dist/chunk-RTLFE6EZ.js +0 -518
  45. package/dist/chunk-UTKQTZHL.js +0 -88
@@ -8,45 +8,86 @@ 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 "../chunk-BQUJ4AFJ.js";
28
29
  import {
29
- scrubFromCwd
30
- } from "../chunk-G5D3FF3D.js";
30
+ prepareCodexContext
31
+ } from "../chunk-KKP2NYZ3.js";
32
+ import "../chunk-4A2XB2PC.js";
31
33
  import {
32
- warmBinCache
33
- } from "../chunk-CZ24W5QU.js";
34
+ scrubFromCwd,
35
+ writeHookDebug
36
+ } from "../chunk-FI3LIRCB.js";
37
+ import "../chunk-LEMX3IOG.js";
34
38
  import {
35
39
  isRepoActiveForCapture,
36
40
  repoSyncId,
37
41
  resolveRepositoryContext
38
- } from "../chunk-TDRXHBEX.js";
39
- import "../chunk-RTLFE6EZ.js";
42
+ } from "../chunk-TJTVHDJ5.js";
43
+ import "../chunk-Z7YPFWAZ.js";
40
44
  import {
41
45
  normalizeEnvelope,
42
46
  parseAgent
43
- } from "../chunk-TCDUH7AN.js";
47
+ } from "../chunk-WB7AUZ4C.js";
48
+ import "../chunk-CUE2LKLR.js";
49
+ import "../chunk-3EEFL6NJ.js";
44
50
 
45
51
  // src/hooks/prim-hook.ts
46
52
  import { spawn } from "child_process";
47
53
  import { readFileSync } from "fs";
48
54
  import { dirname, join } from "path";
49
55
  import { fileURLToPath } from "url";
56
+
57
+ // src/hooks/codex-message-context.ts
58
+ var defaultDeps = { prepare: prepareCodexContext };
59
+ async function processCodexMessageContext(envelope, deps = defaultDeps) {
60
+ const event = envelope.hook_event_name;
61
+ if (event === "Stop") return { output: {} };
62
+ if (event !== "UserPromptSubmit") return { output: {} };
63
+ if (typeof envelope.session_id !== "string" || envelope.session_id.length === 0) {
64
+ return { output: {} };
65
+ }
66
+ let prepared;
67
+ try {
68
+ prepared = await deps.prepare({
69
+ cwd: typeof envelope.cwd === "string" ? envelope.cwd : process.cwd(),
70
+ sessionId: envelope.session_id
71
+ });
72
+ } catch {
73
+ return { output: {} };
74
+ }
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
+
90
+ // src/hooks/prim-hook.ts
50
91
  var here = dirname(fileURLToPath(import.meta.url));
51
92
  var outputAttempted = false;
52
93
  function emitOutput(output, acknowledge) {
@@ -68,15 +109,8 @@ function spawnBackgroundFlush() {
68
109
  stdio: "ignore"
69
110
  }).unref();
70
111
  }
71
- function debug(area, error) {
72
- if (!process.env.PRIM_HOOK_DEBUG) return;
73
- const detail = error instanceof Error ? error.message : String(error);
74
- process.stderr.write(`[prim-hook] ${area} failed: ${detail}
75
- `);
76
- }
77
112
  async function main() {
78
113
  const feedbackSignal = AbortSignal.timeout(FEEDBACK_DEADLINE_MS);
79
- warmBinCache();
80
114
  const agent = parseAgent(process.argv);
81
115
  let raw;
82
116
  let parsed;
@@ -84,14 +118,15 @@ async function main() {
84
118
  raw = readFileSync(0, "utf-8");
85
119
  parsed = normalizeEnvelope(JSON.parse(raw), agent);
86
120
  } catch (error) {
87
- debug("capture", error);
121
+ writeHookDebug("capture failed", error);
88
122
  await emitOutput(buildHookOutput({}));
89
123
  return;
90
124
  }
91
125
  const cwd = parsed.cwd ?? process.cwd();
92
126
  const isClaudeStop = agent === "claude_code" && parsed.hook_event_name === "Stop";
127
+ const isCodexContextEvent = agent === "codex" && (parsed.hook_event_name === "UserPromptSubmit" || parsed.hook_event_name === "Stop");
93
128
  if (!isRepoActiveForCapture(cwd)) {
94
- if (isClaudeStop) await emitOutput(buildHookOutput({}));
129
+ if (isClaudeStop || isCodexContextEvent) await emitOutput(buildHookOutput({}));
95
130
  return;
96
131
  }
97
132
  const identity = getOrCreateWorkspaceId(cwd);
@@ -110,18 +145,23 @@ async function main() {
110
145
  repository,
111
146
  invocationId
112
147
  );
113
- const scrubbed = scrubFromCwd(enriched, cwd);
148
+ const scrubbed = await scrubFromCwd(enriched, cwd);
114
149
  const move = {
115
150
  ...base,
116
151
  payload: enrichment ? preserveHookFileMetadata(scrubbed, enrichment.resolution) : scrubbed
117
152
  };
118
- const { orgId } = resolveOrg({ sessionId: move.sessionId, cwd: move.env.cwd });
153
+ const { orgId } = resolveOrg({ sessionId: move.sessionId, cwd });
119
154
  appendMove(move, orgId);
120
155
  if (shouldFlushAfter(move.eventType)) {
121
156
  spawnBackgroundFlush();
122
157
  }
123
158
  } catch (error) {
124
- debug("capture", error);
159
+ writeHookDebug("capture failed", error);
160
+ }
161
+ if (isCodexContextEvent) {
162
+ const result = await processCodexMessageContext(parsed);
163
+ await emitOutput(result.output, result.acknowledge);
164
+ return;
125
165
  }
126
166
  if (!isClaudeStop) return;
127
167
  const sessionId = typeof parsed.session_id === "string" ? parsed.session_id : "";
@@ -131,20 +171,25 @@ async function main() {
131
171
  }
132
172
  const lease = await leaseDecisionFeedback(
133
173
  { workspaceId, currentSessionId: sessionId, signal: feedbackSignal },
134
- { onError: (error) => debug("feedback", error) }
174
+ { onError: (error) => writeHookDebug("feedback failed", error) }
135
175
  );
136
176
  const rendered = lease ? renderFeedback(lease) : void 0;
137
177
  await emitOutput(
138
178
  buildHookOutput({ systemMessage: rendered?.systemMessage }),
139
179
  rendered ? async () => {
140
180
  await acknowledgeDecisionFeedback(
141
- { workspaceId, deliveries: rendered.deliveries, signal: feedbackSignal },
142
- { 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) }
143
188
  );
144
189
  } : void 0
145
190
  );
146
191
  }
147
192
  void main().catch(async (error) => {
148
- debug("capture", error);
193
+ writeHookDebug("capture failed", error);
149
194
  if (!outputAttempted) await emitOutput(buildHookOutput({}));
150
195
  });
@@ -1,11 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- daemonRequest
4
- } from "../chunk-UTKQTZHL.js";
5
2
  import {
6
3
  normalizeEnvelope,
7
4
  parseAgent
8
- } from "../chunk-TCDUH7AN.js";
5
+ } from "../chunk-WB7AUZ4C.js";
6
+ import {
7
+ daemonRequest
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,31 +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
- binFile,
24
- warmBinCache
25
- } from "../chunk-CZ24W5QU.js";
24
+ prepareCodexContext
25
+ } from "../chunk-KKP2NYZ3.js";
26
+ import {
27
+ binFile
28
+ } from "../chunk-4A2XB2PC.js";
26
29
  import {
27
30
  gitToplevel,
28
31
  isRepoActiveForCapture,
29
32
  repoActiveFlag,
30
33
  setRepoActive
31
- } from "../chunk-TDRXHBEX.js";
34
+ } from "../chunk-TJTVHDJ5.js";
32
35
  import {
33
36
  getSiteUrl,
34
37
  isSessionEnded
35
- } from "../chunk-RTLFE6EZ.js";
36
- import {
37
- daemonRequest
38
- } from "../chunk-UTKQTZHL.js";
38
+ } from "../chunk-Z7YPFWAZ.js";
39
39
  import {
40
40
  normalizeEnvelope,
41
41
  parseAgent
42
- } from "../chunk-TCDUH7AN.js";
42
+ } from "../chunk-WB7AUZ4C.js";
43
+ import {
44
+ daemonRequest
45
+ } from "../chunk-CUE2LKLR.js";
46
+ import "../chunk-3EEFL6NJ.js";
43
47
 
44
48
  // src/daemon/self-heal.ts
45
49
  import { spawn } from "child_process";
@@ -68,7 +72,6 @@ function kickDaemonEnsure(options = {}) {
68
72
  // src/hooks/reauth-notice.ts
69
73
  var REAUTH_NOTICE = "[prim] authentication ended \u2014 run `prim auth login` to resume decision capture";
70
74
  function reauthNoticeFields(agent) {
71
- if (agent === "codex") return { additionalContext: REAUTH_NOTICE };
72
75
  if (agent === "claude_code") return { systemMessage: REAUTH_NOTICE };
73
76
  return;
74
77
  }
@@ -138,7 +141,7 @@ async function processSessionStart(raw, agent, feedbackSignal) {
138
141
  kickDaemonEnsure();
139
142
  await daemonRequest(
140
143
  "session_start",
141
- { sessionId: envelope.session_id },
144
+ { sessionId: envelope.session_id, callerEnv: getSiteUrl() },
142
145
  { timeoutMs: DAEMON_TIMEOUT_MS }
143
146
  );
144
147
  const cwd = envelope.cwd ?? process.cwd();
@@ -156,7 +159,7 @@ async function processSessionStart(raw, agent, feedbackSignal) {
156
159
  } catch {
157
160
  }
158
161
  }
159
- if (isSessionEnded()) {
162
+ if (isSessionEnded() && agent !== "codex") {
160
163
  const notice = reauthNoticeFields(agent);
161
164
  if (notice) {
162
165
  return {
@@ -165,14 +168,16 @@ async function processSessionStart(raw, agent, feedbackSignal) {
165
168
  }
166
169
  }
167
170
  if (agent === "codex") {
168
- const snapshot = await daemonRequest(
169
- "status_snapshot",
170
- // callerEnv: a cross-env daemon withholds onlineCount, so a prod Codex
171
- // session never gets a staging daemon's team count injected.
172
- { callerEnv: getSiteUrl() },
173
- { timeoutMs: DAEMON_TIMEOUT_MS }
174
- );
175
- const presence = snapshot && !snapshot.presenceStale && typeof snapshot.onlineCount === "number" ? `[prim] team: ${snapshot.onlineCount} online` : void 0;
171
+ let context;
172
+ try {
173
+ context = await prepareCodexContext({
174
+ cwd,
175
+ sessionId: envelope.session_id,
176
+ startup: true,
177
+ includeDigest: false
178
+ });
179
+ } catch {
180
+ }
176
181
  projectRoot = await activeProjectRoot(cwd);
177
182
  active = projectRoot !== null;
178
183
  let proactive = false;
@@ -180,8 +185,13 @@ async function processSessionStart(raw, agent, feedbackSignal) {
180
185
  proactive = projectRoot !== null && active && hasUsableCodexGuidance(projectRoot);
181
186
  } catch {
182
187
  }
183
- const additionalContext = [proactive ? CODEX_PRIM_REMINDER : void 0, presence].filter((value) => value !== void 0).join("\n\n");
184
- return { output: buildHookOutput({ additionalContext }) };
188
+ const additionalContext = [proactive ? CODEX_PRIM_REMINDER : void 0, context?.context].filter((value) => value !== void 0).join("\n\n");
189
+ return {
190
+ output: buildHookOutput({ additionalContext }),
191
+ acknowledge: async () => {
192
+ await context?.acknowledge(true);
193
+ }
194
+ };
185
195
  }
186
196
  if (agent === "claude_code") {
187
197
  const additionalContext = active && skillState.installed > 0 ? PRIM_SKILL_REMINDER : void 0;
@@ -204,6 +214,7 @@ async function processSessionStart(raw, agent, feedbackSignal) {
204
214
  }),
205
215
  acknowledge: rendered ? async () => {
206
216
  await acknowledgeDecisionFeedback({
217
+ protocolVersion: rendered.protocolVersion,
207
218
  workspaceId: identity.workspaceId,
208
219
  deliveries: rendered.deliveries,
209
220
  signal