@primitive.ai/prim 0.1.0-alpha.18 → 0.1.0-alpha.19
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/index.js +263 -169
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -34,9 +34,9 @@ import {
|
|
|
34
34
|
} from "./chunk-UTKQTZHL.js";
|
|
35
35
|
|
|
36
36
|
// src/index.ts
|
|
37
|
-
import { readFileSync as
|
|
38
|
-
import { dirname as
|
|
39
|
-
import { fileURLToPath as
|
|
37
|
+
import { readFileSync as readFileSync11 } from "fs";
|
|
38
|
+
import { dirname as dirname6, resolve as resolve4 } from "path";
|
|
39
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
40
40
|
import { Command } from "commander";
|
|
41
41
|
import updateNotifier from "update-notifier";
|
|
42
42
|
|
|
@@ -125,7 +125,8 @@ function registerAuthCommands(program2) {
|
|
|
125
125
|
res.end("<h1>Authentication successful!</h1><p>You can close this tab.</p>");
|
|
126
126
|
exchangeCode(siteUrl, code, verifier, `http://${LOCALHOST}:${port}/callback`).then((token) => {
|
|
127
127
|
saveToken(token);
|
|
128
|
-
console.
|
|
128
|
+
console.error(`Authenticated! Token saved to ${TOKEN_FILE_PATH}`);
|
|
129
|
+
console.log(JSON.stringify({ authenticated: true, tokenFile: TOKEN_FILE_PATH }));
|
|
129
130
|
server.close();
|
|
130
131
|
process.exit(0);
|
|
131
132
|
}).catch((err) => {
|
|
@@ -151,12 +152,12 @@ function registerAuthCommands(program2) {
|
|
|
151
152
|
authUrl.searchParams.set("state", state);
|
|
152
153
|
authUrl.searchParams.set("code_challenge", challenge);
|
|
153
154
|
authUrl.searchParams.set("code_challenge_method", "S256");
|
|
154
|
-
console.
|
|
155
|
+
console.error("Opening browser for authentication...");
|
|
155
156
|
openBrowser(authUrl.toString());
|
|
156
|
-
console.
|
|
157
|
+
console.error(`If the browser doesn't open, visit:
|
|
157
158
|
${authUrl.toString()}
|
|
158
159
|
`);
|
|
159
|
-
console.
|
|
160
|
+
console.error("Waiting for callback...");
|
|
160
161
|
setTimeout(() => {
|
|
161
162
|
console.error("Authentication timed out.");
|
|
162
163
|
server.close();
|
|
@@ -281,33 +282,94 @@ async function exchangeCode(siteUrl, code, codeVerifier, redirectUri) {
|
|
|
281
282
|
// src/commands/claude-install.ts
|
|
282
283
|
import {
|
|
283
284
|
closeSync,
|
|
284
|
-
existsSync as
|
|
285
|
+
existsSync as existsSync3,
|
|
285
286
|
fsyncSync,
|
|
286
287
|
mkdirSync as mkdirSync2,
|
|
287
288
|
openSync,
|
|
288
|
-
readFileSync as
|
|
289
|
+
readFileSync as readFileSync3,
|
|
289
290
|
renameSync,
|
|
290
291
|
writeFileSync as writeFileSync2
|
|
291
292
|
} from "fs";
|
|
292
293
|
import { homedir } from "os";
|
|
293
|
-
import { dirname as
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
var
|
|
294
|
+
import { dirname as dirname3, join as join2 } from "path";
|
|
295
|
+
|
|
296
|
+
// src/lib/bin-path.ts
|
|
297
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
298
|
+
import { dirname as dirname2, isAbsolute, join } from "path";
|
|
299
|
+
import { fileURLToPath } from "url";
|
|
300
|
+
var PKG_NAME = "@primitive.ai/prim";
|
|
301
|
+
var ROOT_WALK_LIMIT = 6;
|
|
302
|
+
var NPX_FALLBACK = `npx --yes -p ${PKG_NAME}@latest`;
|
|
303
|
+
var resolvedRoot;
|
|
304
|
+
function locateRoot() {
|
|
305
|
+
if (resolvedRoot !== void 0) {
|
|
306
|
+
return resolvedRoot;
|
|
307
|
+
}
|
|
308
|
+
let dir = dirname2(fileURLToPath(import.meta.url));
|
|
309
|
+
for (let depth = 0; depth < ROOT_WALK_LIMIT; depth++) {
|
|
310
|
+
const manifestPath = join(dir, "package.json");
|
|
311
|
+
if (existsSync2(manifestPath)) {
|
|
312
|
+
try {
|
|
313
|
+
const manifest = JSON.parse(readFileSync2(manifestPath, "utf-8"));
|
|
314
|
+
if (manifest.name === PKG_NAME && manifest.bin) {
|
|
315
|
+
resolvedRoot = { dir, bin: manifest.bin };
|
|
316
|
+
return resolvedRoot;
|
|
317
|
+
}
|
|
318
|
+
} catch {
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
const parent = dirname2(dir);
|
|
322
|
+
if (parent === dir) {
|
|
323
|
+
break;
|
|
324
|
+
}
|
|
325
|
+
dir = parent;
|
|
326
|
+
}
|
|
327
|
+
resolvedRoot = null;
|
|
328
|
+
return resolvedRoot;
|
|
329
|
+
}
|
|
330
|
+
function binFile(bin) {
|
|
331
|
+
const root = locateRoot();
|
|
332
|
+
const rel = root?.bin[bin];
|
|
333
|
+
if (!root || !rel) {
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
return isAbsolute(rel) ? rel : join(root.dir, rel);
|
|
337
|
+
}
|
|
338
|
+
function hookShimCommand(bin, args = "") {
|
|
339
|
+
const invoke = (cmd) => args ? `${cmd} ${args}` : cmd;
|
|
340
|
+
return `if command -v ${bin} >/dev/null 2>&1; then ${invoke(bin)}; elif [ -f "./node_modules/.bin/${bin}" ]; then ${invoke(`./node_modules/.bin/${bin}`)}; else ${invoke(`${NPX_FALLBACK} ${bin}`)}; fi`;
|
|
341
|
+
}
|
|
342
|
+
function commandMatchesBin(command, bin) {
|
|
343
|
+
if (!command) {
|
|
344
|
+
return false;
|
|
345
|
+
}
|
|
346
|
+
const c = command.trim();
|
|
347
|
+
if (c === bin || c.startsWith(`${bin} `)) {
|
|
348
|
+
return true;
|
|
349
|
+
}
|
|
350
|
+
return c.includes(`command -v ${bin} `);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// src/commands/claude-install.ts
|
|
354
|
+
var CAPTURE_BIN = "prim-hook";
|
|
355
|
+
var GATE_BIN = "prim-pre-tool-use";
|
|
356
|
+
var POST_TOOL_USE_BIN = "prim-post-tool-use";
|
|
357
|
+
var SESSION_START_BIN = "prim-session-start";
|
|
358
|
+
var SESSION_END_BIN = "prim-session-end";
|
|
359
|
+
var STATUSLINE_BIN = "prim";
|
|
360
|
+
var STATUSLINE_ARGS = "statusline";
|
|
361
|
+
var STATUSLINE_COMMAND = hookShimCommand(STATUSLINE_BIN, STATUSLINE_ARGS);
|
|
300
362
|
var STATUSLINE_REFRESH_SECONDS = 5;
|
|
301
|
-
var
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
]
|
|
363
|
+
var PRIM_BINS = [
|
|
364
|
+
CAPTURE_BIN,
|
|
365
|
+
GATE_BIN,
|
|
366
|
+
POST_TOOL_USE_BIN,
|
|
367
|
+
SESSION_START_BIN,
|
|
368
|
+
SESSION_END_BIN
|
|
369
|
+
];
|
|
308
370
|
var JSON_INDENT = 2;
|
|
309
|
-
var USER_SCOPE_PATH =
|
|
310
|
-
var PROJECT_SCOPE_PATH =
|
|
371
|
+
var USER_SCOPE_PATH = join2(homedir(), ".claude", "settings.json");
|
|
372
|
+
var PROJECT_SCOPE_PATH = join2(process.cwd(), ".claude", "settings.json");
|
|
311
373
|
var CAPTURE_EVENTS = [
|
|
312
374
|
"SessionStart",
|
|
313
375
|
"UserPromptSubmit",
|
|
@@ -317,21 +379,24 @@ var CAPTURE_EVENTS = [
|
|
|
317
379
|
"SessionEnd",
|
|
318
380
|
"SubagentStop"
|
|
319
381
|
];
|
|
382
|
+
function makeRegistration(event, matcher, bin, args = "") {
|
|
383
|
+
return { event, matcher, bin, command: hookShimCommand(bin, args) };
|
|
384
|
+
}
|
|
320
385
|
var REGISTRATIONS = [
|
|
321
|
-
...CAPTURE_EVENTS.map((event) => (
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
386
|
+
...CAPTURE_EVENTS.map((event) => makeRegistration(event, "*", CAPTURE_BIN)),
|
|
387
|
+
makeRegistration("PreToolUse", "Edit|Write|MultiEdit", GATE_BIN),
|
|
388
|
+
makeRegistration("PostToolUse", "Edit|Write|MultiEdit", POST_TOOL_USE_BIN),
|
|
389
|
+
makeRegistration("SessionStart", "*", SESSION_START_BIN),
|
|
390
|
+
makeRegistration("SessionEnd", "*", SESSION_END_BIN)
|
|
326
391
|
];
|
|
327
392
|
function settingsPathFor(scope) {
|
|
328
393
|
return scope === "user" ? USER_SCOPE_PATH : PROJECT_SCOPE_PATH;
|
|
329
394
|
}
|
|
330
395
|
function readSettings(path) {
|
|
331
|
-
if (!
|
|
396
|
+
if (!existsSync3(path)) {
|
|
332
397
|
return {};
|
|
333
398
|
}
|
|
334
|
-
const raw =
|
|
399
|
+
const raw = readFileSync3(path, "utf-8");
|
|
335
400
|
try {
|
|
336
401
|
return JSON.parse(raw);
|
|
337
402
|
} catch (err) {
|
|
@@ -339,16 +404,16 @@ function readSettings(path) {
|
|
|
339
404
|
throw new Error(`${path} is not valid JSON: ${detail}`);
|
|
340
405
|
}
|
|
341
406
|
}
|
|
342
|
-
function entryHasCommand(entry,
|
|
343
|
-
return entry.hooks?.some((h) => h.command
|
|
407
|
+
function entryHasCommand(entry, bin) {
|
|
408
|
+
return entry.hooks?.some((h) => commandMatchesBin(h.command, bin)) ?? false;
|
|
344
409
|
}
|
|
345
410
|
function canonicalEntry(reg) {
|
|
346
411
|
return { matcher: reg.matcher, hooks: [{ type: "command", command: reg.command }] };
|
|
347
412
|
}
|
|
348
|
-
function stripCommand(list,
|
|
413
|
+
function stripCommand(list, bin) {
|
|
349
414
|
const out = [];
|
|
350
415
|
for (const e of list) {
|
|
351
|
-
const hooks = (e.hooks ?? []).filter((h) => h.command
|
|
416
|
+
const hooks = (e.hooks ?? []).filter((h) => !commandMatchesBin(h.command, bin));
|
|
352
417
|
if (hooks.length > 0) {
|
|
353
418
|
out.push({ ...e, hooks });
|
|
354
419
|
}
|
|
@@ -362,11 +427,16 @@ function ensureRegistration(list, reg, force) {
|
|
|
362
427
|
if (hasCanonical && !force) {
|
|
363
428
|
return list;
|
|
364
429
|
}
|
|
365
|
-
return [...stripCommand(list, reg.
|
|
430
|
+
return [...stripCommand(list, reg.bin), canonicalEntry(reg)];
|
|
366
431
|
}
|
|
432
|
+
var LEGACY_STATUSLINE_COMMAND = "prim statusline";
|
|
367
433
|
function isPrimStatusLine(settings) {
|
|
368
434
|
const s = settings.statusLine;
|
|
369
|
-
|
|
435
|
+
if (s?.type !== "command") {
|
|
436
|
+
return false;
|
|
437
|
+
}
|
|
438
|
+
const c = (s.command ?? "").trim();
|
|
439
|
+
return c === LEGACY_STATUSLINE_COMMAND || c.includes("@primitive.ai/prim") && c.includes("statusline");
|
|
370
440
|
}
|
|
371
441
|
function applyStatusLine(settings) {
|
|
372
442
|
if (settings.statusLine && !isPrimStatusLine(settings)) {
|
|
@@ -393,8 +463,8 @@ function applyUninstall(settings) {
|
|
|
393
463
|
const hooks = {};
|
|
394
464
|
for (const event of Object.keys(source)) {
|
|
395
465
|
let list = source[event] ?? [];
|
|
396
|
-
for (const
|
|
397
|
-
list = stripCommand(list,
|
|
466
|
+
for (const bin of PRIM_BINS) {
|
|
467
|
+
list = stripCommand(list, bin);
|
|
398
468
|
}
|
|
399
469
|
if (list.length > 0) {
|
|
400
470
|
hooks[event] = list;
|
|
@@ -408,18 +478,18 @@ function applyUninstall(settings) {
|
|
|
408
478
|
}
|
|
409
479
|
function captureInstalled(settings) {
|
|
410
480
|
return CAPTURE_EVENTS.some(
|
|
411
|
-
(event) => (settings.hooks?.[event] ?? []).some((e) => entryHasCommand(e,
|
|
481
|
+
(event) => (settings.hooks?.[event] ?? []).some((e) => entryHasCommand(e, CAPTURE_BIN))
|
|
412
482
|
);
|
|
413
483
|
}
|
|
414
484
|
function statuslineInstalled(settings) {
|
|
415
485
|
return isPrimStatusLine(settings);
|
|
416
486
|
}
|
|
417
487
|
function isGateInstalled(settings) {
|
|
418
|
-
return (settings.hooks?.PreToolUse ?? []).some((e) => entryHasCommand(e,
|
|
488
|
+
return (settings.hooks?.PreToolUse ?? []).some((e) => entryHasCommand(e, GATE_BIN));
|
|
419
489
|
}
|
|
420
490
|
function atomicWrite(path, content) {
|
|
421
|
-
const dir =
|
|
422
|
-
if (!
|
|
491
|
+
const dir = dirname3(path);
|
|
492
|
+
if (!existsSync3(dir)) {
|
|
423
493
|
mkdirSync2(dir, { recursive: true });
|
|
424
494
|
}
|
|
425
495
|
const tmp = `${path}.tmp.${String(Date.now())}`;
|
|
@@ -535,11 +605,12 @@ ${line("project", result.project)}`);
|
|
|
535
605
|
|
|
536
606
|
// src/commands/codex-install.ts
|
|
537
607
|
import { homedir as homedir2 } from "os";
|
|
538
|
-
import { join as
|
|
539
|
-
var
|
|
540
|
-
var
|
|
541
|
-
var
|
|
542
|
-
var
|
|
608
|
+
import { join as join3 } from "path";
|
|
609
|
+
var CAPTURE_BIN2 = "prim-hook";
|
|
610
|
+
var GATE_BIN2 = "prim-pre-tool-use";
|
|
611
|
+
var POST_TOOL_USE_BIN2 = "prim-post-tool-use";
|
|
612
|
+
var SESSION_START_BIN2 = "prim-session-start";
|
|
613
|
+
var CODEX_ARGS = "--agent codex";
|
|
543
614
|
var JSON_INDENT2 = 2;
|
|
544
615
|
var CODEX_CAPTURE_EVENTS = [
|
|
545
616
|
"SessionStart",
|
|
@@ -549,20 +620,15 @@ var CODEX_CAPTURE_EVENTS = [
|
|
|
549
620
|
"Stop",
|
|
550
621
|
"SubagentStop"
|
|
551
622
|
];
|
|
552
|
-
var
|
|
553
|
-
CAPTURE_COMMAND2,
|
|
554
|
-
GATE_COMMAND2,
|
|
555
|
-
POST_TOOL_USE_COMMAND2,
|
|
556
|
-
SESSION_START_COMMAND2
|
|
557
|
-
]);
|
|
623
|
+
var PRIM_BINS2 = [CAPTURE_BIN2, GATE_BIN2, POST_TOOL_USE_BIN2, SESSION_START_BIN2];
|
|
558
624
|
var CODEX_REGISTRATIONS = [
|
|
559
|
-
...CODEX_CAPTURE_EVENTS.map((event) => (
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
625
|
+
...CODEX_CAPTURE_EVENTS.map((event) => makeRegistration(event, "*", CAPTURE_BIN2, CODEX_ARGS)),
|
|
626
|
+
makeRegistration("PreToolUse", "apply_patch", GATE_BIN2, CODEX_ARGS),
|
|
627
|
+
makeRegistration("PostToolUse", "apply_patch", POST_TOOL_USE_BIN2, CODEX_ARGS),
|
|
628
|
+
makeRegistration("SessionStart", "*", SESSION_START_BIN2, CODEX_ARGS)
|
|
563
629
|
];
|
|
564
|
-
var USER_SCOPE_PATH2 =
|
|
565
|
-
var PROJECT_SCOPE_PATH2 =
|
|
630
|
+
var USER_SCOPE_PATH2 = join3(homedir2(), ".codex", "hooks.json");
|
|
631
|
+
var PROJECT_SCOPE_PATH2 = join3(process.cwd(), ".codex", "hooks.json");
|
|
566
632
|
function settingsPathFor2(scope) {
|
|
567
633
|
return scope === "user" ? USER_SCOPE_PATH2 : PROJECT_SCOPE_PATH2;
|
|
568
634
|
}
|
|
@@ -578,8 +644,8 @@ function applyUninstall2(settings) {
|
|
|
578
644
|
const hooks = {};
|
|
579
645
|
for (const event of Object.keys(source)) {
|
|
580
646
|
let list = source[event] ?? [];
|
|
581
|
-
for (const
|
|
582
|
-
list = stripCommand(list,
|
|
647
|
+
for (const bin of PRIM_BINS2) {
|
|
648
|
+
list = stripCommand(list, bin);
|
|
583
649
|
}
|
|
584
650
|
if (list.length > 0) {
|
|
585
651
|
hooks[event] = list;
|
|
@@ -589,11 +655,11 @@ function applyUninstall2(settings) {
|
|
|
589
655
|
}
|
|
590
656
|
function captureInstalled2(settings) {
|
|
591
657
|
return CODEX_CAPTURE_EVENTS.some(
|
|
592
|
-
(event) => (settings.hooks?.[event] ?? []).some((e) => entryHasCommand(e,
|
|
658
|
+
(event) => (settings.hooks?.[event] ?? []).some((e) => entryHasCommand(e, CAPTURE_BIN2))
|
|
593
659
|
);
|
|
594
660
|
}
|
|
595
661
|
function isGateInstalled2(settings) {
|
|
596
|
-
return (settings.hooks?.PreToolUse ?? []).some((e) => entryHasCommand(e,
|
|
662
|
+
return (settings.hooks?.PreToolUse ?? []).some((e) => entryHasCommand(e, GATE_BIN2));
|
|
597
663
|
}
|
|
598
664
|
function resultFor(scope, path, after, changed) {
|
|
599
665
|
return {
|
|
@@ -682,7 +748,7 @@ ${line("project", result.project)}`);
|
|
|
682
748
|
}
|
|
683
749
|
|
|
684
750
|
// src/commands/context.ts
|
|
685
|
-
import { readFileSync as
|
|
751
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
686
752
|
function registerContextCommands(program2) {
|
|
687
753
|
const context = program2.command("context").description("Manage contexts");
|
|
688
754
|
context.command("list").description("List contexts").option("-s, --scope <scope>", "Filter by scope: project, global, external").option("-t, --project-id <projectId>", "List contexts linked to a specific project").option("--json", "Output as JSON").action(async (opts) => {
|
|
@@ -711,7 +777,7 @@ function registerContextCommands(program2) {
|
|
|
711
777
|
const client = getClient();
|
|
712
778
|
let text = opts.text;
|
|
713
779
|
if (opts.file) {
|
|
714
|
-
text =
|
|
780
|
+
text = readFileSync4(opts.file, "utf-8");
|
|
715
781
|
}
|
|
716
782
|
const taskIds = opts.projectId ? opts.projectId.split(",").map((id) => id.trim()) : void 0;
|
|
717
783
|
const result = await client.post("/api/cli/contexts", {
|
|
@@ -734,7 +800,7 @@ function registerContextCommands(program2) {
|
|
|
734
800
|
const client = getClient();
|
|
735
801
|
let text = opts.text;
|
|
736
802
|
if (opts.file) {
|
|
737
|
-
text =
|
|
803
|
+
text = readFileSync4(opts.file, "utf-8");
|
|
738
804
|
}
|
|
739
805
|
await client.patch(`/api/cli/contexts/${contextId}`, {
|
|
740
806
|
name: opts.name,
|
|
@@ -800,22 +866,26 @@ ${contexts.length} context(s)`);
|
|
|
800
866
|
|
|
801
867
|
// src/commands/daemon.ts
|
|
802
868
|
import { spawn } from "child_process";
|
|
803
|
-
import { existsSync as
|
|
869
|
+
import { existsSync as existsSync4, readFileSync as readFileSync5, unlinkSync } from "fs";
|
|
804
870
|
import { homedir as homedir3 } from "os";
|
|
805
|
-
import { join as
|
|
871
|
+
import { join as join4 } from "path";
|
|
806
872
|
var DAEMON_BIN = "prim-daemon-server";
|
|
807
|
-
var PID_PATH =
|
|
808
|
-
var SOCK_PATH =
|
|
873
|
+
var PID_PATH = join4(homedir3(), ".config", "prim", "daemon.pid");
|
|
874
|
+
var SOCK_PATH = join4(homedir3(), ".config", "prim", "sock");
|
|
809
875
|
var STOP_TIMEOUT_MS = 5e3;
|
|
810
876
|
var STOP_POLL_MS = 100;
|
|
811
877
|
var STATUS_PROBE_TIMEOUT_MS = 500;
|
|
812
|
-
var
|
|
878
|
+
var READY_TIMEOUT_MS = 5e3;
|
|
879
|
+
var READY_POLL_MS = 100;
|
|
880
|
+
var READY_PROBE_TIMEOUT_MS = 250;
|
|
881
|
+
var EXIT_OK = 0;
|
|
813
882
|
var EXIT_NOT_RUNNING = 2;
|
|
883
|
+
var EXIT_BOOTING = 3;
|
|
814
884
|
function readPidfile() {
|
|
815
|
-
if (!
|
|
885
|
+
if (!existsSync4(PID_PATH)) {
|
|
816
886
|
return null;
|
|
817
887
|
}
|
|
818
|
-
const raw =
|
|
888
|
+
const raw = readFileSync5(PID_PATH, "utf-8").trim();
|
|
819
889
|
const pid = Number(raw);
|
|
820
890
|
if (!Number.isInteger(pid) || pid <= 0) {
|
|
821
891
|
return null;
|
|
@@ -846,6 +916,20 @@ function sleep(ms) {
|
|
|
846
916
|
timer.unref();
|
|
847
917
|
});
|
|
848
918
|
}
|
|
919
|
+
function spawnDaemon(options) {
|
|
920
|
+
const file = binFile(DAEMON_BIN);
|
|
921
|
+
return file ? spawn(process.execPath, [file], options) : spawn(DAEMON_BIN, [], options);
|
|
922
|
+
}
|
|
923
|
+
async function waitForReady() {
|
|
924
|
+
const deadline = Date.now() + READY_TIMEOUT_MS;
|
|
925
|
+
while (Date.now() < deadline) {
|
|
926
|
+
if (await daemonIsLive(READY_PROBE_TIMEOUT_MS)) {
|
|
927
|
+
return true;
|
|
928
|
+
}
|
|
929
|
+
await sleep(READY_POLL_MS);
|
|
930
|
+
}
|
|
931
|
+
return daemonIsLive(READY_PROBE_TIMEOUT_MS);
|
|
932
|
+
}
|
|
849
933
|
async function daemonStart(opts) {
|
|
850
934
|
const existing = readPidfile();
|
|
851
935
|
if (existing?.alive) {
|
|
@@ -858,29 +942,32 @@ async function daemonStart(opts) {
|
|
|
858
942
|
clearStaleArtifacts();
|
|
859
943
|
}
|
|
860
944
|
if (opts.foreground) {
|
|
861
|
-
const child2 =
|
|
945
|
+
const child2 = spawnDaemon({ stdio: "inherit" });
|
|
862
946
|
child2.on("exit", (code) => {
|
|
863
947
|
process.exit(code ?? 0);
|
|
864
948
|
});
|
|
865
949
|
return;
|
|
866
950
|
}
|
|
867
|
-
const child =
|
|
868
|
-
detached: true,
|
|
869
|
-
stdio: ["ignore", "ignore", "ignore"]
|
|
870
|
-
});
|
|
951
|
+
const child = spawnDaemon({ detached: true, stdio: ["ignore", "ignore", "ignore"] });
|
|
871
952
|
child.unref();
|
|
872
|
-
await
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
process.stderr.write(
|
|
876
|
-
`)
|
|
877
|
-
|
|
953
|
+
const live = await waitForReady();
|
|
954
|
+
if (live) {
|
|
955
|
+
const after = readPidfile();
|
|
956
|
+
process.stderr.write(
|
|
957
|
+
`[prim] \u2713 daemon started (pid=${after?.pid ?? "?"}, socket=${SOCK_PATH})
|
|
958
|
+
`
|
|
959
|
+
);
|
|
960
|
+
console.log(JSON.stringify({ started: true, pid: after?.pid }, null, 2));
|
|
878
961
|
return;
|
|
879
962
|
}
|
|
880
963
|
process.stderr.write(
|
|
881
|
-
|
|
964
|
+
`[prim] \u2717 daemon start: spawned but the socket did not respond within ${READY_TIMEOUT_MS}ms (check that \`${DAEMON_BIN}\` resolves, and see its log)
|
|
965
|
+
`
|
|
882
966
|
);
|
|
883
967
|
console.log(JSON.stringify({ started: false }, null, 2));
|
|
968
|
+
if (!process.exitCode) {
|
|
969
|
+
process.exitCode = EXIT_NOT_RUNNING;
|
|
970
|
+
}
|
|
884
971
|
}
|
|
885
972
|
async function daemonStop() {
|
|
886
973
|
const existing = readPidfile();
|
|
@@ -922,41 +1009,48 @@ async function daemonStop() {
|
|
|
922
1009
|
);
|
|
923
1010
|
console.log(JSON.stringify({ stopped: false, pid: existing.pid }, null, 2));
|
|
924
1011
|
}
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
process.stderr.write("[prim] \u2717 daemon down\n");
|
|
929
|
-
console.log(JSON.stringify({ running: false }, null, 2));
|
|
930
|
-
if (!process.exitCode) {
|
|
931
|
-
process.exitCode = EXIT_NOT_RUNNING;
|
|
932
|
-
}
|
|
933
|
-
return;
|
|
1012
|
+
function classifyStatus(pidAlive, responding, snapshot, pid) {
|
|
1013
|
+
if (!pidAlive) {
|
|
1014
|
+
return { json: { running: false }, exitCode: EXIT_NOT_RUNNING };
|
|
934
1015
|
}
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
if (!process.exitCode) {
|
|
941
|
-
process.exitCode = EXIT_NOT_RUNNING;
|
|
942
|
-
}
|
|
943
|
-
return;
|
|
1016
|
+
if (!responding) {
|
|
1017
|
+
return {
|
|
1018
|
+
json: { running: true, responding: false, state: "starting", pid },
|
|
1019
|
+
exitCode: EXIT_BOOTING
|
|
1020
|
+
};
|
|
944
1021
|
}
|
|
945
|
-
|
|
1022
|
+
if (!snapshot) {
|
|
1023
|
+
return { json: { running: true, responding: true }, exitCode: EXIT_OK };
|
|
1024
|
+
}
|
|
1025
|
+
return { json: { running: true, responding: true, ...snapshot }, exitCode: EXIT_OK };
|
|
1026
|
+
}
|
|
1027
|
+
async function daemonStatus() {
|
|
1028
|
+
const pid = readPidfile();
|
|
1029
|
+
const pidAlive = pid?.alive ?? false;
|
|
1030
|
+
const responding = pidAlive ? await daemonIsLive(STATUS_PROBE_TIMEOUT_MS) : false;
|
|
1031
|
+
const snapshot = responding ? await daemonRequest(
|
|
946
1032
|
"status_snapshot",
|
|
947
1033
|
{},
|
|
948
1034
|
{ timeoutMs: STATUS_PROBE_TIMEOUT_MS }
|
|
949
|
-
);
|
|
950
|
-
|
|
1035
|
+
) : null;
|
|
1036
|
+
const { json, exitCode } = classifyStatus(pidAlive, responding, snapshot, pid?.pid);
|
|
1037
|
+
if (!pidAlive) {
|
|
1038
|
+
process.stderr.write("[prim] \u2717 daemon down\n");
|
|
1039
|
+
} else if (!responding) {
|
|
1040
|
+
process.stderr.write(`[prim] \u25CC daemon pid=${pid?.pid} starting (socket not responding yet)
|
|
1041
|
+
`);
|
|
1042
|
+
} else if (!snapshot) {
|
|
951
1043
|
process.stderr.write("[prim] \u2713 daemon live (no snapshot)\n");
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
process.stderr.write(
|
|
956
|
-
`[prim] \u2713 daemon live \xB7 pid=${snapshot.pid} \xB7 uptime=${Math.round(snapshot.uptimeMs / 1e3)}s \xB7 session=${snapshot.sessionId}
|
|
1044
|
+
} else {
|
|
1045
|
+
process.stderr.write(
|
|
1046
|
+
`[prim] \u2713 daemon live \xB7 pid=${snapshot.pid} \xB7 uptime=${Math.round(snapshot.uptimeMs / 1e3)}s \xB7 session=${snapshot.sessionId}
|
|
957
1047
|
`
|
|
958
|
-
|
|
959
|
-
|
|
1048
|
+
);
|
|
1049
|
+
}
|
|
1050
|
+
console.log(JSON.stringify(json, null, 2));
|
|
1051
|
+
if (exitCode !== EXIT_OK && !process.exitCode) {
|
|
1052
|
+
process.exitCode = exitCode;
|
|
1053
|
+
}
|
|
960
1054
|
}
|
|
961
1055
|
async function daemonRestart(opts) {
|
|
962
1056
|
await daemonStop();
|
|
@@ -1574,7 +1668,7 @@ function registerDecisionsCommands(program2) {
|
|
|
1574
1668
|
|
|
1575
1669
|
// src/commands/hooks.ts
|
|
1576
1670
|
import { execSync } from "child_process";
|
|
1577
|
-
import { existsSync as
|
|
1671
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync6, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
1578
1672
|
import { resolve } from "path";
|
|
1579
1673
|
import { Option } from "commander";
|
|
1580
1674
|
var PRE_COMMIT = { hookName: "pre-commit", binName: "prim-pre-commit" };
|
|
@@ -1617,13 +1711,13 @@ function getGitRoot() {
|
|
|
1617
1711
|
}
|
|
1618
1712
|
function detectHusky(gitRoot) {
|
|
1619
1713
|
const huskyDir = resolve(gitRoot, ".husky");
|
|
1620
|
-
if (!
|
|
1621
|
-
if (
|
|
1622
|
-
if (
|
|
1714
|
+
if (!existsSync5(huskyDir)) return false;
|
|
1715
|
+
if (existsSync5(resolve(huskyDir, "_"))) return true;
|
|
1716
|
+
if (existsSync5(resolve(huskyDir, "pre-commit"))) return true;
|
|
1623
1717
|
const pkgPath = resolve(gitRoot, "package.json");
|
|
1624
|
-
if (
|
|
1718
|
+
if (existsSync5(pkgPath)) {
|
|
1625
1719
|
try {
|
|
1626
|
-
const pkg2 = JSON.parse(
|
|
1720
|
+
const pkg2 = JSON.parse(readFileSync6(pkgPath, "utf-8"));
|
|
1627
1721
|
const scripts = pkg2.scripts ?? {};
|
|
1628
1722
|
if (/husky/i.test(scripts.prepare ?? "") || /husky/i.test(scripts.postinstall ?? "")) {
|
|
1629
1723
|
return true;
|
|
@@ -1650,8 +1744,8 @@ async function askConfirmation(question) {
|
|
|
1650
1744
|
}
|
|
1651
1745
|
function installToHusky(gitRoot, spec = PRE_COMMIT) {
|
|
1652
1746
|
const hookPath = resolve(gitRoot, ".husky", spec.hookName);
|
|
1653
|
-
if (
|
|
1654
|
-
const existing =
|
|
1747
|
+
if (existsSync5(hookPath)) {
|
|
1748
|
+
const existing = readFileSync6(hookPath, "utf-8");
|
|
1655
1749
|
if (containsPrimHook(existing, spec.binName)) {
|
|
1656
1750
|
console.log(`Prim ${spec.hookName} hook is already installed in .husky/${spec.hookName}.`);
|
|
1657
1751
|
return;
|
|
@@ -1675,11 +1769,11 @@ ${huskyBlock(spec)}
|
|
|
1675
1769
|
function installToDotGit(gitRoot, spec = PRE_COMMIT) {
|
|
1676
1770
|
const hooksDir = resolve(gitRoot, ".git", "hooks");
|
|
1677
1771
|
const hookPath = resolve(hooksDir, spec.hookName);
|
|
1678
|
-
if (!
|
|
1772
|
+
if (!existsSync5(hooksDir)) {
|
|
1679
1773
|
mkdirSync3(hooksDir, { recursive: true });
|
|
1680
1774
|
}
|
|
1681
|
-
if (
|
|
1682
|
-
const existing =
|
|
1775
|
+
if (existsSync5(hookPath)) {
|
|
1776
|
+
const existing = readFileSync6(hookPath, "utf-8");
|
|
1683
1777
|
if (containsPrimHook(existing, spec.binName)) {
|
|
1684
1778
|
console.log(`Prim ${spec.hookName} hook is already installed at ${hookPath}.`);
|
|
1685
1779
|
return;
|
|
@@ -1742,11 +1836,11 @@ function registerHooksCommands(program2) {
|
|
|
1742
1836
|
const gitRoot = getGitRoot();
|
|
1743
1837
|
for (const spec of HOOKS) {
|
|
1744
1838
|
const hookPath = resolve(gitRoot, ".git", "hooks", spec.hookName);
|
|
1745
|
-
if (!
|
|
1839
|
+
if (!existsSync5(hookPath)) {
|
|
1746
1840
|
console.log(`No ${spec.hookName} hook found.`);
|
|
1747
1841
|
continue;
|
|
1748
1842
|
}
|
|
1749
|
-
if (containsPrimHook(
|
|
1843
|
+
if (containsPrimHook(readFileSync6(hookPath, "utf-8"), spec.binName)) {
|
|
1750
1844
|
unlinkSync2(hookPath);
|
|
1751
1845
|
console.log(`Removed ${spec.hookName} hook at ${hookPath}`);
|
|
1752
1846
|
} else {
|
|
@@ -1757,8 +1851,8 @@ function registerHooksCommands(program2) {
|
|
|
1757
1851
|
}
|
|
1758
1852
|
|
|
1759
1853
|
// src/commands/moves.ts
|
|
1760
|
-
import { existsSync as
|
|
1761
|
-
import { join as
|
|
1854
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync4, unlinkSync as unlinkSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
1855
|
+
import { join as join5 } from "path";
|
|
1762
1856
|
|
|
1763
1857
|
// src/flusher.ts
|
|
1764
1858
|
import { renameSync as renameSync2, unlinkSync as unlinkSync3 } from "fs";
|
|
@@ -1867,19 +1961,19 @@ function registerMovesCommands(program2) {
|
|
|
1867
1961
|
}
|
|
1868
1962
|
});
|
|
1869
1963
|
moves.command("bind").description("Pin the current directory to an org via .prim/workspace.json").requiredOption("--orgId <orgId>", "Convex organization id").action((opts) => {
|
|
1870
|
-
const dir =
|
|
1871
|
-
if (!
|
|
1964
|
+
const dir = join5(process.cwd(), ".prim");
|
|
1965
|
+
if (!existsSync6(dir)) {
|
|
1872
1966
|
mkdirSync4(dir, { recursive: true, mode: DIR_MODE });
|
|
1873
1967
|
}
|
|
1874
|
-
const file =
|
|
1968
|
+
const file = join5(process.cwd(), WORKSPACE_FILE);
|
|
1875
1969
|
writeFileSync4(file, JSON.stringify({ orgId: opts.orgId, boundAt: Date.now() }, null, 2), {
|
|
1876
1970
|
mode: FILE_MODE2
|
|
1877
1971
|
});
|
|
1878
1972
|
console.log(`[prim] bound ${process.cwd()} to org ${opts.orgId}`);
|
|
1879
1973
|
});
|
|
1880
1974
|
moves.command("drop").description("Remove the .prim/workspace.json binding from the cwd").action(() => {
|
|
1881
|
-
const file =
|
|
1882
|
-
if (!
|
|
1975
|
+
const file = join5(process.cwd(), WORKSPACE_FILE);
|
|
1976
|
+
if (!existsSync6(file)) {
|
|
1883
1977
|
console.log("[prim] no workspace binding in cwd");
|
|
1884
1978
|
return;
|
|
1885
1979
|
}
|
|
@@ -1911,7 +2005,7 @@ function registerProjectCommands(program2) {
|
|
|
1911
2005
|
}
|
|
1912
2006
|
|
|
1913
2007
|
// src/commands/reconcile.ts
|
|
1914
|
-
var
|
|
2008
|
+
var EXIT_OK2 = 0;
|
|
1915
2009
|
var EXIT_USAGE = 2;
|
|
1916
2010
|
var EXIT_SERVER = 3;
|
|
1917
2011
|
var HTTP_CLIENT_ERROR_MIN = 400;
|
|
@@ -1974,7 +2068,7 @@ async function performReconcile(idOrShortId, opts = {}) {
|
|
|
1974
2068
|
`
|
|
1975
2069
|
);
|
|
1976
2070
|
console.log(JSON.stringify(response, null, 2));
|
|
1977
|
-
process.exitCode =
|
|
2071
|
+
process.exitCode = EXIT_OK2;
|
|
1978
2072
|
return;
|
|
1979
2073
|
}
|
|
1980
2074
|
process.stderr.write("[prim] reconcile: malformed server response\n");
|
|
@@ -1994,23 +2088,23 @@ function registerReconcileCommands(program2) {
|
|
|
1994
2088
|
|
|
1995
2089
|
// src/commands/session.ts
|
|
1996
2090
|
import {
|
|
1997
|
-
existsSync as
|
|
2091
|
+
existsSync as existsSync7,
|
|
1998
2092
|
mkdirSync as mkdirSync5,
|
|
1999
|
-
readFileSync as
|
|
2093
|
+
readFileSync as readFileSync7,
|
|
2000
2094
|
readdirSync,
|
|
2001
2095
|
unlinkSync as unlinkSync5,
|
|
2002
2096
|
writeFileSync as writeFileSync5
|
|
2003
2097
|
} from "fs";
|
|
2004
|
-
import { join as
|
|
2098
|
+
import { join as join6 } from "path";
|
|
2005
2099
|
var DIR_MODE2 = 448;
|
|
2006
2100
|
var FILE_MODE3 = 384;
|
|
2007
2101
|
function ensureDir() {
|
|
2008
|
-
if (!
|
|
2102
|
+
if (!existsSync7(SESSIONS_DIR)) {
|
|
2009
2103
|
mkdirSync5(SESSIONS_DIR, { recursive: true, mode: DIR_MODE2 });
|
|
2010
2104
|
}
|
|
2011
2105
|
}
|
|
2012
2106
|
function markerPath(sessionId) {
|
|
2013
|
-
return
|
|
2107
|
+
return join6(SESSIONS_DIR, `${sessionId}.json`);
|
|
2014
2108
|
}
|
|
2015
2109
|
function registerSessionCommands(program2) {
|
|
2016
2110
|
const session = program2.command("session").description("Decision Event Pipeline \u2014 session binding markers");
|
|
@@ -2026,7 +2120,7 @@ function registerSessionCommands(program2) {
|
|
|
2026
2120
|
console.log(`[prim] session ${sessionId} bound to org ${opts.orgId}`);
|
|
2027
2121
|
});
|
|
2028
2122
|
session.command("list").description("List active session markers").action(() => {
|
|
2029
|
-
if (!
|
|
2123
|
+
if (!existsSync7(SESSIONS_DIR)) {
|
|
2030
2124
|
console.log("[prim] no session markers");
|
|
2031
2125
|
return;
|
|
2032
2126
|
}
|
|
@@ -2038,7 +2132,7 @@ function registerSessionCommands(program2) {
|
|
|
2038
2132
|
for (const f of files) {
|
|
2039
2133
|
const sessionId = f.replace(/\.json$/, "");
|
|
2040
2134
|
try {
|
|
2041
|
-
const m = JSON.parse(
|
|
2135
|
+
const m = JSON.parse(readFileSync7(join6(SESSIONS_DIR, f), "utf-8"));
|
|
2042
2136
|
console.log(`${sessionId} org=${m.orgId}`);
|
|
2043
2137
|
} catch {
|
|
2044
2138
|
}
|
|
@@ -2046,7 +2140,7 @@ function registerSessionCommands(program2) {
|
|
|
2046
2140
|
});
|
|
2047
2141
|
session.command("drop <sessionId>").description("Remove a session marker").action((sessionId) => {
|
|
2048
2142
|
const p = markerPath(sessionId);
|
|
2049
|
-
if (!
|
|
2143
|
+
if (!existsSync7(p)) {
|
|
2050
2144
|
console.log(`[prim] no marker for session ${sessionId}`);
|
|
2051
2145
|
return;
|
|
2052
2146
|
}
|
|
@@ -2058,17 +2152,17 @@ function registerSessionCommands(program2) {
|
|
|
2058
2152
|
// src/commands/skill.ts
|
|
2059
2153
|
import {
|
|
2060
2154
|
closeSync as closeSync2,
|
|
2061
|
-
existsSync as
|
|
2155
|
+
existsSync as existsSync8,
|
|
2062
2156
|
fsyncSync as fsyncSync2,
|
|
2063
2157
|
openSync as openSync2,
|
|
2064
|
-
readFileSync as
|
|
2158
|
+
readFileSync as readFileSync8,
|
|
2065
2159
|
renameSync as renameSync3,
|
|
2066
2160
|
writeFileSync as writeFileSync6
|
|
2067
2161
|
} from "fs";
|
|
2068
|
-
import { dirname as
|
|
2069
|
-
import { fileURLToPath } from "url";
|
|
2162
|
+
import { dirname as dirname4, resolve as resolve2 } from "path";
|
|
2163
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2070
2164
|
import { createPatch } from "diff";
|
|
2071
|
-
var __dirname =
|
|
2165
|
+
var __dirname = dirname4(fileURLToPath2(import.meta.url));
|
|
2072
2166
|
var SKILL_BEGIN = "<!-- BEGIN PRIM SKILL v1 -->";
|
|
2073
2167
|
var SKILL_END = "<!-- END PRIM SKILL v1 -->";
|
|
2074
2168
|
var TARGET_CANDIDATES = [
|
|
@@ -2081,15 +2175,15 @@ var TARGET_CANDIDATES = [
|
|
|
2081
2175
|
var DEFAULT_TARGET = "CLAUDE.md";
|
|
2082
2176
|
function loadSkill() {
|
|
2083
2177
|
let dir = __dirname;
|
|
2084
|
-
while (dir !==
|
|
2178
|
+
while (dir !== dirname4(dir)) {
|
|
2085
2179
|
const p = resolve2(dir, "SKILL.md");
|
|
2086
|
-
if (
|
|
2087
|
-
dir =
|
|
2180
|
+
if (existsSync8(p)) return readFileSync8(p, "utf-8");
|
|
2181
|
+
dir = dirname4(dir);
|
|
2088
2182
|
}
|
|
2089
2183
|
throw new Error("SKILL.md not found in package");
|
|
2090
2184
|
}
|
|
2091
2185
|
function detectTargets(cwd) {
|
|
2092
|
-
return TARGET_CANDIDATES.filter((p) =>
|
|
2186
|
+
return TARGET_CANDIDATES.filter((p) => existsSync8(resolve2(cwd, p)));
|
|
2093
2187
|
}
|
|
2094
2188
|
function detectNewline(content) {
|
|
2095
2189
|
return content.includes("\r\n") ? "\r\n" : "\n";
|
|
@@ -2138,7 +2232,7 @@ function resolveTarget(cwd, override) {
|
|
|
2138
2232
|
function runInstall(cwd, opts) {
|
|
2139
2233
|
const target = resolveTarget(cwd, opts.target);
|
|
2140
2234
|
if (target === null) return 1;
|
|
2141
|
-
const existing =
|
|
2235
|
+
const existing = existsSync8(target) ? readFileSync8(target, "utf-8") : "";
|
|
2142
2236
|
const eol = existing ? detectNewline(existing) : "\n";
|
|
2143
2237
|
const block = composeBlock(loadSkill(), eol);
|
|
2144
2238
|
const next = applyBlock(existing, block, eol);
|
|
@@ -2157,11 +2251,11 @@ function runInstall(cwd, opts) {
|
|
|
2157
2251
|
function runUninstall(cwd, opts) {
|
|
2158
2252
|
const target = resolveTarget(cwd, opts.target);
|
|
2159
2253
|
if (target === null) return 1;
|
|
2160
|
-
if (!
|
|
2254
|
+
if (!existsSync8(target)) {
|
|
2161
2255
|
console.log(`Skill block not present at ${target}`);
|
|
2162
2256
|
return 0;
|
|
2163
2257
|
}
|
|
2164
|
-
const existing =
|
|
2258
|
+
const existing = readFileSync8(target, "utf-8");
|
|
2165
2259
|
const next = removeBlock(existing);
|
|
2166
2260
|
if (next === null) {
|
|
2167
2261
|
console.log(`Skill block not present at ${target}`);
|
|
@@ -2174,10 +2268,10 @@ function runUninstall(cwd, opts) {
|
|
|
2174
2268
|
function runStatus(cwd, opts) {
|
|
2175
2269
|
const target = resolveTarget(cwd, opts.target);
|
|
2176
2270
|
if (target === null) return 1;
|
|
2177
|
-
const fileExists =
|
|
2271
|
+
const fileExists = existsSync8(target);
|
|
2178
2272
|
let installed = false;
|
|
2179
2273
|
if (fileExists) {
|
|
2180
|
-
const content =
|
|
2274
|
+
const content = readFileSync8(target, "utf-8");
|
|
2181
2275
|
installed = content.includes(SKILL_BEGIN) && content.includes(SKILL_END);
|
|
2182
2276
|
}
|
|
2183
2277
|
if (opts.json) {
|
|
@@ -2214,7 +2308,7 @@ function registerSkillCommands(program2) {
|
|
|
2214
2308
|
}
|
|
2215
2309
|
|
|
2216
2310
|
// src/commands/spec.ts
|
|
2217
|
-
import { readFileSync as
|
|
2311
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
2218
2312
|
function registerSpecCommands(program2) {
|
|
2219
2313
|
const spec = program2.command("spec").description("Manage spec documents");
|
|
2220
2314
|
spec.command("list").description("List spec documents").option("-t, --project-id <projectId>", "List spec for a specific root project").option("--json", "Output as JSON").action(async (opts) => {
|
|
@@ -2268,7 +2362,7 @@ ${contexts.length} spec(s)`);
|
|
|
2268
2362
|
const client = getClient();
|
|
2269
2363
|
let text = opts.text;
|
|
2270
2364
|
if (opts.file) {
|
|
2271
|
-
text =
|
|
2365
|
+
text = readFileSync9(opts.file, "utf-8");
|
|
2272
2366
|
}
|
|
2273
2367
|
const taskIds = opts.projectId ? opts.projectId.split(",").map((id) => id.trim()) : void 0;
|
|
2274
2368
|
let linkedBranch;
|
|
@@ -2309,7 +2403,7 @@ ${contexts.length} spec(s)`);
|
|
|
2309
2403
|
const client = getClient();
|
|
2310
2404
|
let text = opts.text;
|
|
2311
2405
|
if (opts.file) {
|
|
2312
|
-
text =
|
|
2406
|
+
text = readFileSync9(opts.file, "utf-8");
|
|
2313
2407
|
}
|
|
2314
2408
|
if (!(text || opts.name)) {
|
|
2315
2409
|
console.error("Provide --text, --file, or --name to update.");
|
|
@@ -2480,17 +2574,17 @@ ${preview}`);
|
|
|
2480
2574
|
}
|
|
2481
2575
|
|
|
2482
2576
|
// src/commands/statusline.ts
|
|
2483
|
-
import { readFileSync as
|
|
2484
|
-
import { dirname as
|
|
2485
|
-
import { fileURLToPath as
|
|
2577
|
+
import { readFileSync as readFileSync10 } from "fs";
|
|
2578
|
+
import { dirname as dirname5, resolve as resolve3 } from "path";
|
|
2579
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
2486
2580
|
var STATUSLINE_TIMEOUT_MS = 200;
|
|
2487
2581
|
function readPackageVersion() {
|
|
2488
2582
|
try {
|
|
2489
|
-
const here =
|
|
2583
|
+
const here = dirname5(fileURLToPath3(import.meta.url));
|
|
2490
2584
|
const candidates = [resolve3(here, "../../package.json"), resolve3(here, "../package.json")];
|
|
2491
2585
|
for (const path of candidates) {
|
|
2492
2586
|
try {
|
|
2493
|
-
const pkg2 = JSON.parse(
|
|
2587
|
+
const pkg2 = JSON.parse(readFileSync10(path, "utf-8"));
|
|
2494
2588
|
if (pkg2.version) {
|
|
2495
2589
|
return pkg2.version;
|
|
2496
2590
|
}
|
|
@@ -2535,8 +2629,8 @@ function registerStatuslineCommands(program2) {
|
|
|
2535
2629
|
}
|
|
2536
2630
|
|
|
2537
2631
|
// src/index.ts
|
|
2538
|
-
var __dirname2 =
|
|
2539
|
-
var pkg = JSON.parse(
|
|
2632
|
+
var __dirname2 = dirname6(fileURLToPath4(import.meta.url));
|
|
2633
|
+
var pkg = JSON.parse(readFileSync11(resolve4(__dirname2, "../package.json"), "utf-8"));
|
|
2540
2634
|
updateNotifier({ pkg }).notify();
|
|
2541
2635
|
var program = new Command();
|
|
2542
2636
|
program.name("prim").description("CLI for managing Primitive specs and contexts").version(pkg.version).option("-y, --yes", "auto-confirm prompts").option(
|