@primitive.ai/prim 0.1.0-alpha.67 → 0.1.0-alpha.68
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/chunk-I5BHJQH2.js +329 -0
- package/dist/chunk-K3AYW6VZ.js +300 -0
- package/dist/chunk-XGADQPCI.js +26 -0
- package/dist/daemon/server.js +115 -24
- package/dist/hooks/post-tool-use.js +49 -19
- package/dist/hooks/pre-tool-use.js +63 -24
- package/dist/hooks/prim-hook.js +64 -2
- package/dist/hooks/session-end.js +3 -3
- package/dist/hooks/session-start.js +25 -17
- package/dist/index.js +13 -100
- package/dist/statusline-main.js +16 -12
- package/package.json +1 -1
- package/dist/chunk-CZ24W5QU.js +0 -123
- package/dist/chunk-JQFN6LBO.js +0 -110
package/dist/hooks/prim-hook.js
CHANGED
|
@@ -28,9 +28,12 @@ import {
|
|
|
28
28
|
import {
|
|
29
29
|
scrubFromCwd
|
|
30
30
|
} from "../chunk-G5D3FF3D.js";
|
|
31
|
+
import {
|
|
32
|
+
prepareCodexContext
|
|
33
|
+
} from "../chunk-I5BHJQH2.js";
|
|
31
34
|
import {
|
|
32
35
|
warmBinCache
|
|
33
|
-
} from "../chunk-
|
|
36
|
+
} from "../chunk-K3AYW6VZ.js";
|
|
34
37
|
import {
|
|
35
38
|
isRepoActiveForCapture,
|
|
36
39
|
repoSyncId,
|
|
@@ -41,12 +44,65 @@ import {
|
|
|
41
44
|
normalizeEnvelope,
|
|
42
45
|
parseAgent
|
|
43
46
|
} from "../chunk-TCDUH7AN.js";
|
|
47
|
+
import "../chunk-UTKQTZHL.js";
|
|
44
48
|
|
|
45
49
|
// src/hooks/prim-hook.ts
|
|
46
50
|
import { spawn } from "child_process";
|
|
47
51
|
import { readFileSync } from "fs";
|
|
48
52
|
import { dirname, join } from "path";
|
|
49
53
|
import { fileURLToPath } from "url";
|
|
54
|
+
|
|
55
|
+
// src/hooks/codex-message-context.ts
|
|
56
|
+
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
|
+
async function processCodexMessageContext(envelope, deps = defaultDeps) {
|
|
59
|
+
const event = envelope.hook_event_name;
|
|
60
|
+
if (event !== "UserPromptSubmit" && event !== "Stop") return { output: {} };
|
|
61
|
+
if (typeof envelope.session_id !== "string" || envelope.session_id.length === 0) {
|
|
62
|
+
return { output: {} };
|
|
63
|
+
}
|
|
64
|
+
if (event === "Stop" && envelope.stop_hook_active === true) return { output: {} };
|
|
65
|
+
let prepared;
|
|
66
|
+
try {
|
|
67
|
+
prepared = await deps.prepare({
|
|
68
|
+
cwd: typeof envelope.cwd === "string" ? envelope.cwd : process.cwd(),
|
|
69
|
+
sessionId: envelope.session_id
|
|
70
|
+
});
|
|
71
|
+
} catch {
|
|
72
|
+
return { output: {} };
|
|
73
|
+
}
|
|
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
|
+
return {
|
|
93
|
+
output: {
|
|
94
|
+
decision: "block",
|
|
95
|
+
reason: `${prepared.context ?? prepared.decisionDigest}
|
|
96
|
+
|
|
97
|
+
${STOP_BACKSTOP_INSTRUCTION}`
|
|
98
|
+
},
|
|
99
|
+
acknowledge: async () => {
|
|
100
|
+
await prepared.acknowledge(true);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// src/hooks/prim-hook.ts
|
|
50
106
|
var here = dirname(fileURLToPath(import.meta.url));
|
|
51
107
|
var outputAttempted = false;
|
|
52
108
|
function emitOutput(output, acknowledge) {
|
|
@@ -90,8 +146,9 @@ async function main() {
|
|
|
90
146
|
}
|
|
91
147
|
const cwd = parsed.cwd ?? process.cwd();
|
|
92
148
|
const isClaudeStop = agent === "claude_code" && parsed.hook_event_name === "Stop";
|
|
149
|
+
const isCodexContextEvent = agent === "codex" && (parsed.hook_event_name === "UserPromptSubmit" || parsed.hook_event_name === "Stop");
|
|
93
150
|
if (!isRepoActiveForCapture(cwd)) {
|
|
94
|
-
if (isClaudeStop) await emitOutput(buildHookOutput({}));
|
|
151
|
+
if (isClaudeStop || isCodexContextEvent) await emitOutput(buildHookOutput({}));
|
|
95
152
|
return;
|
|
96
153
|
}
|
|
97
154
|
const identity = getOrCreateWorkspaceId(cwd);
|
|
@@ -123,6 +180,11 @@ async function main() {
|
|
|
123
180
|
} catch (error) {
|
|
124
181
|
debug("capture", error);
|
|
125
182
|
}
|
|
183
|
+
if (isCodexContextEvent) {
|
|
184
|
+
const result = await processCodexMessageContext(parsed);
|
|
185
|
+
await emitOutput(result.output, result.acknowledge);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
126
188
|
if (!isClaudeStop) return;
|
|
127
189
|
const sessionId = typeof parsed.session_id === "string" ? parsed.session_id : "";
|
|
128
190
|
if (!workspaceId || !sessionId) {
|
|
@@ -1,11 +1,11 @@
|
|
|
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
5
|
} from "../chunk-TCDUH7AN.js";
|
|
6
|
+
import {
|
|
7
|
+
daemonRequest
|
|
8
|
+
} from "../chunk-UTKQTZHL.js";
|
|
9
9
|
|
|
10
10
|
// src/hooks/session-end.ts
|
|
11
11
|
var STDIN_TIMEOUT_MS = 1e3;
|
|
@@ -19,10 +19,13 @@ import {
|
|
|
19
19
|
import {
|
|
20
20
|
getOrCreateWorkspaceId
|
|
21
21
|
} from "../chunk-UVIWZWM6.js";
|
|
22
|
+
import {
|
|
23
|
+
prepareCodexContext
|
|
24
|
+
} from "../chunk-I5BHJQH2.js";
|
|
22
25
|
import {
|
|
23
26
|
binFile,
|
|
24
27
|
warmBinCache
|
|
25
|
-
} from "../chunk-
|
|
28
|
+
} from "../chunk-K3AYW6VZ.js";
|
|
26
29
|
import {
|
|
27
30
|
gitToplevel,
|
|
28
31
|
isRepoActiveForCapture,
|
|
@@ -30,16 +33,15 @@ import {
|
|
|
30
33
|
setRepoActive
|
|
31
34
|
} from "../chunk-TDRXHBEX.js";
|
|
32
35
|
import {
|
|
33
|
-
getSiteUrl,
|
|
34
36
|
isSessionEnded
|
|
35
37
|
} from "../chunk-RTLFE6EZ.js";
|
|
36
|
-
import {
|
|
37
|
-
daemonRequest
|
|
38
|
-
} from "../chunk-UTKQTZHL.js";
|
|
39
38
|
import {
|
|
40
39
|
normalizeEnvelope,
|
|
41
40
|
parseAgent
|
|
42
41
|
} from "../chunk-TCDUH7AN.js";
|
|
42
|
+
import {
|
|
43
|
+
daemonRequest
|
|
44
|
+
} from "../chunk-UTKQTZHL.js";
|
|
43
45
|
|
|
44
46
|
// src/daemon/self-heal.ts
|
|
45
47
|
import { spawn } from "child_process";
|
|
@@ -68,7 +70,6 @@ function kickDaemonEnsure(options = {}) {
|
|
|
68
70
|
// src/hooks/reauth-notice.ts
|
|
69
71
|
var REAUTH_NOTICE = "[prim] authentication ended \u2014 run `prim auth login` to resume decision capture";
|
|
70
72
|
function reauthNoticeFields(agent) {
|
|
71
|
-
if (agent === "codex") return { additionalContext: REAUTH_NOTICE };
|
|
72
73
|
if (agent === "claude_code") return { systemMessage: REAUTH_NOTICE };
|
|
73
74
|
return;
|
|
74
75
|
}
|
|
@@ -156,7 +157,7 @@ async function processSessionStart(raw, agent, feedbackSignal) {
|
|
|
156
157
|
} catch {
|
|
157
158
|
}
|
|
158
159
|
}
|
|
159
|
-
if (isSessionEnded()) {
|
|
160
|
+
if (isSessionEnded() && agent !== "codex") {
|
|
160
161
|
const notice = reauthNoticeFields(agent);
|
|
161
162
|
if (notice) {
|
|
162
163
|
return {
|
|
@@ -165,14 +166,16 @@ async function processSessionStart(raw, agent, feedbackSignal) {
|
|
|
165
166
|
}
|
|
166
167
|
}
|
|
167
168
|
if (agent === "codex") {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
169
|
+
let context;
|
|
170
|
+
try {
|
|
171
|
+
context = await prepareCodexContext({
|
|
172
|
+
cwd,
|
|
173
|
+
sessionId: envelope.session_id,
|
|
174
|
+
startup: true,
|
|
175
|
+
includeDigest: false
|
|
176
|
+
});
|
|
177
|
+
} catch {
|
|
178
|
+
}
|
|
176
179
|
projectRoot = await activeProjectRoot(cwd);
|
|
177
180
|
active = projectRoot !== null;
|
|
178
181
|
let proactive = false;
|
|
@@ -180,8 +183,13 @@ async function processSessionStart(raw, agent, feedbackSignal) {
|
|
|
180
183
|
proactive = projectRoot !== null && active && hasUsableCodexGuidance(projectRoot);
|
|
181
184
|
} catch {
|
|
182
185
|
}
|
|
183
|
-
const additionalContext = [proactive ? CODEX_PRIM_REMINDER : void 0,
|
|
184
|
-
return {
|
|
186
|
+
const additionalContext = [proactive ? CODEX_PRIM_REMINDER : void 0, context?.context].filter((value) => value !== void 0).join("\n\n");
|
|
187
|
+
return {
|
|
188
|
+
output: buildHookOutput({ additionalContext }),
|
|
189
|
+
acknowledge: async () => {
|
|
190
|
+
await context?.acknowledge(true);
|
|
191
|
+
}
|
|
192
|
+
};
|
|
185
193
|
}
|
|
186
194
|
if (agent === "claude_code") {
|
|
187
195
|
const additionalContext = active && skillState.installed > 0 ? PRIM_SKILL_REMINDER : void 0;
|
package/dist/index.js
CHANGED
|
@@ -19,15 +19,8 @@ import {
|
|
|
19
19
|
uninstallProjectPostRewriteHook
|
|
20
20
|
} from "./chunk-XPVNH3J6.js";
|
|
21
21
|
import {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
color,
|
|
25
|
-
colorForArea,
|
|
26
|
-
dim,
|
|
27
|
-
requireDurableIngestAcknowledgement,
|
|
28
|
-
stripAnsi,
|
|
29
|
-
stripControlChars
|
|
30
|
-
} from "./chunk-JQFN6LBO.js";
|
|
22
|
+
requireDurableIngestAcknowledgement
|
|
23
|
+
} from "./chunk-XGADQPCI.js";
|
|
31
24
|
import {
|
|
32
25
|
checkAffectedDecisions,
|
|
33
26
|
daemonOrDirectGet,
|
|
@@ -50,12 +43,21 @@ import {
|
|
|
50
43
|
} from "./chunk-UVIWZWM6.js";
|
|
51
44
|
import {
|
|
52
45
|
binFile,
|
|
46
|
+
bold,
|
|
47
|
+
boundedHealthError,
|
|
48
|
+
color,
|
|
49
|
+
colorForArea,
|
|
53
50
|
commandMatchesBin,
|
|
54
51
|
detachedHookShimCommand,
|
|
52
|
+
dim,
|
|
53
|
+
formatStatusline,
|
|
54
|
+
formatTeammates,
|
|
55
55
|
packageVersion,
|
|
56
56
|
pinnedHookCommand,
|
|
57
|
+
stripAnsi,
|
|
58
|
+
stripControlChars,
|
|
57
59
|
warmBinCache
|
|
58
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-K3AYW6VZ.js";
|
|
59
61
|
import {
|
|
60
62
|
canonicalGitRoot,
|
|
61
63
|
canonicalRepositoryPath,
|
|
@@ -2131,53 +2133,6 @@ async function runLatestDaemonBootstrap(ensureCurrent, options = {}) {
|
|
|
2131
2133
|
}
|
|
2132
2134
|
}
|
|
2133
2135
|
|
|
2134
|
-
// src/lib/presence.ts
|
|
2135
|
-
var DECISION_ORIGIN = "https://app.getprimitive.ai";
|
|
2136
|
-
function validDecisionUrl(value) {
|
|
2137
|
-
if (typeof value !== "string" || stripControlChars(value) !== value) {
|
|
2138
|
-
return void 0;
|
|
2139
|
-
}
|
|
2140
|
-
try {
|
|
2141
|
-
const url = new URL(value);
|
|
2142
|
-
if (url.origin !== DECISION_ORIGIN || url.username !== "" || url.password !== "" || url.search !== "" || url.hash !== "" || !/^\/decisions\/[^/]+$/u.test(url.pathname)) {
|
|
2143
|
-
return void 0;
|
|
2144
|
-
}
|
|
2145
|
-
return url.href;
|
|
2146
|
-
} catch {
|
|
2147
|
-
return void 0;
|
|
2148
|
-
}
|
|
2149
|
-
}
|
|
2150
|
-
function decisionLink(label, decisionUrl) {
|
|
2151
|
-
const url = validDecisionUrl(decisionUrl);
|
|
2152
|
-
return url ? `\x1B]8;;${url}\x07\x1B[34;4m${label}\x1B[0m\x1B]8;;\x07` : label;
|
|
2153
|
-
}
|
|
2154
|
-
function formatLabeled(labels, cap) {
|
|
2155
|
-
if (labels === void 0) {
|
|
2156
|
-
return "\u2014";
|
|
2157
|
-
}
|
|
2158
|
-
if (labels.length === 0) {
|
|
2159
|
-
return "just you";
|
|
2160
|
-
}
|
|
2161
|
-
if (labels.length <= cap) {
|
|
2162
|
-
return labels.join(", ");
|
|
2163
|
-
}
|
|
2164
|
-
return `${labels.slice(0, cap).join(", ")} +${String(labels.length - cap)}`;
|
|
2165
|
-
}
|
|
2166
|
-
function formatTeammates(names, cap) {
|
|
2167
|
-
return formatLabeled(names?.map(stripControlChars), cap);
|
|
2168
|
-
}
|
|
2169
|
-
function formatTeammatesWithArea(teammates, cap) {
|
|
2170
|
-
return formatLabeled(
|
|
2171
|
-
teammates?.map((t) => {
|
|
2172
|
-
const name = stripControlChars(t.name);
|
|
2173
|
-
const area = stripControlChars(t.area ?? "").trim();
|
|
2174
|
-
const label = area ? `${name} - ${area}` : name;
|
|
2175
|
-
return decisionLink(label, t.decisionUrl);
|
|
2176
|
-
}),
|
|
2177
|
-
cap
|
|
2178
|
-
);
|
|
2179
|
-
}
|
|
2180
|
-
|
|
2181
2136
|
// src/commands/daemon.ts
|
|
2182
2137
|
var DAEMON_BIN = "prim-daemon-server";
|
|
2183
2138
|
var CONFIG_DIR = join5(homedir5(), ".config", "prim");
|
|
@@ -3077,7 +3032,7 @@ async function fetchRecent(args, deps = defaultDeps2) {
|
|
|
3077
3032
|
"decisions_recent",
|
|
3078
3033
|
`/api/cli/decisions/recent?${params.toString()}`,
|
|
3079
3034
|
client,
|
|
3080
|
-
RECENT_TIMEOUT_MS
|
|
3035
|
+
deps.timeoutMs ?? RECENT_TIMEOUT_MS
|
|
3081
3036
|
);
|
|
3082
3037
|
if (args.author !== void 0 && res.author === void 0 && res.unavailable === void 0) {
|
|
3083
3038
|
return {
|
|
@@ -6244,48 +6199,6 @@ function registerSetupCommand(program2, dependencies = {}) {
|
|
|
6244
6199
|
import { readFileSync as readFileSync9 } from "fs";
|
|
6245
6200
|
import { dirname as dirname6, resolve as resolve3 } from "path";
|
|
6246
6201
|
import { fileURLToPath } from "url";
|
|
6247
|
-
|
|
6248
|
-
// src/lib/statusline-render.ts
|
|
6249
|
-
var STATUSLINE_NAME_CAP = 3;
|
|
6250
|
-
function formatStatusline(version, snapshot, resolveIngestionStatus) {
|
|
6251
|
-
if (!snapshot) {
|
|
6252
|
-
return `primitive ${version} (daemon: down)`;
|
|
6253
|
-
}
|
|
6254
|
-
if (snapshot.healthy === false) {
|
|
6255
|
-
if (snapshot.needsReauth) {
|
|
6256
|
-
return `primitive ${version} (daemon: paused \xB7 run \`prim auth login\`)`;
|
|
6257
|
-
}
|
|
6258
|
-
if (snapshot.ingestion?.healthy === false) {
|
|
6259
|
-
const pending = snapshot.ingestion.pendingCount;
|
|
6260
|
-
const qualifier = snapshot.ingestion.pendingSampled ? "at least " : "";
|
|
6261
|
-
return `primitive ${version} (daemon: degraded \xB7 delivery: stalled${typeof pending === "number" ? ` \xB7 ${qualifier}${String(pending)} pending` : ""})`;
|
|
6262
|
-
}
|
|
6263
|
-
if (snapshot.heartbeat?.healthy === false) {
|
|
6264
|
-
return `primitive ${version} (daemon: degraded \xB7 presence: unavailable)`;
|
|
6265
|
-
}
|
|
6266
|
-
return `primitive ${version} (daemon: starting)`;
|
|
6267
|
-
}
|
|
6268
|
-
const ingestionStatus = resolveIngestionStatus();
|
|
6269
|
-
if (snapshot.envMismatch) {
|
|
6270
|
-
return `primitive ${version} (daemon: live, Decision ingestion ${ingestionStatus} \xB7 presence: other env)`;
|
|
6271
|
-
}
|
|
6272
|
-
if (snapshot.presenceStale) {
|
|
6273
|
-
return `primitive ${version} (daemon: live, Decision ingestion ${ingestionStatus} \xB7 presence: stale)`;
|
|
6274
|
-
}
|
|
6275
|
-
let team;
|
|
6276
|
-
if (snapshot.onlineTeammates !== void 0) {
|
|
6277
|
-
team = `team: ${formatTeammatesWithArea(snapshot.onlineTeammates, STATUSLINE_NAME_CAP)}`;
|
|
6278
|
-
} else if (snapshot.onlineNames !== void 0) {
|
|
6279
|
-
team = `team: ${formatTeammates(snapshot.onlineNames, STATUSLINE_NAME_CAP)}`;
|
|
6280
|
-
} else if (typeof snapshot.onlineCount === "number") {
|
|
6281
|
-
team = `team: ${String(snapshot.onlineCount)} online`;
|
|
6282
|
-
} else {
|
|
6283
|
-
team = "team: \u2014";
|
|
6284
|
-
}
|
|
6285
|
-
return `primitive ${version} (daemon: live, Decision ingestion ${ingestionStatus} \xB7 ${team})`;
|
|
6286
|
-
}
|
|
6287
|
-
|
|
6288
|
-
// src/commands/statusline.ts
|
|
6289
6202
|
var STATUSLINE_TIMEOUT_MS = 200;
|
|
6290
6203
|
function readPackageVersion() {
|
|
6291
6204
|
try {
|
package/dist/statusline-main.js
CHANGED
|
@@ -245,9 +245,12 @@ function validDecisionUrl(value) {
|
|
|
245
245
|
return void 0;
|
|
246
246
|
}
|
|
247
247
|
}
|
|
248
|
-
function decisionLink(label, decisionUrl) {
|
|
248
|
+
function decisionLink(label, decisionUrl, plain) {
|
|
249
249
|
const url = validDecisionUrl(decisionUrl);
|
|
250
|
-
|
|
250
|
+
if (plain || !url) {
|
|
251
|
+
return label;
|
|
252
|
+
}
|
|
253
|
+
return `\x1B]8;;${url}\x07\x1B[34;4m${label}\x1B[0m\x1B]8;;\x07`;
|
|
251
254
|
}
|
|
252
255
|
function formatLabeled(labels, cap) {
|
|
253
256
|
if (labels === void 0) {
|
|
@@ -264,13 +267,13 @@ function formatLabeled(labels, cap) {
|
|
|
264
267
|
function formatTeammates(names, cap) {
|
|
265
268
|
return formatLabeled(names?.map(stripControlChars), cap);
|
|
266
269
|
}
|
|
267
|
-
function formatTeammatesWithArea(teammates, cap) {
|
|
270
|
+
function formatTeammatesWithArea(teammates, cap, plainLinks = false) {
|
|
268
271
|
return formatLabeled(
|
|
269
272
|
teammates?.map((t) => {
|
|
270
273
|
const name = stripControlChars(t.name);
|
|
271
274
|
const area = stripControlChars(t.area ?? "").trim();
|
|
272
275
|
const label = area ? `${name} - ${area}` : name;
|
|
273
|
-
return decisionLink(label, t.decisionUrl);
|
|
276
|
+
return decisionLink(label, t.decisionUrl, plainLinks);
|
|
274
277
|
}),
|
|
275
278
|
cap
|
|
276
279
|
);
|
|
@@ -278,25 +281,26 @@ function formatTeammatesWithArea(teammates, cap) {
|
|
|
278
281
|
|
|
279
282
|
// src/lib/statusline-render.ts
|
|
280
283
|
var STATUSLINE_NAME_CAP = 3;
|
|
281
|
-
function formatStatusline(version, snapshot, resolveIngestionStatus) {
|
|
284
|
+
function formatStatusline(version, snapshot, resolveIngestionStatus, options = {}) {
|
|
285
|
+
const ingestionSuffix = (status) => status === void 0 ? "" : ` \xB7 Decision ingestion ${status}`;
|
|
286
|
+
const ingestionStatus = snapshot === null || snapshot.healthy === false ? options.includeIngestionWhenUnavailable ? resolveIngestionStatus() : void 0 : resolveIngestionStatus();
|
|
282
287
|
if (!snapshot) {
|
|
283
|
-
return `primitive ${version} (daemon: down)`;
|
|
288
|
+
return `primitive ${version} (daemon: down${ingestionSuffix(ingestionStatus)})`;
|
|
284
289
|
}
|
|
285
290
|
if (snapshot.healthy === false) {
|
|
286
291
|
if (snapshot.needsReauth) {
|
|
287
|
-
return `primitive ${version} (daemon: paused \xB7 run \`prim auth login
|
|
292
|
+
return `primitive ${version} (daemon: paused \xB7 run \`prim auth login\`${ingestionSuffix(ingestionStatus)})`;
|
|
288
293
|
}
|
|
289
294
|
if (snapshot.ingestion?.healthy === false) {
|
|
290
295
|
const pending = snapshot.ingestion.pendingCount;
|
|
291
296
|
const qualifier = snapshot.ingestion.pendingSampled ? "at least " : "";
|
|
292
|
-
return `primitive ${version} (daemon: degraded \xB7 delivery: stalled${typeof pending === "number" ? ` \xB7 ${qualifier}${String(pending)} pending` : ""})`;
|
|
297
|
+
return `primitive ${version} (daemon: degraded \xB7 delivery: stalled${typeof pending === "number" ? ` \xB7 ${qualifier}${String(pending)} pending` : ""}${ingestionSuffix(ingestionStatus)})`;
|
|
293
298
|
}
|
|
294
299
|
if (snapshot.heartbeat?.healthy === false) {
|
|
295
|
-
return `primitive ${version} (daemon: degraded \xB7 presence: unavailable)`;
|
|
300
|
+
return `primitive ${version} (daemon: degraded \xB7 presence: unavailable${ingestionSuffix(ingestionStatus)})`;
|
|
296
301
|
}
|
|
297
|
-
return `primitive ${version} (daemon: starting)`;
|
|
302
|
+
return `primitive ${version} (daemon: starting${ingestionSuffix(ingestionStatus)})`;
|
|
298
303
|
}
|
|
299
|
-
const ingestionStatus = resolveIngestionStatus();
|
|
300
304
|
if (snapshot.envMismatch) {
|
|
301
305
|
return `primitive ${version} (daemon: live, Decision ingestion ${ingestionStatus} \xB7 presence: other env)`;
|
|
302
306
|
}
|
|
@@ -305,7 +309,7 @@ function formatStatusline(version, snapshot, resolveIngestionStatus) {
|
|
|
305
309
|
}
|
|
306
310
|
let team;
|
|
307
311
|
if (snapshot.onlineTeammates !== void 0) {
|
|
308
|
-
team = `team: ${formatTeammatesWithArea(snapshot.onlineTeammates, STATUSLINE_NAME_CAP)}`;
|
|
312
|
+
team = `team: ${formatTeammatesWithArea(snapshot.onlineTeammates, STATUSLINE_NAME_CAP, options.plainLinks === true)}`;
|
|
309
313
|
} else if (snapshot.onlineNames !== void 0) {
|
|
310
314
|
team = `team: ${formatTeammates(snapshot.onlineNames, STATUSLINE_NAME_CAP)}`;
|
|
311
315
|
} else if (typeof snapshot.onlineCount === "number") {
|
package/package.json
CHANGED
package/dist/chunk-CZ24W5QU.js
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
// src/lib/bin-path.ts
|
|
2
|
-
import { existsSync, readFileSync } from "fs";
|
|
3
|
-
import { dirname, isAbsolute, join } from "path";
|
|
4
|
-
import { fileURLToPath } from "url";
|
|
5
|
-
var PKG_NAME = "@primitive.ai/prim";
|
|
6
|
-
var ROOT_WALK_LIMIT = 6;
|
|
7
|
-
var NPX_FALLBACK = `npx --yes -p ${PKG_NAME}@latest`;
|
|
8
|
-
var resolvedRoot;
|
|
9
|
-
function locateRoot() {
|
|
10
|
-
if (resolvedRoot !== void 0) {
|
|
11
|
-
return resolvedRoot;
|
|
12
|
-
}
|
|
13
|
-
let dir = dirname(fileURLToPath(import.meta.url));
|
|
14
|
-
for (let depth = 0; depth < ROOT_WALK_LIMIT; depth++) {
|
|
15
|
-
const manifestPath = join(dir, "package.json");
|
|
16
|
-
if (existsSync(manifestPath)) {
|
|
17
|
-
try {
|
|
18
|
-
const manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
19
|
-
if (manifest.name === PKG_NAME && manifest.bin) {
|
|
20
|
-
resolvedRoot = { dir, version: manifest.version, bin: manifest.bin };
|
|
21
|
-
return resolvedRoot;
|
|
22
|
-
}
|
|
23
|
-
} catch {
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
const parent = dirname(dir);
|
|
27
|
-
if (parent === dir) {
|
|
28
|
-
break;
|
|
29
|
-
}
|
|
30
|
-
dir = parent;
|
|
31
|
-
}
|
|
32
|
-
resolvedRoot = null;
|
|
33
|
-
return resolvedRoot;
|
|
34
|
-
}
|
|
35
|
-
function binFile(bin) {
|
|
36
|
-
const root = locateRoot();
|
|
37
|
-
const rel = root?.bin[bin];
|
|
38
|
-
if (!root || !rel) {
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
return isAbsolute(rel) ? rel : join(root.dir, rel);
|
|
42
|
-
}
|
|
43
|
-
function packageVersion() {
|
|
44
|
-
return locateRoot()?.version ?? null;
|
|
45
|
-
}
|
|
46
|
-
function shellQuote(value) {
|
|
47
|
-
return `'${value.replaceAll("'", `'"'"'`)}'`;
|
|
48
|
-
}
|
|
49
|
-
function pinnedHookCommand(bin, args = "") {
|
|
50
|
-
const version = packageVersion();
|
|
51
|
-
if (!version) throw new Error("cannot determine Primitive package version");
|
|
52
|
-
const suffix = args ? ` ${args}` : "";
|
|
53
|
-
const fallback = `npx --yes -p ${PKG_NAME}@${version} ${bin}${suffix}`;
|
|
54
|
-
const file = binFile(bin);
|
|
55
|
-
if (!file) return fallback;
|
|
56
|
-
return `if [ -x ${shellQuote(process.execPath)} ] && [ -f ${shellQuote(file)} ]; then ${shellQuote(process.execPath)} ${shellQuote(file)}${suffix}; else ${fallback}; fi`;
|
|
57
|
-
}
|
|
58
|
-
function detachedHookShimCommand(bin, args = "") {
|
|
59
|
-
return `payload=$(cat); { trap '' HUP; export npm_config_fetch_retries=2 npm_config_fetch_retry_mintimeout=10000 npm_config_fetch_retry_maxtimeout=10000 npm_config_fetch_timeout=60000; printf '%s' "$payload" | { ${pinnedHookCommand(bin, args)}; }; } </dev/null >/dev/null 2>&1 &`;
|
|
60
|
-
}
|
|
61
|
-
function commandMatchesBin(command, bin) {
|
|
62
|
-
if (!command) {
|
|
63
|
-
return false;
|
|
64
|
-
}
|
|
65
|
-
const c = command.trim();
|
|
66
|
-
if (c === bin || c.startsWith(`${bin} `)) {
|
|
67
|
-
return true;
|
|
68
|
-
}
|
|
69
|
-
const exactBin = new RegExp(`(?:^|\\s)${bin.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?:\\s|;|$)`);
|
|
70
|
-
return c.includes(`command -v ${bin} `) || c.includes(`-p ${PKG_NAME}@`) && exactBin.test(c);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// src/lib/bin-cache.ts
|
|
74
|
-
import { chmodSync, mkdirSync, renameSync, writeFileSync } from "fs";
|
|
75
|
-
import { homedir } from "os";
|
|
76
|
-
import { join as join2 } from "path";
|
|
77
|
-
var CACHED_BINS = [
|
|
78
|
-
"prim",
|
|
79
|
-
"prim-hook",
|
|
80
|
-
"prim-pre-tool-use",
|
|
81
|
-
"prim-post-tool-use",
|
|
82
|
-
"prim-post-commit",
|
|
83
|
-
"prim-post-rewrite"
|
|
84
|
-
];
|
|
85
|
-
function binCacheDir() {
|
|
86
|
-
const base = process.env.XDG_CACHE_HOME || join2(homedir(), ".cache");
|
|
87
|
-
return join2(base, "prim", "bin");
|
|
88
|
-
}
|
|
89
|
-
function writeAtomic(path, content) {
|
|
90
|
-
const tmp = `${path}.${process.pid}.tmp`;
|
|
91
|
-
writeFileSync(tmp, content, { mode: 384 });
|
|
92
|
-
renameSync(tmp, path);
|
|
93
|
-
}
|
|
94
|
-
function warmBinCache() {
|
|
95
|
-
try {
|
|
96
|
-
if (process.env.PRIM_BIN_CACHE_HIT) {
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
if (process.env.PRIM_BIN_CACHE === "0") {
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
const dir = binCacheDir();
|
|
103
|
-
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
104
|
-
chmodSync(dir, 448);
|
|
105
|
-
writeAtomic(join2(dir, "node"), process.execPath);
|
|
106
|
-
for (const bin of CACHED_BINS) {
|
|
107
|
-
const file = binFile(bin);
|
|
108
|
-
if (file) {
|
|
109
|
-
writeAtomic(join2(dir, bin), file);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
} catch {
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export {
|
|
117
|
-
binFile,
|
|
118
|
-
packageVersion,
|
|
119
|
-
pinnedHookCommand,
|
|
120
|
-
detachedHookShimCommand,
|
|
121
|
-
commandMatchesBin,
|
|
122
|
-
warmBinCache
|
|
123
|
-
};
|
package/dist/chunk-JQFN6LBO.js
DELETED
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
// src/lib/ansi.ts
|
|
2
|
-
var ANSI_CODES = {
|
|
3
|
-
yellow: "\x1B[33m",
|
|
4
|
-
magenta: "\x1B[35m",
|
|
5
|
-
blue: "\x1B[34m",
|
|
6
|
-
cyan: "\x1B[36m",
|
|
7
|
-
green: "\x1B[32m",
|
|
8
|
-
red: "\x1B[31m",
|
|
9
|
-
// 256-color approximation of the orange trigger marker (xterm 208).
|
|
10
|
-
orange: "\x1B[38;5;208m",
|
|
11
|
-
gray: "\x1B[90m"
|
|
12
|
-
};
|
|
13
|
-
var ANSI_RESET = "\x1B[0m";
|
|
14
|
-
var ANSI_DIM = "\x1B[2m";
|
|
15
|
-
var ANSI_BOLD = "\x1B[1m";
|
|
16
|
-
function supportsColor() {
|
|
17
|
-
if (process.env.NO_COLOR !== void 0 && process.env.NO_COLOR !== "") {
|
|
18
|
-
return false;
|
|
19
|
-
}
|
|
20
|
-
return process.stderr.isTTY === true;
|
|
21
|
-
}
|
|
22
|
-
function color(text, c) {
|
|
23
|
-
if (!supportsColor()) {
|
|
24
|
-
return text;
|
|
25
|
-
}
|
|
26
|
-
return `${ANSI_CODES[c]}${text}${ANSI_RESET}`;
|
|
27
|
-
}
|
|
28
|
-
function dim(text) {
|
|
29
|
-
if (!supportsColor()) {
|
|
30
|
-
return text;
|
|
31
|
-
}
|
|
32
|
-
return `${ANSI_DIM}${text}${ANSI_RESET}`;
|
|
33
|
-
}
|
|
34
|
-
function bold(text) {
|
|
35
|
-
if (!supportsColor()) {
|
|
36
|
-
return text;
|
|
37
|
-
}
|
|
38
|
-
return `${ANSI_BOLD}${text}${ANSI_RESET}`;
|
|
39
|
-
}
|
|
40
|
-
var AREA_COLORS = {
|
|
41
|
-
auth: "yellow",
|
|
42
|
-
data: "magenta",
|
|
43
|
-
mobile: "blue",
|
|
44
|
-
infra: "cyan",
|
|
45
|
-
ui: "green",
|
|
46
|
-
billing: "orange",
|
|
47
|
-
api: "blue",
|
|
48
|
-
docs: "gray",
|
|
49
|
-
testing: "gray"
|
|
50
|
-
};
|
|
51
|
-
function colorForArea(area) {
|
|
52
|
-
if (!area) {
|
|
53
|
-
return "gray";
|
|
54
|
-
}
|
|
55
|
-
return AREA_COLORS[area] ?? "gray";
|
|
56
|
-
}
|
|
57
|
-
function stripControlChars(text) {
|
|
58
|
-
let out = "";
|
|
59
|
-
for (const ch of text) {
|
|
60
|
-
const code = ch.codePointAt(0) ?? 0;
|
|
61
|
-
if (code > 31 && !(code >= 127 && code <= 159)) {
|
|
62
|
-
out += ch;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
return out;
|
|
66
|
-
}
|
|
67
|
-
var MAX_HEALTH_ERROR_LENGTH = 240;
|
|
68
|
-
function boundedHealthError(value) {
|
|
69
|
-
if (!value) return void 0;
|
|
70
|
-
const clean = stripControlChars(value).replace(/\s+/g, " ").trim();
|
|
71
|
-
if (!clean) return void 0;
|
|
72
|
-
return clean.length <= MAX_HEALTH_ERROR_LENGTH ? clean : `${clean.slice(0, MAX_HEALTH_ERROR_LENGTH - 1)}\u2026`;
|
|
73
|
-
}
|
|
74
|
-
function stripAnsi(text) {
|
|
75
|
-
return text.replace(/\u001b\[[0-9;]*m/g, "");
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// src/ingest-response.ts
|
|
79
|
-
var IngestAcknowledgementError = class extends Error {
|
|
80
|
-
constructor(message) {
|
|
81
|
-
super(message);
|
|
82
|
-
this.name = "IngestAcknowledgementError";
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
function requireDurableIngestAcknowledgement(value, expected) {
|
|
86
|
-
if (typeof value !== "object" || value === null) {
|
|
87
|
-
throw new IngestAcknowledgementError("ingest response was not an object");
|
|
88
|
-
}
|
|
89
|
-
const response = value;
|
|
90
|
-
if (response.disposition !== "persisted") {
|
|
91
|
-
throw new IngestAcknowledgementError("ingest response did not confirm persistence");
|
|
92
|
-
}
|
|
93
|
-
if (response.acknowledged !== expected) {
|
|
94
|
-
throw new IngestAcknowledgementError(
|
|
95
|
-
`ingest acknowledged ${String(response.acknowledged)} of ${String(expected)} moves`
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
return value;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export {
|
|
102
|
-
color,
|
|
103
|
-
dim,
|
|
104
|
-
bold,
|
|
105
|
-
colorForArea,
|
|
106
|
-
stripControlChars,
|
|
107
|
-
boundedHealthError,
|
|
108
|
-
stripAnsi,
|
|
109
|
-
requireDurableIngestAcknowledgement
|
|
110
|
-
};
|