@primitive.ai/prim 0.1.0-alpha.7 → 0.1.0-alpha.70

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 +296 -37
  2. package/SKILL.md +269 -0
  3. package/dist/chunk-2KW7DVFJ.js +1400 -0
  4. package/dist/chunk-3EEFL6NJ.js +529 -0
  5. package/dist/chunk-4A2XB2PC.js +310 -0
  6. package/dist/chunk-4GLVJLEQ.js +55 -0
  7. package/dist/chunk-BQUJ4AFJ.js +771 -0
  8. package/dist/chunk-CUE2LKLR.js +155 -0
  9. package/dist/chunk-FI3LIRCB.js +262 -0
  10. package/dist/chunk-H64F6QHV.js +247 -0
  11. package/dist/chunk-KKP2NYZ3.js +505 -0
  12. package/dist/chunk-LEMX3IOG.js +79 -0
  13. package/dist/chunk-LMRYZL3D.js +209 -0
  14. package/dist/chunk-RO3F6JYV.js +126 -0
  15. package/dist/chunk-TJTVHDJ5.js +321 -0
  16. package/dist/chunk-UVIWZWM6.js +211 -0
  17. package/dist/chunk-WB7AUZ4C.js +52 -0
  18. package/dist/chunk-XGADQPCI.js +26 -0
  19. package/dist/chunk-YWO7O6QG.js +327 -0
  20. package/dist/chunk-Z7YPFWAZ.js +917 -0
  21. package/dist/chunk-ZOSNEO5N.js +77 -0
  22. package/dist/daemon/server.js +13353 -0
  23. package/dist/hook-runtime/daemon/server.js +13353 -0
  24. package/dist/hook-runtime/hooks/post-commit.js +1128 -0
  25. package/dist/hook-runtime/hooks/post-rewrite.js +1148 -0
  26. package/dist/hook-runtime/hooks/post-tool-use.js +7586 -0
  27. package/dist/hook-runtime/hooks/pre-commit.js +1314 -0
  28. package/dist/hook-runtime/hooks/pre-tool-use.js +7099 -0
  29. package/dist/hook-runtime/hooks/prim-hook.js +7691 -0
  30. package/dist/hook-runtime/hooks/session-end.js +495 -0
  31. package/dist/hook-runtime/hooks/session-start.js +11284 -0
  32. package/dist/hook-runtime/index.js +42775 -0
  33. package/dist/hook-runtime/statusline-main.js +765 -0
  34. package/dist/hooks/post-commit.js +179 -0
  35. package/dist/hooks/post-rewrite.js +197 -0
  36. package/dist/hooks/post-tool-use.js +250 -0
  37. package/dist/hooks/pre-commit.js +21 -74
  38. package/dist/hooks/pre-tool-use.js +348 -0
  39. package/dist/hooks/prim-hook.js +195 -0
  40. package/dist/hooks/session-end.js +70 -0
  41. package/dist/hooks/session-start.js +271 -0
  42. package/dist/index.js +18920 -518
  43. package/dist/statusline-main.js +765 -0
  44. package/package.json +35 -13
  45. package/dist/chunk-3APLWTLB.js +0 -165
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ normalizeEnvelope,
4
+ parseAgent
5
+ } from "../chunk-WB7AUZ4C.js";
6
+ import {
7
+ daemonRequest
8
+ } from "../chunk-CUE2LKLR.js";
9
+ import "../chunk-3EEFL6NJ.js";
10
+
11
+ // src/hooks/session-end.ts
12
+ var STDIN_TIMEOUT_MS = 1e3;
13
+ var DAEMON_TIMEOUT_MS = 250;
14
+ function readStdin() {
15
+ return new Promise((resolve, reject) => {
16
+ const chunks = [];
17
+ const timer = setTimeout(() => {
18
+ reject(new Error("stdin read timeout"));
19
+ }, STDIN_TIMEOUT_MS);
20
+ process.stdin.on("data", (chunk) => chunks.push(chunk));
21
+ process.stdin.on("end", () => {
22
+ clearTimeout(timer);
23
+ resolve(Buffer.concat(chunks).toString("utf-8"));
24
+ });
25
+ process.stdin.on("error", (err) => {
26
+ clearTimeout(timer);
27
+ reject(err);
28
+ });
29
+ });
30
+ }
31
+ function emit() {
32
+ process.stdout.write("{}\n");
33
+ }
34
+ async function main() {
35
+ const agent = parseAgent(process.argv);
36
+ let raw;
37
+ try {
38
+ raw = await readStdin();
39
+ } catch {
40
+ emit();
41
+ return;
42
+ }
43
+ let envelope;
44
+ try {
45
+ envelope = normalizeEnvelope(
46
+ JSON.parse(raw),
47
+ agent
48
+ );
49
+ } catch {
50
+ emit();
51
+ return;
52
+ }
53
+ if (envelope.hook_event_name !== "SessionEnd") {
54
+ emit();
55
+ return;
56
+ }
57
+ if (typeof envelope.session_id !== "string" || envelope.session_id.length === 0) {
58
+ emit();
59
+ return;
60
+ }
61
+ await daemonRequest(
62
+ "session_end",
63
+ { sessionId: envelope.session_id },
64
+ { timeoutMs: DAEMON_TIMEOUT_MS }
65
+ );
66
+ emit();
67
+ }
68
+ main().catch(() => {
69
+ emit();
70
+ });
@@ -0,0 +1,271 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ bindRepository,
4
+ ensureEffectivePostCommitHook,
5
+ ensureEffectivePostRewriteHook,
6
+ hasUsableCodexGuidance,
7
+ refreshClaudePlugins,
8
+ warmBinCache
9
+ } from "../chunk-2KW7DVFJ.js";
10
+ import {
11
+ buildHookOutput,
12
+ handoffHookOutput
13
+ } from "../chunk-4GLVJLEQ.js";
14
+ import {
15
+ FEEDBACK_DEADLINE_MS,
16
+ acknowledgeDecisionFeedback,
17
+ leaseDecisionFeedback,
18
+ renderFeedback
19
+ } from "../chunk-LMRYZL3D.js";
20
+ import {
21
+ getOrCreateWorkspaceId
22
+ } from "../chunk-UVIWZWM6.js";
23
+ import {
24
+ prepareCodexContext
25
+ } from "../chunk-KKP2NYZ3.js";
26
+ import {
27
+ binFile
28
+ } from "../chunk-4A2XB2PC.js";
29
+ import {
30
+ gitToplevel,
31
+ isRepoActiveForCapture,
32
+ repoActiveFlag,
33
+ setRepoActive
34
+ } from "../chunk-TJTVHDJ5.js";
35
+ import {
36
+ getSiteUrl,
37
+ isSessionEnded
38
+ } from "../chunk-Z7YPFWAZ.js";
39
+ import {
40
+ normalizeEnvelope,
41
+ parseAgent
42
+ } from "../chunk-WB7AUZ4C.js";
43
+ import {
44
+ daemonRequest
45
+ } from "../chunk-CUE2LKLR.js";
46
+ import "../chunk-3EEFL6NJ.js";
47
+
48
+ // src/daemon/self-heal.ts
49
+ import { spawn } from "child_process";
50
+ function kickDaemonEnsure(options = {}) {
51
+ const primEntry = options.primEntry === void 0 ? binFile("prim") : options.primEntry;
52
+ if (!primEntry) {
53
+ return false;
54
+ }
55
+ try {
56
+ const args = [primEntry, "daemon", "ensure"];
57
+ if ((options.platform ?? process.platform) === "darwin") {
58
+ args.push("--latest-bootstrap");
59
+ }
60
+ const child = (options.spawnProcess ?? spawn)(
61
+ options.nodeEntry ?? process.execPath,
62
+ args,
63
+ { detached: true, stdio: "ignore" }
64
+ );
65
+ child.unref();
66
+ return true;
67
+ } catch {
68
+ return false;
69
+ }
70
+ }
71
+
72
+ // src/hooks/reauth-notice.ts
73
+ var REAUTH_NOTICE = "[prim] authentication ended \u2014 run `prim auth login` to resume decision capture";
74
+ function reauthNoticeFields(agent) {
75
+ if (agent === "claude_code") return { systemMessage: REAUTH_NOTICE };
76
+ return;
77
+ }
78
+
79
+ // src/hooks/session-start-core.ts
80
+ var DAEMON_TIMEOUT_MS = 250;
81
+ var REPOSITORY_BIND_TIMEOUT_MS = 1e3;
82
+ var PRIM_TRIGGER = "When this task chooses between plausible approaches or establishes or changes a lasting goal, priority, constraint, invariant, default, commitment, tradeoff, exception, or shared instruction";
83
+ var PRIM_EXCLUSIONS = "Never invoke `prim` for routine implementation that merely follows an existing decision made before this task or for temporary tactics; they never qualify, including for evaluation.";
84
+ function primReminder(action, rationaleAction) {
85
+ return `Primitive is active in this repository. ${PRIM_TRIGGER}, ${action} before finishing. ${PRIM_EXCLUSIONS} When a direct request replaces one lasting default with another but supplies no rationale, complete the work, ${rationaleAction}, and ask one concise rationale question at the task boundary, even if the user requested only implementation or recording fails.`;
86
+ }
87
+ var PRIM_SKILL_REMINDER = primReminder("invoke the `prim` skill", "invoke the skill");
88
+ var CODEX_PRIM_ACTION = "follow the installed Prim workflow and use the `prim` CLI";
89
+ var CODEX_PRIM_REMINDER = primReminder(CODEX_PRIM_ACTION, CODEX_PRIM_ACTION);
90
+ async function activeProjectRoot(cwd) {
91
+ try {
92
+ const root = gitToplevel(cwd);
93
+ if (!root || !isRepoActiveForCapture(cwd)) return null;
94
+ let shellGateActive = repoActiveFlag(root) === "true";
95
+ if (!shellGateActive) {
96
+ try {
97
+ setRepoActive(root, true);
98
+ shellGateActive = true;
99
+ } catch {
100
+ }
101
+ }
102
+ if (shellGateActive) {
103
+ try {
104
+ ensureEffectivePostCommitHook(root);
105
+ } catch {
106
+ }
107
+ try {
108
+ ensureEffectivePostRewriteHook(root);
109
+ } catch {
110
+ }
111
+ }
112
+ try {
113
+ await bindRepository(root, {
114
+ signal: AbortSignal.timeout(REPOSITORY_BIND_TIMEOUT_MS),
115
+ quietRefresh: true
116
+ });
117
+ } catch {
118
+ }
119
+ return root;
120
+ } catch {
121
+ return null;
122
+ }
123
+ }
124
+ async function processSessionStart(raw, agent, feedbackSignal) {
125
+ let envelope;
126
+ try {
127
+ const parsed = JSON.parse(raw);
128
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
129
+ return { output: buildHookOutput({}) };
130
+ }
131
+ envelope = normalizeEnvelope(parsed, agent);
132
+ } catch {
133
+ return { output: buildHookOutput({}) };
134
+ }
135
+ if (envelope.hook_event_name !== "SessionStart") {
136
+ return { output: buildHookOutput({}) };
137
+ }
138
+ if (typeof envelope.session_id !== "string" || envelope.session_id.length === 0) {
139
+ return { output: buildHookOutput({}) };
140
+ }
141
+ kickDaemonEnsure();
142
+ await daemonRequest(
143
+ "session_start",
144
+ { sessionId: envelope.session_id, callerEnv: getSiteUrl() },
145
+ { timeoutMs: DAEMON_TIMEOUT_MS }
146
+ );
147
+ const cwd = envelope.cwd ?? process.cwd();
148
+ let projectRoot = null;
149
+ let active = false;
150
+ let skillState = { installed: 0, refreshed: 0 };
151
+ if (agent === "claude_code") {
152
+ projectRoot = await activeProjectRoot(cwd);
153
+ active = projectRoot !== null;
154
+ try {
155
+ skillState = await refreshClaudePlugins(
156
+ cwd,
157
+ active && projectRoot !== null ? { includeProject: true, projectRoot } : { includeProject: false }
158
+ );
159
+ } catch {
160
+ }
161
+ }
162
+ if (isSessionEnded() && agent !== "codex") {
163
+ const notice = reauthNoticeFields(agent);
164
+ if (notice) {
165
+ return {
166
+ output: buildHookOutput({ ...notice, reloadSkills: skillState.refreshed > 0 })
167
+ };
168
+ }
169
+ }
170
+ if (agent === "codex") {
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
+ }
181
+ projectRoot = await activeProjectRoot(cwd);
182
+ active = projectRoot !== null;
183
+ let proactive = false;
184
+ try {
185
+ proactive = projectRoot !== null && active && hasUsableCodexGuidance(projectRoot);
186
+ } catch {
187
+ }
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
+ };
195
+ }
196
+ if (agent === "claude_code") {
197
+ const additionalContext = active && skillState.installed > 0 ? PRIM_SKILL_REMINDER : void 0;
198
+ const reloadSkills = skillState.refreshed > 0;
199
+ if (active) {
200
+ const identity = getOrCreateWorkspaceId(cwd);
201
+ if (identity.status === "ready") {
202
+ const signal = feedbackSignal ?? AbortSignal.timeout(FEEDBACK_DEADLINE_MS);
203
+ const lease = await leaseDecisionFeedback({
204
+ workspaceId: identity.workspaceId,
205
+ currentSessionId: envelope.session_id,
206
+ signal
207
+ });
208
+ const rendered = lease ? renderFeedback(lease) : void 0;
209
+ return {
210
+ output: buildHookOutput({
211
+ systemMessage: rendered?.systemMessage,
212
+ additionalContext,
213
+ reloadSkills
214
+ }),
215
+ acknowledge: rendered ? async () => {
216
+ await acknowledgeDecisionFeedback({
217
+ protocolVersion: rendered.protocolVersion,
218
+ workspaceId: identity.workspaceId,
219
+ deliveries: rendered.deliveries,
220
+ signal
221
+ });
222
+ } : void 0
223
+ };
224
+ }
225
+ }
226
+ return { output: buildHookOutput({ additionalContext, reloadSkills }) };
227
+ }
228
+ await activeProjectRoot(cwd);
229
+ return { output: buildHookOutput({}) };
230
+ }
231
+
232
+ // src/hooks/session-start.ts
233
+ var STDIN_TIMEOUT_MS = 1e3;
234
+ var outputAttempted = false;
235
+ function emitOutput(output, acknowledge) {
236
+ outputAttempted = true;
237
+ return handoffHookOutput(output, acknowledge);
238
+ }
239
+ function readStdin() {
240
+ return new Promise((resolve, reject) => {
241
+ const chunks = [];
242
+ const timer = setTimeout(() => {
243
+ reject(new Error("stdin read timeout"));
244
+ }, STDIN_TIMEOUT_MS);
245
+ process.stdin.on("data", (chunk) => chunks.push(chunk));
246
+ process.stdin.on("end", () => {
247
+ clearTimeout(timer);
248
+ resolve(Buffer.concat(chunks).toString("utf-8"));
249
+ });
250
+ process.stdin.on("error", (err) => {
251
+ clearTimeout(timer);
252
+ reject(err);
253
+ });
254
+ });
255
+ }
256
+ async function main() {
257
+ warmBinCache();
258
+ const agent = parseAgent(process.argv);
259
+ let raw;
260
+ try {
261
+ raw = await readStdin();
262
+ } catch {
263
+ await emitOutput(buildHookOutput({}));
264
+ return;
265
+ }
266
+ const result = await processSessionStart(raw, agent);
267
+ await emitOutput(result.output, result.acknowledge);
268
+ }
269
+ void main().catch(async () => {
270
+ if (!outputAttempted) await emitOutput(buildHookOutput({}));
271
+ });