@primitive.ai/prim 0.1.0-alpha.90 → 0.1.0-alpha.92
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/README.md +20 -12
- package/SKILL.md +6 -6
- package/dist/chunk-26P57LAR.js +1491 -0
- package/dist/{chunk-LMRYZL3D.js → chunk-5AFRMOPX.js} +1 -1
- package/dist/{chunk-RO3F6JYV.js → chunk-5GYQ4J3D.js} +2 -2
- package/dist/chunk-5HRR4AOR.js +264 -0
- package/dist/{chunk-3EEFL6NJ.js → chunk-67VNLLBN.js} +261 -1
- package/dist/{chunk-UZPBB7V4.js → chunk-ADUTW66W.js} +60 -48
- package/dist/{chunk-LEMX3IOG.js → chunk-BTNNEH2W.js} +1 -1
- package/dist/{chunk-YWO7O6QG.js → chunk-FBAYCS3X.js} +2 -2
- package/dist/{chunk-R26A7TWY.js → chunk-FKXFUUWJ.js} +1 -1
- package/dist/chunk-H4UNYFUC.js +196 -0
- package/dist/{chunk-CUE2LKLR.js → chunk-KFXF2V5G.js} +1 -1
- package/dist/{chunk-6IWNH776.js → chunk-LFFLHSQO.js} +4 -3
- package/dist/{chunk-C7T7B45R.js → chunk-LGGMJYY4.js} +150 -21
- package/dist/{chunk-MAZWKJGL.js → chunk-M6RIJVRE.js} +42 -232
- package/dist/{chunk-2JRX7ZR4.js → chunk-NAHHFSLH.js} +16 -5
- package/dist/{chunk-FI3LIRCB.js → chunk-OAAP2MY6.js} +2 -2
- package/dist/{chunk-Z7YPFWAZ.js → chunk-PCVGBE5B.js} +10 -268
- package/dist/chunk-WX52U7Z2.js +112 -0
- package/dist/{chunk-PPQYQEIR.js → chunk-ZB4F75SZ.js} +28 -0
- package/dist/daemon/server.js +30 -21
- package/dist/hook-runtime/daemon/server.js +30 -21
- package/dist/hook-runtime/hooks/post-commit.js +20 -20
- package/dist/hook-runtime/hooks/post-rewrite.js +20 -20
- package/dist/hook-runtime/hooks/post-tool-use.js +666 -147
- package/dist/hook-runtime/hooks/pre-tool-use.js +659 -111
- package/dist/hook-runtime/hooks/prim-hook.js +627 -111
- package/dist/hook-runtime/hooks/session-end.js +610 -27
- package/dist/hook-runtime/hooks/session-start.js +1132 -533
- package/dist/hook-runtime/index.js +764 -267
- package/dist/hook-runtime/statusline-main.js +48 -4
- package/dist/hooks/post-commit.js +11 -9
- package/dist/hooks/post-rewrite.js +11 -9
- package/dist/hooks/post-tool-use.js +73 -48
- package/dist/hooks/pre-commit.js +4 -4
- package/dist/hooks/pre-tool-use.js +46 -44
- package/dist/hooks/prim-hook.js +47 -25
- package/dist/hooks/session-end.js +15 -26
- package/dist/hooks/session-start.js +59 -32
- package/dist/index.js +561 -1430
- package/dist/statusline-main.js +48 -4
- package/package.json +1 -1
- package/dist/chunk-PMRDE2DA.js +0 -310
- package/dist/chunk-WB7AUZ4C.js +0 -52
|
@@ -179,6 +179,7 @@ function compareSemver(left, right) {
|
|
|
179
179
|
// src/lib/bin-path.ts
|
|
180
180
|
var PKG_NAME = "@primitive.ai/prim";
|
|
181
181
|
var ROOT_WALK_LIMIT = 6;
|
|
182
|
+
var STABLE_HOOK_LAUNCHER_NAME = "prim-hook-launcher-v1";
|
|
182
183
|
var resolvedRoot;
|
|
183
184
|
function locateRoot() {
|
|
184
185
|
if (resolvedRoot !== void 0) {
|
|
@@ -239,6 +240,31 @@ function pinnedNpxArgs(bin, args = [], options = {}) {
|
|
|
239
240
|
function pinnedNpxCommand(bin, args = [], options = {}) {
|
|
240
241
|
return ["npx", ...pinnedNpxArgs(bin, args, options)].map(shellWord).join(" ");
|
|
241
242
|
}
|
|
243
|
+
var STABLE_HOOK_ARGUMENTS_RE = /^[-A-Za-z0-9_ ]*$/u;
|
|
244
|
+
var STABLE_HOOK_BIN_RE = /^[A-Za-z0-9][A-Za-z0-9-]*$/u;
|
|
245
|
+
function stableHookCommand(bin, args = "") {
|
|
246
|
+
if (!STABLE_HOOK_BIN_RE.test(bin) || !STABLE_HOOK_ARGUMENTS_RE.test(args)) {
|
|
247
|
+
throw new Error("invalid stable hook command");
|
|
248
|
+
}
|
|
249
|
+
const resolver = [
|
|
250
|
+
// #242 and earlier identify managed commands by this package marker. Keep
|
|
251
|
+
// it as inert data during the rolling window so an older uninstall or
|
|
252
|
+
// reinstall can remove the stable entry without invoking npm or PATH.
|
|
253
|
+
`prim_legacy_reader='-p ${PKG_NAME}@stable prim-shim.sh ${bin} '; `,
|
|
254
|
+
'prim_absolute() { case "$1" in [/]* ) ;; *) return 1 ;; esac; case "$1" in [[:space:]]*|*[[:space:]]|*[/][/]*|*[/].[/]*|*[/]..[/]*|*[/].|*[/]..|?*[/]) return 1 ;; esac; }; ',
|
|
255
|
+
'prim_config=${PRIM_CONFIG_DIR:-}; if ! prim_absolute "$prim_config"; then prim_config=${XDG_CONFIG_HOME:-}; if prim_absolute "$prim_config"; then ',
|
|
256
|
+
'case "$prim_config" in /) prim_config=/prim ;; *) prim_config="$prim_config/prim" ;; esac; ',
|
|
257
|
+
'else prim_home=${HOME:-}; prim_absolute "$prim_home" || exit 78; case "$prim_home" in /) prim_config=/.config/prim ;; *) prim_config="$prim_home/.config/prim" ;; esac; ',
|
|
258
|
+
"fi; fi; ",
|
|
259
|
+
`case "$prim_config" in /) prim_launcher=/${STABLE_HOOK_LAUNCHER_NAME} ;; *) prim_launcher="$prim_config/${STABLE_HOOK_LAUNCHER_NAME}" ;; esac; `,
|
|
260
|
+
'exec "$prim_launcher" "$@"'
|
|
261
|
+
].join("");
|
|
262
|
+
const suffix = args ? ` ${args}` : "";
|
|
263
|
+
return `/bin/sh -c ${shellQuote(resolver)} ${STABLE_HOOK_LAUNCHER_NAME} ${bin}${suffix}`;
|
|
264
|
+
}
|
|
265
|
+
function detachedHookShimCommand(bin, args = "") {
|
|
266
|
+
return `payload=$(cat); { trap '' HUP; printf '%s' "$payload" | { ${stableHookCommand(bin, args)}; }; } </dev/null >/dev/null 2>&1 &`;
|
|
267
|
+
}
|
|
242
268
|
|
|
243
269
|
// src/lib/bin-cache.ts
|
|
244
270
|
var GIT_HOOK_CACHE_SHELL_DIR = "${XDG_CACHE_HOME:-$HOME/.cache}/prim/bin";
|
|
@@ -274,12 +300,574 @@ function warmBinCache() {
|
|
|
274
300
|
function parseAgent(argv) {
|
|
275
301
|
const i = argv.indexOf("--agent");
|
|
276
302
|
const value = i !== -1 ? argv[i + 1] : void 0;
|
|
277
|
-
if (value === "codex" || value === "hermes") {
|
|
303
|
+
if (value === "codex" || value === "cursor" || value === "hermes") {
|
|
278
304
|
return value;
|
|
279
305
|
}
|
|
280
306
|
return "claude_code";
|
|
281
307
|
}
|
|
282
308
|
|
|
309
|
+
// src/commands/cursor-install.ts
|
|
310
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
|
|
311
|
+
import { homedir as homedir4 } from "os";
|
|
312
|
+
import { isAbsolute as isAbsolute5, join as join7 } from "path";
|
|
313
|
+
|
|
314
|
+
// src/lib/hook-runtime.ts
|
|
315
|
+
import { createHash, randomBytes as randomBytes2 } from "crypto";
|
|
316
|
+
import {
|
|
317
|
+
constants as constants2,
|
|
318
|
+
accessSync,
|
|
319
|
+
chmodSync as chmodSync2,
|
|
320
|
+
copyFileSync,
|
|
321
|
+
existsSync as existsSync3,
|
|
322
|
+
lstatSync,
|
|
323
|
+
mkdirSync as mkdirSync4,
|
|
324
|
+
mkdtempSync,
|
|
325
|
+
readFileSync as readFileSync3,
|
|
326
|
+
readdirSync,
|
|
327
|
+
realpathSync,
|
|
328
|
+
renameSync as renameSync2,
|
|
329
|
+
rmSync as rmSync3,
|
|
330
|
+
statSync as statSync2,
|
|
331
|
+
utimesSync,
|
|
332
|
+
writeFileSync as writeFileSync3
|
|
333
|
+
} from "fs";
|
|
334
|
+
import { delimiter, dirname as dirname4, isAbsolute as isAbsolute3, join as join5, resolve } from "path";
|
|
335
|
+
|
|
336
|
+
// src/lib/file-lock.ts
|
|
337
|
+
import { randomBytes } from "crypto";
|
|
338
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync2, rmSync as rmSync2, statSync, writeFileSync as writeFileSync2 } from "fs";
|
|
339
|
+
import { dirname as dirname3, join as join3 } from "path";
|
|
340
|
+
|
|
341
|
+
// src/lib/process-liveness.ts
|
|
342
|
+
function processIsAlive(pid, probe = process.kill) {
|
|
343
|
+
if (!Number.isSafeInteger(pid) || pid <= 0) return false;
|
|
344
|
+
try {
|
|
345
|
+
probe(pid, 0);
|
|
346
|
+
return true;
|
|
347
|
+
} catch (error) {
|
|
348
|
+
return error.code === "EPERM";
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// src/lib/file-lock.ts
|
|
353
|
+
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
354
|
+
var DEFAULT_POLL_MS = 50;
|
|
355
|
+
var DEFAULT_INIT_GRACE_MS = 2e3;
|
|
356
|
+
var DIRECTORY_MODE = 448;
|
|
357
|
+
var FILE_MODE = 384;
|
|
358
|
+
function ownerPath(lockDir) {
|
|
359
|
+
return join3(lockDir, "owner.json");
|
|
360
|
+
}
|
|
361
|
+
function readOwner(lockDir) {
|
|
362
|
+
try {
|
|
363
|
+
const owner = JSON.parse(readFileSync2(ownerPath(lockDir), "utf8"));
|
|
364
|
+
if (!Number.isInteger(owner.pid) || owner.pid <= 0 || typeof owner.nonce !== "string" || typeof owner.createdAt !== "number") {
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
367
|
+
return owner;
|
|
368
|
+
} catch {
|
|
369
|
+
return null;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
function sameOwner(a, b) {
|
|
373
|
+
return a?.pid === b.pid && a.nonce === b.nonce && a.createdAt === b.createdAt;
|
|
374
|
+
}
|
|
375
|
+
function tryTakeLock(lockDir, now) {
|
|
376
|
+
try {
|
|
377
|
+
mkdirSync3(lockDir, { mode: DIRECTORY_MODE });
|
|
378
|
+
} catch (error) {
|
|
379
|
+
if (error.code === "EEXIST") return null;
|
|
380
|
+
throw error;
|
|
381
|
+
}
|
|
382
|
+
const owner = {
|
|
383
|
+
pid: process.pid,
|
|
384
|
+
nonce: randomBytes(16).toString("hex"),
|
|
385
|
+
createdAt: now
|
|
386
|
+
};
|
|
387
|
+
try {
|
|
388
|
+
writeFileSync2(ownerPath(lockDir), `${JSON.stringify(owner)}
|
|
389
|
+
`, {
|
|
390
|
+
encoding: "utf8",
|
|
391
|
+
mode: FILE_MODE,
|
|
392
|
+
flag: "wx"
|
|
393
|
+
});
|
|
394
|
+
return owner;
|
|
395
|
+
} catch (error) {
|
|
396
|
+
rmSync2(lockDir, { recursive: true, force: true });
|
|
397
|
+
throw error;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
function recoverStaleLock(lockDir, now, alive, initGraceMs) {
|
|
401
|
+
const owner = readOwner(lockDir);
|
|
402
|
+
if (owner) {
|
|
403
|
+
if (alive(owner.pid)) return false;
|
|
404
|
+
if (!sameOwner(readOwner(lockDir), owner)) return false;
|
|
405
|
+
rmSync2(lockDir, { recursive: true, force: true });
|
|
406
|
+
return true;
|
|
407
|
+
}
|
|
408
|
+
try {
|
|
409
|
+
const before = statSync(lockDir).mtimeMs;
|
|
410
|
+
if (now - before < initGraceMs) return false;
|
|
411
|
+
if (readOwner(lockDir)) return false;
|
|
412
|
+
if (statSync(lockDir).mtimeMs !== before) return false;
|
|
413
|
+
rmSync2(lockDir, { recursive: true, force: true });
|
|
414
|
+
return true;
|
|
415
|
+
} catch {
|
|
416
|
+
return true;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
function abortError(signal) {
|
|
420
|
+
if (signal.reason instanceof Error) return signal.reason;
|
|
421
|
+
const error = new Error("The operation was aborted");
|
|
422
|
+
error.name = "AbortError";
|
|
423
|
+
return error;
|
|
424
|
+
}
|
|
425
|
+
function throwIfAborted(signal) {
|
|
426
|
+
if (signal?.aborted) throw abortError(signal);
|
|
427
|
+
}
|
|
428
|
+
async function defaultSleep(ms, signal) {
|
|
429
|
+
if (!signal) {
|
|
430
|
+
await new Promise((resolve9) => setTimeout(resolve9, ms));
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
throwIfAborted(signal);
|
|
434
|
+
await new Promise((resolve9, reject) => {
|
|
435
|
+
const timer = setTimeout(() => {
|
|
436
|
+
signal.removeEventListener("abort", onAbort);
|
|
437
|
+
resolve9();
|
|
438
|
+
}, ms);
|
|
439
|
+
const onAbort = () => {
|
|
440
|
+
clearTimeout(timer);
|
|
441
|
+
reject(abortError(signal));
|
|
442
|
+
};
|
|
443
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
var syncSleeper = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT));
|
|
447
|
+
async function withFileLock(lockDir, operation, options = {}) {
|
|
448
|
+
mkdirSync3(dirname3(lockDir), { recursive: true, mode: DIRECTORY_MODE });
|
|
449
|
+
const nowMs = options.nowMs ?? Date.now;
|
|
450
|
+
const alive = options.processAlive ?? processIsAlive;
|
|
451
|
+
const deadline = nowMs() + (options.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
452
|
+
let owner = null;
|
|
453
|
+
while (!owner) {
|
|
454
|
+
throwIfAborted(options.signal);
|
|
455
|
+
const now = nowMs();
|
|
456
|
+
owner = tryTakeLock(lockDir, now);
|
|
457
|
+
if (owner) break;
|
|
458
|
+
recoverStaleLock(lockDir, now, alive, options.initGraceMs ?? DEFAULT_INIT_GRACE_MS);
|
|
459
|
+
if (now >= deadline) {
|
|
460
|
+
throw new Error(`timed out waiting for file lock ${lockDir}`);
|
|
461
|
+
}
|
|
462
|
+
if (options.sleep) {
|
|
463
|
+
await options.sleep(options.pollMs ?? DEFAULT_POLL_MS);
|
|
464
|
+
throwIfAborted(options.signal);
|
|
465
|
+
} else {
|
|
466
|
+
await defaultSleep(options.pollMs ?? DEFAULT_POLL_MS, options.signal);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
try {
|
|
470
|
+
throwIfAborted(options.signal);
|
|
471
|
+
return await operation();
|
|
472
|
+
} finally {
|
|
473
|
+
if (sameOwner(readOwner(lockDir), owner)) {
|
|
474
|
+
rmSync2(lockDir, { recursive: true, force: true });
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// src/lib/paths.ts
|
|
480
|
+
import { homedir as homedir2 } from "os";
|
|
481
|
+
import { isAbsolute as isAbsolute2, join as join4, normalize } from "path";
|
|
482
|
+
var UNSAFE_CONFIG_PATH_CHARACTERS = /[\p{Cc}\p{Cf}\p{Zl}\p{Zp}]/u;
|
|
483
|
+
function absolutePath(value, variable) {
|
|
484
|
+
if (value !== void 0 && UNSAFE_CONFIG_PATH_CHARACTERS.test(value)) {
|
|
485
|
+
throw new Error(`${variable} contains unsafe characters`);
|
|
486
|
+
}
|
|
487
|
+
if (!value || value.trim() !== value || !isAbsolute2(value)) return;
|
|
488
|
+
const normalized = normalize(value);
|
|
489
|
+
return normalized === value ? value : void 0;
|
|
490
|
+
}
|
|
491
|
+
function resolvePrimConfigDirectory(options = {}) {
|
|
492
|
+
const env = options.env ?? process.env;
|
|
493
|
+
const explicit = absolutePath(env.PRIM_CONFIG_DIR, "PRIM_CONFIG_DIR");
|
|
494
|
+
if (explicit) return { path: explicit, source: "explicit" };
|
|
495
|
+
const xdgConfigHome = absolutePath(env.XDG_CONFIG_HOME, "XDG_CONFIG_HOME");
|
|
496
|
+
if (xdgConfigHome) return { path: join4(xdgConfigHome, "prim"), source: "xdg" };
|
|
497
|
+
const home = absolutePath(options.homeDir ?? homedir2(), "HOME");
|
|
498
|
+
if (!home) {
|
|
499
|
+
throw new Error("cannot resolve Primitive config directory: HOME is not an absolute path");
|
|
500
|
+
}
|
|
501
|
+
return { path: join4(home, ".config", "prim"), source: "default" };
|
|
502
|
+
}
|
|
503
|
+
function primConfigDirectory(options = {}) {
|
|
504
|
+
return resolvePrimConfigDirectory(options).path;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// src/lib/hook-runtime.ts
|
|
508
|
+
var RELEASE_PREFIX = "release-";
|
|
509
|
+
var MAX_MANIFEST_BYTES = 64 * 1024;
|
|
510
|
+
var RELEASE_GRACE_MS = 10 * 60 * 1e3;
|
|
511
|
+
var HOOK_RUNTIME_ENTRIES = {
|
|
512
|
+
// SessionStart self-healing resolves this exact CLI entry to run
|
|
513
|
+
// `daemon ensure`; it must travel with the immutable hook release.
|
|
514
|
+
prim: "dist/index.js",
|
|
515
|
+
"prim-hook": "dist/hooks/prim-hook.js",
|
|
516
|
+
"prim-pre-commit": "dist/hooks/pre-commit.js",
|
|
517
|
+
"prim-post-commit": "dist/hooks/post-commit.js",
|
|
518
|
+
"prim-post-rewrite": "dist/hooks/post-rewrite.js",
|
|
519
|
+
"prim-pre-tool-use": "dist/hooks/pre-tool-use.js",
|
|
520
|
+
"prim-post-tool-use": "dist/hooks/post-tool-use.js",
|
|
521
|
+
"prim-session-start": "dist/hooks/session-start.js",
|
|
522
|
+
"prim-session-end": "dist/hooks/session-end.js",
|
|
523
|
+
"prim-daemon-server": "dist/daemon/server.js",
|
|
524
|
+
"prim-statusline": "dist/statusline-main.js"
|
|
525
|
+
};
|
|
526
|
+
var SOURCE_ENTRIES = Object.fromEntries(
|
|
527
|
+
Object.entries(HOOK_RUNTIME_ENTRIES).map(([bin, target]) => [
|
|
528
|
+
bin,
|
|
529
|
+
target.replace(/^dist\//u, "")
|
|
530
|
+
])
|
|
531
|
+
);
|
|
532
|
+
var STABLE_HOOK_LAUNCHER_CONTENT = `#!/bin/sh
|
|
533
|
+
set -eu
|
|
534
|
+
case "$0" in */*) prim_launcher_dir=\${0%/*} ;; *) exit 78 ;; esac
|
|
535
|
+
IFS= read -r prim_release_name < "$prim_launcher_dir/hook-runtime/current" || exit 69
|
|
536
|
+
case "$prim_release_name" in ${RELEASE_PREFIX}*) ;; *) exit 69 ;; esac
|
|
537
|
+
prim_release_id=\${prim_release_name#${RELEASE_PREFIX}}
|
|
538
|
+
case "$prim_release_id" in *[!0-9a-f]*|"") exit 69 ;; esac
|
|
539
|
+
[ "\${#prim_release_id}" -eq 64 ] || exit 69
|
|
540
|
+
prim_release="$prim_launcher_dir/hook-runtime/releases/$prim_release_name"
|
|
541
|
+
case "\${1-}" in
|
|
542
|
+
${Object.entries(HOOK_RUNTIME_ENTRIES).map(([bin, entry]) => ` ${bin}) prim_entry="$prim_release/${entry}" ;;`).join("\n")}
|
|
543
|
+
*) exit 64 ;;
|
|
544
|
+
esac
|
|
545
|
+
shift
|
|
546
|
+
IFS= read -r prim_node < "$prim_release/node" || exit 69
|
|
547
|
+
case "$prim_node" in /*) ;; *) exit 69 ;; esac
|
|
548
|
+
[ -x "$prim_node" ] && [ -f "$prim_entry" ] || exit 69
|
|
549
|
+
exec "$prim_node" "$prim_entry" "$@"
|
|
550
|
+
`;
|
|
551
|
+
|
|
552
|
+
// src/commands/claude-install.ts
|
|
553
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
|
|
554
|
+
import { homedir as homedir3 } from "os";
|
|
555
|
+
import { join as join6 } from "path";
|
|
556
|
+
|
|
557
|
+
// src/lib/git.ts
|
|
558
|
+
import { execFileSync } from "child_process";
|
|
559
|
+
import { createHash as createHash2 } from "crypto";
|
|
560
|
+
import { lstatSync as lstatSync2, realpathSync as realpathSync2 } from "fs";
|
|
561
|
+
import { basename, dirname as dirname5, isAbsolute as isAbsolute4, relative, resolve as resolve2, sep } from "path";
|
|
562
|
+
var GIT_TIMEOUT_MS = 1e3;
|
|
563
|
+
var GITHUB_OWNER_PATTERN = /^(?![A-Za-z0-9-]*--)[A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?$/u;
|
|
564
|
+
var GITHUB_REPOSITORY_PATTERN = /^[A-Za-z0-9._-]{1,100}$/u;
|
|
565
|
+
function gitToplevel(cwd) {
|
|
566
|
+
try {
|
|
567
|
+
return execFileSync("git", ["rev-parse", "--show-toplevel"], {
|
|
568
|
+
cwd,
|
|
569
|
+
encoding: "utf-8",
|
|
570
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
571
|
+
timeout: GIT_TIMEOUT_MS
|
|
572
|
+
}).trim();
|
|
573
|
+
} catch {
|
|
574
|
+
return null;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
function gitValue(cwd, args) {
|
|
578
|
+
try {
|
|
579
|
+
const value = execFileSync("git", args, {
|
|
580
|
+
cwd,
|
|
581
|
+
encoding: "utf-8",
|
|
582
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
583
|
+
timeout: GIT_TIMEOUT_MS
|
|
584
|
+
}).trim();
|
|
585
|
+
return value || void 0;
|
|
586
|
+
} catch {
|
|
587
|
+
return void 0;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
function githubRepositoryFullName(cwd) {
|
|
591
|
+
const remote = gitValue(cwd, ["config", "--get", "remote.origin.url"]);
|
|
592
|
+
if (!remote || [...remote].some((char) => char < " " || char === "\x7F")) return null;
|
|
593
|
+
const match = /^(?:git@github\.com:([^?#]+)|(?:https|ssh):\/\/(?:[^/@]+@)?github\.com(?::\d+)?\/([^?#]+))$/i.exec(
|
|
594
|
+
remote
|
|
595
|
+
);
|
|
596
|
+
const path = match?.[1] ?? match?.[2];
|
|
597
|
+
if (!path) return null;
|
|
598
|
+
const parts = path.replace(/^\/+|\/+$/g, "").replace(/\.git$/i, "").split("/");
|
|
599
|
+
if (parts.length !== 2 || !GITHUB_OWNER_PATTERN.test(parts[0] ?? "") || !GITHUB_REPOSITORY_PATTERN.test(parts[1] ?? "")) {
|
|
600
|
+
return null;
|
|
601
|
+
}
|
|
602
|
+
return `${parts[0]}/${parts[1]}`;
|
|
603
|
+
}
|
|
604
|
+
function normalizeOriginRemote(remote) {
|
|
605
|
+
const value = remote.trim();
|
|
606
|
+
if (!value) return void 0;
|
|
607
|
+
const scp = !value.includes("://") ? /^(?:[^@/\s]+@)?(?<host>[^:/\s]+):(?<path>.+)$/.exec(value)?.groups : void 0;
|
|
608
|
+
if (scp?.host && scp.path) {
|
|
609
|
+
const path = scp.path.replace(/^\/+|\/+$/g, "").replace(/\.git$/i, "");
|
|
610
|
+
return path ? `${scp.host.toLowerCase()}/${path}` : void 0;
|
|
611
|
+
}
|
|
612
|
+
try {
|
|
613
|
+
const url = new URL(value);
|
|
614
|
+
url.username = "";
|
|
615
|
+
url.password = "";
|
|
616
|
+
url.search = "";
|
|
617
|
+
url.hash = "";
|
|
618
|
+
const path = url.pathname.replace(/^\/+|\/+$/g, "").replace(/\.git$/i, "");
|
|
619
|
+
if (url.host && path) return `${url.host.toLowerCase()}/${path}`;
|
|
620
|
+
return void 0;
|
|
621
|
+
} catch {
|
|
622
|
+
return void 0;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
function opaqueRepoKey(source, value) {
|
|
626
|
+
return `repo_v1_${createHash2("sha256").update(`${source}\0${value}`).digest("hex")}`;
|
|
627
|
+
}
|
|
628
|
+
function resolveRepositoryContext(cwd = process.cwd()) {
|
|
629
|
+
const top = gitToplevel(cwd);
|
|
630
|
+
if (!top) return null;
|
|
631
|
+
let repoRoot;
|
|
632
|
+
try {
|
|
633
|
+
repoRoot = realpathSync2.native(top);
|
|
634
|
+
} catch {
|
|
635
|
+
repoRoot = resolve2(top);
|
|
636
|
+
}
|
|
637
|
+
const origin = gitValue(repoRoot, ["config", "--get", "remote.origin.url"]);
|
|
638
|
+
const repoFullName = githubRepositoryFullName(repoRoot) ?? void 0;
|
|
639
|
+
const normalizedOrigin = origin ? normalizeOriginRemote(origin) : void 0;
|
|
640
|
+
if (normalizedOrigin) {
|
|
641
|
+
return {
|
|
642
|
+
repoRoot,
|
|
643
|
+
repoKey: opaqueRepoKey("origin", normalizedOrigin),
|
|
644
|
+
identitySource: "origin",
|
|
645
|
+
repoFullName
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
const roots = gitValue(repoRoot, ["rev-list", "--max-parents=0", "HEAD"])?.split(/\s+/).filter(Boolean).sort();
|
|
649
|
+
if (roots && roots.length > 0) {
|
|
650
|
+
return {
|
|
651
|
+
repoRoot,
|
|
652
|
+
repoKey: opaqueRepoKey("root_commit", roots.join("\n")),
|
|
653
|
+
identitySource: "root_commit",
|
|
654
|
+
repoFullName
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
return { repoRoot, repoFullName };
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// src/commands/claude-install.ts
|
|
661
|
+
var CAPTURE_BIN = "prim-hook";
|
|
662
|
+
var GATE_BIN = "prim-pre-tool-use";
|
|
663
|
+
var POST_TOOL_USE_BIN = "prim-post-tool-use";
|
|
664
|
+
var SESSION_START_BIN = "prim-session-start";
|
|
665
|
+
var SESSION_END_BIN = "prim-session-end";
|
|
666
|
+
var STATUSLINE_BIN = "prim-statusline";
|
|
667
|
+
var STATUSLINE_ARGS = "";
|
|
668
|
+
var STATUSLINE_COMMAND = stableHookCommand(STATUSLINE_BIN, STATUSLINE_ARGS);
|
|
669
|
+
var USER_SCOPE_PATH = join6(homedir3(), ".claude", "settings.json");
|
|
670
|
+
function projectRoot() {
|
|
671
|
+
return gitToplevel() ?? process.cwd();
|
|
672
|
+
}
|
|
673
|
+
var CAPTURE_EVENTS = [
|
|
674
|
+
"SessionStart",
|
|
675
|
+
"UserPromptSubmit",
|
|
676
|
+
"PreToolUse",
|
|
677
|
+
"PostToolUse",
|
|
678
|
+
"PostToolUseFailure",
|
|
679
|
+
"Stop",
|
|
680
|
+
"SessionEnd",
|
|
681
|
+
"SubagentStop"
|
|
682
|
+
];
|
|
683
|
+
function makeRegistration(event, matcher, bin, args = "") {
|
|
684
|
+
return {
|
|
685
|
+
event,
|
|
686
|
+
matcher,
|
|
687
|
+
bin,
|
|
688
|
+
command: stableHookCommand(bin, args)
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
function makeDetachedRegistration(event, matcher, bin, args = "") {
|
|
692
|
+
return { event, matcher, bin, command: detachedHookShimCommand(bin, args) };
|
|
693
|
+
}
|
|
694
|
+
var REGISTRATIONS = [
|
|
695
|
+
...CAPTURE_EVENTS.map(
|
|
696
|
+
(event) => event === "SessionEnd" ? makeDetachedRegistration(event, "*", CAPTURE_BIN) : makeRegistration(event, "*", CAPTURE_BIN)
|
|
697
|
+
),
|
|
698
|
+
makeRegistration("PreToolUse", "Edit|Write|MultiEdit|NotebookEdit|Bash", GATE_BIN),
|
|
699
|
+
makeRegistration("PostToolUse", "Edit|Write|MultiEdit|NotebookEdit|Bash", POST_TOOL_USE_BIN),
|
|
700
|
+
makeRegistration(
|
|
701
|
+
"PostToolUseFailure",
|
|
702
|
+
"Edit|Write|MultiEdit|NotebookEdit|Bash",
|
|
703
|
+
POST_TOOL_USE_BIN
|
|
704
|
+
),
|
|
705
|
+
makeRegistration("SessionStart", "*", SESSION_START_BIN),
|
|
706
|
+
makeDetachedRegistration("SessionEnd", "*", SESSION_END_BIN)
|
|
707
|
+
];
|
|
708
|
+
var PRIM_PERMISSION_RULE = "Bash(npx --yes @primitive.ai/prim*)";
|
|
709
|
+
var LEGACY_PRIM_PERMISSION_RULES = [
|
|
710
|
+
"Bash(npx --yes @primitive.ai/prim@latest:*)",
|
|
711
|
+
"Bash(npx --yes @primitive.ai/prim:*)"
|
|
712
|
+
];
|
|
713
|
+
var ALL_PRIM_PERMISSION_RULES = /* @__PURE__ */ new Set([
|
|
714
|
+
PRIM_PERMISSION_RULE,
|
|
715
|
+
...LEGACY_PRIM_PERMISSION_RULES
|
|
716
|
+
]);
|
|
717
|
+
|
|
718
|
+
// src/commands/cursor-install.ts
|
|
719
|
+
var CAPTURE_BIN2 = "prim-hook";
|
|
720
|
+
var GATE_BIN2 = "prim-pre-tool-use";
|
|
721
|
+
var POST_TOOL_BIN = "prim-post-tool-use";
|
|
722
|
+
var SESSION_START_BIN2 = "prim-session-start";
|
|
723
|
+
var SESSION_END_BIN2 = "prim-session-end";
|
|
724
|
+
var STATUSLINE_BIN2 = "prim-statusline";
|
|
725
|
+
var CURSOR_EVENTS = [
|
|
726
|
+
"sessionStart",
|
|
727
|
+
"beforeSubmitPrompt",
|
|
728
|
+
"preToolUse",
|
|
729
|
+
"postToolUse",
|
|
730
|
+
"postToolUseFailure",
|
|
731
|
+
"afterAgentResponse",
|
|
732
|
+
"subagentStop",
|
|
733
|
+
"stop",
|
|
734
|
+
"sessionEnd"
|
|
735
|
+
];
|
|
736
|
+
var REGISTRATIONS2 = [
|
|
737
|
+
...CURSOR_EVENTS.map((event) => ({ event, bin: CAPTURE_BIN2 })),
|
|
738
|
+
{ event: "preToolUse", bin: GATE_BIN2, matcher: "Write|Delete|Shell", timeout: 10 },
|
|
739
|
+
{ event: "postToolUse", bin: POST_TOOL_BIN },
|
|
740
|
+
{ event: "postToolUseFailure", bin: POST_TOOL_BIN },
|
|
741
|
+
{ event: "sessionStart", bin: SESSION_START_BIN2 },
|
|
742
|
+
{ event: "sessionEnd", bin: SESSION_END_BIN2 }
|
|
743
|
+
];
|
|
744
|
+
function cursorConfigDirectory(env = process.env, home = homedir4(), platform = process.platform) {
|
|
745
|
+
const explicit = env.CURSOR_CONFIG_DIR?.trim();
|
|
746
|
+
if (explicit && isAbsolute5(explicit)) return explicit;
|
|
747
|
+
const xdg = env.XDG_CONFIG_HOME?.trim();
|
|
748
|
+
if (platform !== "darwin" && xdg && isAbsolute5(xdg)) return join7(xdg, "cursor");
|
|
749
|
+
return join7(home, ".cursor");
|
|
750
|
+
}
|
|
751
|
+
function cursorHooksPath(scope, root = projectRoot()) {
|
|
752
|
+
return scope === "user" ? join7(cursorConfigDirectory(), "hooks.json") : join7(root, ".cursor", "hooks.json");
|
|
753
|
+
}
|
|
754
|
+
function plainObject(value) {
|
|
755
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
756
|
+
}
|
|
757
|
+
function readCursorHooks(path) {
|
|
758
|
+
if (!existsSync5(path)) return {};
|
|
759
|
+
let parsed;
|
|
760
|
+
try {
|
|
761
|
+
parsed = JSON.parse(readFileSync5(path, "utf8"));
|
|
762
|
+
} catch {
|
|
763
|
+
throw new Error(`invalid Cursor hooks JSON at ${path}`);
|
|
764
|
+
}
|
|
765
|
+
if (!plainObject(parsed)) throw new Error(`Cursor hooks config must be an object: ${path}`);
|
|
766
|
+
if (parsed.version !== void 0 && parsed.version !== 1) {
|
|
767
|
+
throw new Error(`unsupported Cursor hooks version at ${path} (expected version 1)`);
|
|
768
|
+
}
|
|
769
|
+
if (parsed.hooks !== void 0) {
|
|
770
|
+
if (!plainObject(parsed.hooks)) throw new Error(`Cursor hooks must be an object: ${path}`);
|
|
771
|
+
for (const [event, entries] of Object.entries(parsed.hooks)) {
|
|
772
|
+
if (!Array.isArray(entries) || !entries.every(plainObject)) {
|
|
773
|
+
throw new Error(`Cursor hook list must contain objects: ${event} in ${path}`);
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
return parsed;
|
|
778
|
+
}
|
|
779
|
+
function commandFor(registration, scope) {
|
|
780
|
+
return stableHookCommand(
|
|
781
|
+
registration.bin,
|
|
782
|
+
`--agent cursor --event ${registration.event} --scope ${scope}`
|
|
783
|
+
);
|
|
784
|
+
}
|
|
785
|
+
var OWNED_COMMANDS = new Set(
|
|
786
|
+
["project", "user"].flatMap(
|
|
787
|
+
(scope) => REGISTRATIONS2.map((registration) => commandFor(registration, scope))
|
|
788
|
+
)
|
|
789
|
+
);
|
|
790
|
+
function jsoncUnsafeCommand(command) {
|
|
791
|
+
return command.replace('case "$1" in [/]* ', 'case "$1" in /*').replace("*[/][/]*", "*//*").replace("*[/].[/]*", "*/./*").replace("*[/]..[/]*", "*/../*").replace("*[/].", "*/.").replace("*[/]..", "*/..").replace("?*[/]", "?*/");
|
|
792
|
+
}
|
|
793
|
+
var JSONC_UNSAFE_OWNED_COMMANDS = new Set([...OWNED_COMMANDS].map(jsoncUnsafeCommand));
|
|
794
|
+
function hookFor(registration, scope) {
|
|
795
|
+
return {
|
|
796
|
+
command: commandFor(registration, scope),
|
|
797
|
+
...registration.matcher ? { matcher: registration.matcher } : {},
|
|
798
|
+
...registration.timeout ? { timeout: registration.timeout } : {}
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
function exactHook(entry, registration, scope) {
|
|
802
|
+
return JSON.stringify(entry) === JSON.stringify(hookFor(registration, scope));
|
|
803
|
+
}
|
|
804
|
+
function hasExactCursorHandler(settings, event, bin, scope) {
|
|
805
|
+
const registration = REGISTRATIONS2.find(
|
|
806
|
+
(candidate) => candidate.event === event && candidate.bin === bin
|
|
807
|
+
);
|
|
808
|
+
return registration ? (settings.hooks?.[event] ?? []).some((entry) => exactHook(entry, registration, scope)) : false;
|
|
809
|
+
}
|
|
810
|
+
var FOOTER = {
|
|
811
|
+
type: "command",
|
|
812
|
+
command: stableHookCommand(STATUSLINE_BIN2),
|
|
813
|
+
updateIntervalMs: 1e3,
|
|
814
|
+
timeoutMs: 2e3
|
|
815
|
+
};
|
|
816
|
+
var JSONC_UNSAFE_FOOTER = {
|
|
817
|
+
...FOOTER,
|
|
818
|
+
command: jsoncUnsafeCommand(FOOTER.command)
|
|
819
|
+
};
|
|
820
|
+
|
|
821
|
+
// src/hooks/cursor-coexistence.ts
|
|
822
|
+
var CURSOR_EVENTS2 = /* @__PURE__ */ new Set([
|
|
823
|
+
"sessionStart",
|
|
824
|
+
"beforeSubmitPrompt",
|
|
825
|
+
"preToolUse",
|
|
826
|
+
"postToolUse",
|
|
827
|
+
"postToolUseFailure",
|
|
828
|
+
"afterAgentResponse",
|
|
829
|
+
"subagentStop",
|
|
830
|
+
"stop",
|
|
831
|
+
"sessionEnd"
|
|
832
|
+
]);
|
|
833
|
+
function cursorEvidence(parsed) {
|
|
834
|
+
return typeof parsed.cursor_version === "string" && parsed.cursor_version.length > 0 && typeof parsed.conversation_id === "string" && parsed.conversation_id.length > 0 && typeof parsed.generation_id === "string" && parsed.generation_id.length > 0 && Array.isArray(parsed.workspace_roots) && typeof parsed.hook_event_name === "string" && CURSOR_EVENTS2.has(parsed.hook_event_name);
|
|
835
|
+
}
|
|
836
|
+
function uniqueProjectRoot(parsed) {
|
|
837
|
+
if (!Array.isArray(parsed.workspace_roots)) return;
|
|
838
|
+
const roots = new Set(
|
|
839
|
+
parsed.workspace_roots.filter((value) => typeof value === "string" && value.length > 0).map((value) => resolveRepositoryContext(value)?.repoRoot).filter((value) => !!value)
|
|
840
|
+
);
|
|
841
|
+
return roots.size === 1 ? [...roots][0] : void 0;
|
|
842
|
+
}
|
|
843
|
+
function shouldSuppressImportedCursorHandler(parsed, bin) {
|
|
844
|
+
if (!cursorEvidence(parsed)) return false;
|
|
845
|
+
const project = uniqueProjectRoot(parsed);
|
|
846
|
+
if (project) {
|
|
847
|
+
try {
|
|
848
|
+
if (hasExactCursorHandler(
|
|
849
|
+
readCursorHooks(cursorHooksPath("project", project)),
|
|
850
|
+
parsed.hook_event_name,
|
|
851
|
+
bin,
|
|
852
|
+
"project"
|
|
853
|
+
)) {
|
|
854
|
+
return true;
|
|
855
|
+
}
|
|
856
|
+
} catch {
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
try {
|
|
860
|
+
return hasExactCursorHandler(
|
|
861
|
+
readCursorHooks(cursorHooksPath("user")),
|
|
862
|
+
parsed.hook_event_name,
|
|
863
|
+
bin,
|
|
864
|
+
"user"
|
|
865
|
+
);
|
|
866
|
+
} catch {
|
|
867
|
+
return false;
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
|
|
283
871
|
// src/hooks/decision-feedback-core.ts
|
|
284
872
|
function buildHookOutput(options) {
|
|
285
873
|
const output = {};
|
|
@@ -293,13 +881,13 @@ function buildHookOutput(options) {
|
|
|
293
881
|
return output;
|
|
294
882
|
}
|
|
295
883
|
function writeHookOutput(output, stream = process.stdout) {
|
|
296
|
-
return new Promise((
|
|
884
|
+
return new Promise((resolve9) => {
|
|
297
885
|
let settled = false;
|
|
298
886
|
const finish = (ok, retainErrorListener = false) => {
|
|
299
887
|
if (settled) return;
|
|
300
888
|
settled = true;
|
|
301
889
|
if (!retainErrorListener) stream.off("error", onError);
|
|
302
|
-
|
|
890
|
+
resolve9(ok);
|
|
303
891
|
};
|
|
304
892
|
const onError = () => {
|
|
305
893
|
if (settled) {
|
|
@@ -331,43 +919,46 @@ async function handoffHookOutput(output, acknowledge, stream = process.stdout) {
|
|
|
331
919
|
return handedOff;
|
|
332
920
|
}
|
|
333
921
|
|
|
922
|
+
// src/hooks/hook-stdin.ts
|
|
923
|
+
var DEFAULT_MAX_BYTES = 1024 * 1024;
|
|
924
|
+
function readHookStdin(timeoutMs = 1e3, maxBytes = DEFAULT_MAX_BYTES) {
|
|
925
|
+
return new Promise((resolve9, reject) => {
|
|
926
|
+
const chunks = [];
|
|
927
|
+
let bytes = 0;
|
|
928
|
+
let settled = false;
|
|
929
|
+
const finish = (error) => {
|
|
930
|
+
if (settled) return;
|
|
931
|
+
settled = true;
|
|
932
|
+
clearTimeout(timer);
|
|
933
|
+
process.stdin.removeAllListeners("data");
|
|
934
|
+
process.stdin.removeAllListeners("end");
|
|
935
|
+
process.stdin.removeAllListeners("error");
|
|
936
|
+
if (error) reject(error);
|
|
937
|
+
else resolve9(Buffer.concat(chunks, bytes).toString("utf-8"));
|
|
938
|
+
};
|
|
939
|
+
const timer = setTimeout(() => finish(new Error("stdin read timeout")), timeoutMs);
|
|
940
|
+
process.stdin.on("data", (chunk) => {
|
|
941
|
+
bytes += chunk.length;
|
|
942
|
+
if (bytes > maxBytes) {
|
|
943
|
+
finish(new Error("stdin envelope exceeds size limit"));
|
|
944
|
+
return;
|
|
945
|
+
}
|
|
946
|
+
chunks.push(chunk);
|
|
947
|
+
});
|
|
948
|
+
process.stdin.on("end", () => finish());
|
|
949
|
+
process.stdin.on("error", (error) => finish(error));
|
|
950
|
+
});
|
|
951
|
+
}
|
|
952
|
+
|
|
334
953
|
// src/client.ts
|
|
335
|
-
import { createHash as
|
|
336
|
-
import { chmodSync as
|
|
337
|
-
import { dirname as
|
|
954
|
+
import { createHash as createHash4 } from "crypto";
|
|
955
|
+
import { chmodSync as chmodSync3, existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync7, rmSync as rmSync4 } from "fs";
|
|
956
|
+
import { dirname as dirname7 } from "path";
|
|
338
957
|
|
|
339
958
|
// src/lib/credentials.ts
|
|
340
|
-
import { createHash } from "crypto";
|
|
341
|
-
import { readFileSync as
|
|
342
|
-
import { join as
|
|
343
|
-
|
|
344
|
-
// src/lib/paths.ts
|
|
345
|
-
import { homedir as homedir2 } from "os";
|
|
346
|
-
import { isAbsolute as isAbsolute2, join as join3, normalize } from "path";
|
|
347
|
-
var UNSAFE_CONFIG_PATH_CHARACTERS = /[\p{Cc}\p{Cf}\p{Zl}\p{Zp}]/u;
|
|
348
|
-
function absolutePath(value, variable) {
|
|
349
|
-
if (value !== void 0 && UNSAFE_CONFIG_PATH_CHARACTERS.test(value)) {
|
|
350
|
-
throw new Error(`${variable} contains unsafe characters`);
|
|
351
|
-
}
|
|
352
|
-
if (!value || value.trim() !== value || !isAbsolute2(value)) return;
|
|
353
|
-
const normalized = normalize(value);
|
|
354
|
-
return normalized === value ? value : void 0;
|
|
355
|
-
}
|
|
356
|
-
function resolvePrimConfigDirectory(options = {}) {
|
|
357
|
-
const env = options.env ?? process.env;
|
|
358
|
-
const explicit = absolutePath(env.PRIM_CONFIG_DIR, "PRIM_CONFIG_DIR");
|
|
359
|
-
if (explicit) return { path: explicit, source: "explicit" };
|
|
360
|
-
const xdgConfigHome = absolutePath(env.XDG_CONFIG_HOME, "XDG_CONFIG_HOME");
|
|
361
|
-
if (xdgConfigHome) return { path: join3(xdgConfigHome, "prim"), source: "xdg" };
|
|
362
|
-
const home = absolutePath(options.homeDir ?? homedir2(), "HOME");
|
|
363
|
-
if (!home) {
|
|
364
|
-
throw new Error("cannot resolve Primitive config directory: HOME is not an absolute path");
|
|
365
|
-
}
|
|
366
|
-
return { path: join3(home, ".config", "prim"), source: "default" };
|
|
367
|
-
}
|
|
368
|
-
function primConfigDirectory(options = {}) {
|
|
369
|
-
return resolvePrimConfigDirectory(options).path;
|
|
370
|
-
}
|
|
959
|
+
import { createHash as createHash3 } from "crypto";
|
|
960
|
+
import { readFileSync as readFileSync6 } from "fs";
|
|
961
|
+
import { join as join8 } from "path";
|
|
371
962
|
|
|
372
963
|
// src/lib/workos-connect.ts
|
|
373
964
|
var TOKEN_PATH = "/oauth2/token";
|
|
@@ -515,20 +1106,20 @@ function parseWorkosConnectTokens(value, options = {}) {
|
|
|
515
1106
|
|
|
516
1107
|
// src/lib/credentials.ts
|
|
517
1108
|
var CONFIG_DIRECTORY = primConfigDirectory();
|
|
518
|
-
var TOKEN_FILE_PATH =
|
|
519
|
-
var REFRESH_TOKEN_PATH =
|
|
520
|
-
var TOKEN_EXPIRES_PATH =
|
|
521
|
-
var TERMINAL_REFRESH_PATH =
|
|
522
|
-
var CREDENTIAL_METADATA_PATH =
|
|
523
|
-
var CREDENTIAL_FAMILY_PATH =
|
|
524
|
-
var CREDENTIAL_MIGRATION_PATH =
|
|
525
|
-
var CREDENTIAL_LOCK_PATH =
|
|
1109
|
+
var TOKEN_FILE_PATH = join8(CONFIG_DIRECTORY, "token");
|
|
1110
|
+
var REFRESH_TOKEN_PATH = join8(CONFIG_DIRECTORY, "refresh_token");
|
|
1111
|
+
var TOKEN_EXPIRES_PATH = join8(CONFIG_DIRECTORY, "token_expires_at");
|
|
1112
|
+
var TERMINAL_REFRESH_PATH = join8(CONFIG_DIRECTORY, "refresh_terminal");
|
|
1113
|
+
var CREDENTIAL_METADATA_PATH = join8(CONFIG_DIRECTORY, "credential_metadata.json");
|
|
1114
|
+
var CREDENTIAL_FAMILY_PATH = join8(CONFIG_DIRECTORY, "credential_family.json");
|
|
1115
|
+
var CREDENTIAL_MIGRATION_PATH = join8(CONFIG_DIRECTORY, "credential_migration.json");
|
|
1116
|
+
var CREDENTIAL_LOCK_PATH = join8(CONFIG_DIRECTORY, "credentials.lock");
|
|
526
1117
|
var MAX_CREDENTIAL_METADATA_BYTES = 4096;
|
|
527
1118
|
var CREDENTIAL_MIGRATION_VERSION = 1;
|
|
528
1119
|
var CREDENTIAL_MIGRATION_STATE = "family_bound";
|
|
529
1120
|
function readTrimmed(path) {
|
|
530
1121
|
try {
|
|
531
|
-
const value =
|
|
1122
|
+
const value = readFileSync6(path, "utf8").trim();
|
|
532
1123
|
return value || void 0;
|
|
533
1124
|
} catch {
|
|
534
1125
|
return void 0;
|
|
@@ -561,7 +1152,7 @@ function resolveAuthCredential(options = {}) {
|
|
|
561
1152
|
return { token: stored, source: "token_file" };
|
|
562
1153
|
}
|
|
563
1154
|
function credentialFingerprint(value) {
|
|
564
|
-
return
|
|
1155
|
+
return createHash3("sha256").update(value).digest("hex");
|
|
565
1156
|
}
|
|
566
1157
|
function parseLegacyBrokerCredentialMetadata(value) {
|
|
567
1158
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
@@ -581,7 +1172,7 @@ function parseLegacyBrokerCredentialMetadata(value) {
|
|
|
581
1172
|
function readBoundedCredentialJson(path) {
|
|
582
1173
|
let raw;
|
|
583
1174
|
try {
|
|
584
|
-
raw =
|
|
1175
|
+
raw = readFileSync6(path, "utf8");
|
|
585
1176
|
} catch (error) {
|
|
586
1177
|
return error.code === "ENOENT" ? void 0 : null;
|
|
587
1178
|
}
|
|
@@ -618,182 +1209,39 @@ function readCredentialMigrationState(path = CREDENTIAL_MIGRATION_PATH) {
|
|
|
618
1209
|
const parsed = readBoundedCredentialJson(path);
|
|
619
1210
|
if (parsed === void 0) return "absent";
|
|
620
1211
|
return parsed !== null && isCredentialMigrationSentinel(parsed) ? "valid" : "invalid";
|
|
621
|
-
}
|
|
622
|
-
function readStoredCredentialMetadata(metadataPath = CREDENTIAL_METADATA_PATH, familyPath = CREDENTIAL_FAMILY_PATH, migrationPath = CREDENTIAL_MIGRATION_PATH) {
|
|
623
|
-
const family = readCredentialFamily(familyPath);
|
|
624
|
-
if (family) return family;
|
|
625
|
-
const parsed = readBoundedCredentialJson(metadataPath);
|
|
626
|
-
if (parsed === void 0) {
|
|
627
|
-
return readCredentialMigrationState(migrationPath) === "absent" ? { state: "legacy_broker" } : { state: "invalid" };
|
|
628
|
-
}
|
|
629
|
-
if (parsed === null) return { state: "invalid" };
|
|
630
|
-
try {
|
|
631
|
-
return {
|
|
632
|
-
state: "workos_connect",
|
|
633
|
-
metadata: parseWorkosConnectCredentialMetadata(parsed)
|
|
634
|
-
};
|
|
635
|
-
} catch {
|
|
636
|
-
return { state: "invalid" };
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
function decodeJwtPayload(token) {
|
|
640
|
-
const parts = token.split(".");
|
|
641
|
-
if (parts.length !== 3) return void 0;
|
|
642
|
-
try {
|
|
643
|
-
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"));
|
|
644
|
-
if (payload === null || typeof payload !== "object" || Array.isArray(payload)) return void 0;
|
|
645
|
-
return payload;
|
|
646
|
-
} catch {
|
|
647
|
-
return void 0;
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
function jwtExpiresAt(token) {
|
|
651
|
-
const exp = decodeJwtPayload(token)?.exp;
|
|
652
|
-
return typeof exp === "number" && Number.isFinite(exp) ? exp * 1e3 : void 0;
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
// src/lib/file-lock.ts
|
|
656
|
-
import { randomBytes } from "crypto";
|
|
657
|
-
import { existsSync as existsSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync3, rmSync as rmSync2, statSync, writeFileSync as writeFileSync2 } from "fs";
|
|
658
|
-
import { dirname as dirname3, join as join5 } from "path";
|
|
659
|
-
|
|
660
|
-
// src/lib/process-liveness.ts
|
|
661
|
-
function processIsAlive(pid, probe = process.kill) {
|
|
662
|
-
if (!Number.isSafeInteger(pid) || pid <= 0) return false;
|
|
663
|
-
try {
|
|
664
|
-
probe(pid, 0);
|
|
665
|
-
return true;
|
|
666
|
-
} catch (error) {
|
|
667
|
-
return error.code === "EPERM";
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
// src/lib/file-lock.ts
|
|
672
|
-
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
673
|
-
var DEFAULT_POLL_MS = 50;
|
|
674
|
-
var DEFAULT_INIT_GRACE_MS = 2e3;
|
|
675
|
-
var DIRECTORY_MODE = 448;
|
|
676
|
-
var FILE_MODE = 384;
|
|
677
|
-
function ownerPath(lockDir) {
|
|
678
|
-
return join5(lockDir, "owner.json");
|
|
679
|
-
}
|
|
680
|
-
function readOwner(lockDir) {
|
|
681
|
-
try {
|
|
682
|
-
const owner = JSON.parse(readFileSync3(ownerPath(lockDir), "utf8"));
|
|
683
|
-
if (!Number.isInteger(owner.pid) || owner.pid <= 0 || typeof owner.nonce !== "string" || typeof owner.createdAt !== "number") {
|
|
684
|
-
return null;
|
|
685
|
-
}
|
|
686
|
-
return owner;
|
|
687
|
-
} catch {
|
|
688
|
-
return null;
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
function sameOwner(a, b) {
|
|
692
|
-
return a?.pid === b.pid && a.nonce === b.nonce && a.createdAt === b.createdAt;
|
|
693
|
-
}
|
|
694
|
-
function tryTakeLock(lockDir, now) {
|
|
695
|
-
try {
|
|
696
|
-
mkdirSync3(lockDir, { mode: DIRECTORY_MODE });
|
|
697
|
-
} catch (error) {
|
|
698
|
-
if (error.code === "EEXIST") return null;
|
|
699
|
-
throw error;
|
|
700
|
-
}
|
|
701
|
-
const owner = {
|
|
702
|
-
pid: process.pid,
|
|
703
|
-
nonce: randomBytes(16).toString("hex"),
|
|
704
|
-
createdAt: now
|
|
705
|
-
};
|
|
706
|
-
try {
|
|
707
|
-
writeFileSync2(ownerPath(lockDir), `${JSON.stringify(owner)}
|
|
708
|
-
`, {
|
|
709
|
-
encoding: "utf8",
|
|
710
|
-
mode: FILE_MODE,
|
|
711
|
-
flag: "wx"
|
|
712
|
-
});
|
|
713
|
-
return owner;
|
|
714
|
-
} catch (error) {
|
|
715
|
-
rmSync2(lockDir, { recursive: true, force: true });
|
|
716
|
-
throw error;
|
|
717
|
-
}
|
|
718
|
-
}
|
|
719
|
-
function recoverStaleLock(lockDir, now, alive, initGraceMs) {
|
|
720
|
-
const owner = readOwner(lockDir);
|
|
721
|
-
if (owner) {
|
|
722
|
-
if (alive(owner.pid)) return false;
|
|
723
|
-
if (!sameOwner(readOwner(lockDir), owner)) return false;
|
|
724
|
-
rmSync2(lockDir, { recursive: true, force: true });
|
|
725
|
-
return true;
|
|
726
|
-
}
|
|
727
|
-
try {
|
|
728
|
-
const before = statSync(lockDir).mtimeMs;
|
|
729
|
-
if (now - before < initGraceMs) return false;
|
|
730
|
-
if (readOwner(lockDir)) return false;
|
|
731
|
-
if (statSync(lockDir).mtimeMs !== before) return false;
|
|
732
|
-
rmSync2(lockDir, { recursive: true, force: true });
|
|
733
|
-
return true;
|
|
734
|
-
} catch {
|
|
735
|
-
return true;
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
|
-
function abortError(signal) {
|
|
739
|
-
if (signal.reason instanceof Error) return signal.reason;
|
|
740
|
-
const error = new Error("The operation was aborted");
|
|
741
|
-
error.name = "AbortError";
|
|
742
|
-
return error;
|
|
743
|
-
}
|
|
744
|
-
function throwIfAborted(signal) {
|
|
745
|
-
if (signal?.aborted) throw abortError(signal);
|
|
746
|
-
}
|
|
747
|
-
async function defaultSleep(ms, signal) {
|
|
748
|
-
if (!signal) {
|
|
749
|
-
await new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
750
|
-
return;
|
|
1212
|
+
}
|
|
1213
|
+
function readStoredCredentialMetadata(metadataPath = CREDENTIAL_METADATA_PATH, familyPath = CREDENTIAL_FAMILY_PATH, migrationPath = CREDENTIAL_MIGRATION_PATH) {
|
|
1214
|
+
const family = readCredentialFamily(familyPath);
|
|
1215
|
+
if (family) return family;
|
|
1216
|
+
const parsed = readBoundedCredentialJson(metadataPath);
|
|
1217
|
+
if (parsed === void 0) {
|
|
1218
|
+
return readCredentialMigrationState(migrationPath) === "absent" ? { state: "legacy_broker" } : { state: "invalid" };
|
|
751
1219
|
}
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
}, ms);
|
|
758
|
-
const onAbort = () => {
|
|
759
|
-
clearTimeout(timer);
|
|
760
|
-
reject(abortError(signal));
|
|
1220
|
+
if (parsed === null) return { state: "invalid" };
|
|
1221
|
+
try {
|
|
1222
|
+
return {
|
|
1223
|
+
state: "workos_connect",
|
|
1224
|
+
metadata: parseWorkosConnectCredentialMetadata(parsed)
|
|
761
1225
|
};
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
}
|
|
765
|
-
var syncSleeper = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT));
|
|
766
|
-
async function withFileLock(lockDir, operation, options = {}) {
|
|
767
|
-
mkdirSync3(dirname3(lockDir), { recursive: true, mode: DIRECTORY_MODE });
|
|
768
|
-
const nowMs = options.nowMs ?? Date.now;
|
|
769
|
-
const alive = options.processAlive ?? processIsAlive;
|
|
770
|
-
const deadline = nowMs() + (options.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
771
|
-
let owner = null;
|
|
772
|
-
while (!owner) {
|
|
773
|
-
throwIfAborted(options.signal);
|
|
774
|
-
const now = nowMs();
|
|
775
|
-
owner = tryTakeLock(lockDir, now);
|
|
776
|
-
if (owner) break;
|
|
777
|
-
recoverStaleLock(lockDir, now, alive, options.initGraceMs ?? DEFAULT_INIT_GRACE_MS);
|
|
778
|
-
if (now >= deadline) {
|
|
779
|
-
throw new Error(`timed out waiting for file lock ${lockDir}`);
|
|
780
|
-
}
|
|
781
|
-
if (options.sleep) {
|
|
782
|
-
await options.sleep(options.pollMs ?? DEFAULT_POLL_MS);
|
|
783
|
-
throwIfAborted(options.signal);
|
|
784
|
-
} else {
|
|
785
|
-
await defaultSleep(options.pollMs ?? DEFAULT_POLL_MS, options.signal);
|
|
786
|
-
}
|
|
1226
|
+
} catch {
|
|
1227
|
+
return { state: "invalid" };
|
|
787
1228
|
}
|
|
1229
|
+
}
|
|
1230
|
+
function decodeJwtPayload(token) {
|
|
1231
|
+
const parts = token.split(".");
|
|
1232
|
+
if (parts.length !== 3) return void 0;
|
|
788
1233
|
try {
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
}
|
|
1234
|
+
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"));
|
|
1235
|
+
if (payload === null || typeof payload !== "object" || Array.isArray(payload)) return void 0;
|
|
1236
|
+
return payload;
|
|
1237
|
+
} catch {
|
|
1238
|
+
return void 0;
|
|
795
1239
|
}
|
|
796
1240
|
}
|
|
1241
|
+
function jwtExpiresAt(token) {
|
|
1242
|
+
const exp = decodeJwtPayload(token)?.exp;
|
|
1243
|
+
return typeof exp === "number" && Number.isFinite(exp) ? exp * 1e3 : void 0;
|
|
1244
|
+
}
|
|
797
1245
|
|
|
798
1246
|
// src/lib/terminal-safe.ts
|
|
799
1247
|
function replaceIsolatedSurrogates(value) {
|
|
@@ -848,7 +1296,7 @@ var DEFAULT_API_URL = "https://api.getprimitive.ai";
|
|
|
848
1296
|
var AUTH_EXPIRED_MESSAGE = "Authentication expired. Run `prim auth login` to re-authenticate.";
|
|
849
1297
|
function readTrimmed2(path) {
|
|
850
1298
|
try {
|
|
851
|
-
const value =
|
|
1299
|
+
const value = readFileSync7(path, "utf8").trim();
|
|
852
1300
|
return value || void 0;
|
|
853
1301
|
} catch {
|
|
854
1302
|
return void 0;
|
|
@@ -864,17 +1312,17 @@ function expiresAtFor(token, expiresIn) {
|
|
|
864
1312
|
return expiresIn === void 0 ? jwtExpiresAt(token) : Date.now() + expiresIn * 1e3;
|
|
865
1313
|
}
|
|
866
1314
|
function ensureConfigDirectory() {
|
|
867
|
-
const directory =
|
|
868
|
-
|
|
869
|
-
|
|
1315
|
+
const directory = dirname7(TOKEN_FILE_PATH);
|
|
1316
|
+
mkdirSync5(directory, { recursive: true, mode: CONFIG_DIR_MODE });
|
|
1317
|
+
chmodSync3(directory, CONFIG_DIR_MODE);
|
|
870
1318
|
}
|
|
871
1319
|
function atomicWrite(path, content) {
|
|
872
1320
|
ensureConfigDirectory();
|
|
873
1321
|
atomicWriteFile(path, content, { mode: CREDENTIAL_FILE_MODE });
|
|
874
1322
|
}
|
|
875
1323
|
function removeCredentialFile(path) {
|
|
876
|
-
if (!
|
|
877
|
-
|
|
1324
|
+
if (!existsSync6(path)) return false;
|
|
1325
|
+
rmSync4(path, { force: true });
|
|
878
1326
|
return true;
|
|
879
1327
|
}
|
|
880
1328
|
function getTokenExpiresAt() {
|
|
@@ -889,7 +1337,7 @@ function isTokenExpiringSoon(credential) {
|
|
|
889
1337
|
return expiresAt !== void 0 && Date.now() >= expiresAt - REFRESH_THRESHOLD_MS;
|
|
890
1338
|
}
|
|
891
1339
|
function refreshFingerprint(refreshToken2) {
|
|
892
|
-
return
|
|
1340
|
+
return createHash4("sha256").update(refreshToken2).digest("hex");
|
|
893
1341
|
}
|
|
894
1342
|
function legacyBrokerCredentialMetadata(accessToken, refreshToken2) {
|
|
895
1343
|
return {
|
|
@@ -1291,24 +1739,24 @@ function getClient() {
|
|
|
1291
1739
|
}
|
|
1292
1740
|
|
|
1293
1741
|
// src/commands/claude-plugin.ts
|
|
1294
|
-
import { createHash as
|
|
1742
|
+
import { createHash as createHash6 } from "crypto";
|
|
1295
1743
|
import {
|
|
1296
|
-
constants as
|
|
1744
|
+
constants as constants4,
|
|
1297
1745
|
closeSync as closeSync3,
|
|
1298
|
-
existsSync as
|
|
1746
|
+
existsSync as existsSync8,
|
|
1299
1747
|
fstatSync as fstatSync2,
|
|
1300
|
-
lstatSync as
|
|
1301
|
-
mkdirSync as
|
|
1748
|
+
lstatSync as lstatSync4,
|
|
1749
|
+
mkdirSync as mkdirSync6,
|
|
1302
1750
|
openSync as openSync3,
|
|
1303
|
-
readFileSync as
|
|
1751
|
+
readFileSync as readFileSync9,
|
|
1304
1752
|
readSync as readSync2,
|
|
1305
|
-
readdirSync,
|
|
1306
|
-
realpathSync as
|
|
1307
|
-
rmSync as
|
|
1308
|
-
rmdirSync
|
|
1753
|
+
readdirSync as readdirSync3,
|
|
1754
|
+
realpathSync as realpathSync3,
|
|
1755
|
+
rmSync as rmSync5,
|
|
1756
|
+
rmdirSync as rmdirSync2
|
|
1309
1757
|
} from "fs";
|
|
1310
|
-
import { homedir as
|
|
1311
|
-
import { dirname as
|
|
1758
|
+
import { homedir as homedir6 } from "os";
|
|
1759
|
+
import { dirname as dirname9, isAbsolute as isAbsolute6, join as join12, relative as relative2, resolve as resolve5, sep as sep2 } from "path";
|
|
1312
1760
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
1313
1761
|
|
|
1314
1762
|
// node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/browser/dist/nodes/identity.js
|
|
@@ -7578,67 +8026,23 @@ function parse(src, reviver, options) {
|
|
|
7578
8026
|
return doc.toJS(Object.assign({ reviver: _reviver }, options));
|
|
7579
8027
|
}
|
|
7580
8028
|
|
|
7581
|
-
// src/lib/git.ts
|
|
7582
|
-
import { execFileSync } from "child_process";
|
|
7583
|
-
import { createHash as createHash3 } from "crypto";
|
|
7584
|
-
import { lstatSync, realpathSync } from "fs";
|
|
7585
|
-
import { basename, dirname as dirname5, isAbsolute as isAbsolute3, relative, resolve as resolve2, sep } from "path";
|
|
7586
|
-
var GIT_TIMEOUT_MS = 1e3;
|
|
7587
|
-
var GITHUB_OWNER_PATTERN = /^(?![A-Za-z0-9-]*--)[A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?$/u;
|
|
7588
|
-
var GITHUB_REPOSITORY_PATTERN = /^[A-Za-z0-9._-]{1,100}$/u;
|
|
7589
|
-
function gitToplevel(cwd) {
|
|
7590
|
-
try {
|
|
7591
|
-
return execFileSync("git", ["rev-parse", "--show-toplevel"], {
|
|
7592
|
-
cwd,
|
|
7593
|
-
encoding: "utf-8",
|
|
7594
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
7595
|
-
timeout: GIT_TIMEOUT_MS
|
|
7596
|
-
}).trim();
|
|
7597
|
-
} catch {
|
|
7598
|
-
return null;
|
|
7599
|
-
}
|
|
7600
|
-
}
|
|
7601
|
-
function gitValue(cwd, args) {
|
|
7602
|
-
try {
|
|
7603
|
-
const value = execFileSync("git", args, {
|
|
7604
|
-
cwd,
|
|
7605
|
-
encoding: "utf-8",
|
|
7606
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
7607
|
-
timeout: GIT_TIMEOUT_MS
|
|
7608
|
-
}).trim();
|
|
7609
|
-
return value || void 0;
|
|
7610
|
-
} catch {
|
|
7611
|
-
return void 0;
|
|
7612
|
-
}
|
|
7613
|
-
}
|
|
7614
|
-
function githubRepositoryFullName(cwd) {
|
|
7615
|
-
const remote = gitValue(cwd, ["config", "--get", "remote.origin.url"]);
|
|
7616
|
-
if (!remote || [...remote].some((char) => char < " " || char === "\x7F")) return null;
|
|
7617
|
-
const match = /^(?:git@github\.com:([^?#]+)|(?:https|ssh):\/\/(?:[^/@]+@)?github\.com(?::\d+)?\/([^?#]+))$/i.exec(
|
|
7618
|
-
remote
|
|
7619
|
-
);
|
|
7620
|
-
const path = match?.[1] ?? match?.[2];
|
|
7621
|
-
if (!path) return null;
|
|
7622
|
-
const parts = path.replace(/^\/+|\/+$/g, "").replace(/\.git$/i, "").split("/");
|
|
7623
|
-
if (parts.length !== 2 || !GITHUB_OWNER_PATTERN.test(parts[0] ?? "") || !GITHUB_REPOSITORY_PATTERN.test(parts[1] ?? "")) {
|
|
7624
|
-
return null;
|
|
7625
|
-
}
|
|
7626
|
-
return `${parts[0]}/${parts[1]}`;
|
|
7627
|
-
}
|
|
7628
|
-
|
|
7629
8029
|
// src/commands/skill.ts
|
|
8030
|
+
import { createHash as createHash5 } from "crypto";
|
|
7630
8031
|
import {
|
|
7631
|
-
constants as
|
|
8032
|
+
constants as constants3,
|
|
7632
8033
|
closeSync as closeSync2,
|
|
7633
|
-
existsSync as
|
|
8034
|
+
existsSync as existsSync7,
|
|
7634
8035
|
fstatSync,
|
|
7635
|
-
lstatSync as
|
|
8036
|
+
lstatSync as lstatSync3,
|
|
7636
8037
|
openSync as openSync2,
|
|
7637
|
-
readFileSync as
|
|
7638
|
-
readSync
|
|
8038
|
+
readFileSync as readFileSync8,
|
|
8039
|
+
readSync,
|
|
8040
|
+
readdirSync as readdirSync2,
|
|
8041
|
+
rmdirSync,
|
|
8042
|
+
unlinkSync
|
|
7639
8043
|
} from "fs";
|
|
7640
|
-
import { homedir as
|
|
7641
|
-
import { dirname as
|
|
8044
|
+
import { homedir as homedir5 } from "os";
|
|
8045
|
+
import { dirname as dirname8, join as join11, resolve as resolve4 } from "path";
|
|
7642
8046
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
7643
8047
|
|
|
7644
8048
|
// node_modules/.pnpm/diff@5.2.2/node_modules/diff/lib/index.mjs
|
|
@@ -7808,7 +8212,7 @@ Diff.prototype = {
|
|
|
7808
8212
|
tokenize: function tokenize(value) {
|
|
7809
8213
|
return value.split("");
|
|
7810
8214
|
},
|
|
7811
|
-
join: function
|
|
8215
|
+
join: function join10(chars) {
|
|
7812
8216
|
return chars.join("");
|
|
7813
8217
|
}
|
|
7814
8218
|
};
|
|
@@ -7993,7 +8397,7 @@ arrayDiff.join = arrayDiff.removeEmpty = function(value) {
|
|
|
7993
8397
|
};
|
|
7994
8398
|
|
|
7995
8399
|
// src/commands/skill.ts
|
|
7996
|
-
var __dirname =
|
|
8400
|
+
var __dirname = dirname8(fileURLToPath2(import.meta.url));
|
|
7997
8401
|
var SKILL_BEGIN = "<!-- BEGIN PRIM SKILL v1 -->";
|
|
7998
8402
|
var SKILL_END = "<!-- END PRIM SKILL v1 -->";
|
|
7999
8403
|
var CODEX_GUIDANCE_LIMIT_BYTES = 1024 * 1024;
|
|
@@ -8002,9 +8406,9 @@ var SKILL_BEGIN_BUFFER = Buffer.from(SKILL_BEGIN);
|
|
|
8002
8406
|
var SKILL_END_BUFFER = Buffer.from(SKILL_END);
|
|
8003
8407
|
function readCodexGuidance(path) {
|
|
8004
8408
|
try {
|
|
8005
|
-
const entry =
|
|
8409
|
+
const entry = lstatSync3(path);
|
|
8006
8410
|
if (entry.isSymbolicLink() || !entry.isFile()) return null;
|
|
8007
|
-
const fd = openSync2(path,
|
|
8411
|
+
const fd = openSync2(path, constants3.O_RDONLY | constants3.O_NOFOLLOW);
|
|
8008
8412
|
try {
|
|
8009
8413
|
const opened = fstatSync(fd);
|
|
8010
8414
|
if (!opened.isFile() || opened.size > CODEX_GUIDANCE_LIMIT_BYTES) return null;
|
|
@@ -8025,10 +8429,10 @@ function readCodexGuidance(path) {
|
|
|
8025
8429
|
}
|
|
8026
8430
|
}
|
|
8027
8431
|
function effectiveCodexGuidance(scope) {
|
|
8028
|
-
const override = readCodexGuidance(
|
|
8432
|
+
const override = readCodexGuidance(join11(scope, "AGENTS.override.md"));
|
|
8029
8433
|
if (override === null) return null;
|
|
8030
8434
|
if (override !== void 0 && override.toString("utf8").trim().length > 0) return override;
|
|
8031
|
-
const base = readCodexGuidance(
|
|
8435
|
+
const base = readCodexGuidance(join11(scope, "AGENTS.md"));
|
|
8032
8436
|
return base ?? null;
|
|
8033
8437
|
}
|
|
8034
8438
|
function hasUsablePrimBlock(content, visibleBytes) {
|
|
@@ -8049,12 +8453,12 @@ function hasUsablePrimBlock(content, visibleBytes) {
|
|
|
8049
8453
|
return false;
|
|
8050
8454
|
}
|
|
8051
8455
|
}
|
|
8052
|
-
function hasUsableCodexGuidance(
|
|
8456
|
+
function hasUsableCodexGuidance(projectRoot2) {
|
|
8053
8457
|
try {
|
|
8054
|
-
const codexHome = process.env.CODEX_HOME?.trim() ?
|
|
8458
|
+
const codexHome = process.env.CODEX_HOME?.trim() ? resolve4(process.env.CODEX_HOME) : join11(homedir5(), ".codex");
|
|
8055
8459
|
const scopes = [
|
|
8056
8460
|
{ path: codexHome, visibleBytes: CODEX_GUIDANCE_LIMIT_BYTES },
|
|
8057
|
-
{ path:
|
|
8461
|
+
{ path: projectRoot2, visibleBytes: CODEX_DEFAULT_PROJECT_GUIDANCE_BYTES }
|
|
8058
8462
|
];
|
|
8059
8463
|
return scopes.some(({ path, visibleBytes }) => {
|
|
8060
8464
|
const guidance = effectiveCodexGuidance(path);
|
|
@@ -8064,12 +8468,58 @@ function hasUsableCodexGuidance(projectRoot) {
|
|
|
8064
8468
|
return false;
|
|
8065
8469
|
}
|
|
8066
8470
|
}
|
|
8471
|
+
var CURSOR_SKILL_OWNER = "@primitive.ai/prim";
|
|
8472
|
+
var CURSOR_SKILL_MANIFEST = ".prim-owned.json";
|
|
8473
|
+
function sha256(content) {
|
|
8474
|
+
return createHash5("sha256").update(content).digest("hex");
|
|
8475
|
+
}
|
|
8476
|
+
function cursorSkillDirectory(cwd, scope) {
|
|
8477
|
+
const base = scope === "user" ? cursorConfigDirectory() : gitToplevel(cwd) ?? cwd;
|
|
8478
|
+
return join11(base, scope === "user" ? "skills" : ".cursor/skills", "prim");
|
|
8479
|
+
}
|
|
8480
|
+
function cursorSkillPaths(cwd, scope) {
|
|
8481
|
+
const directory = cursorSkillDirectory(cwd, scope);
|
|
8482
|
+
return {
|
|
8483
|
+
directory,
|
|
8484
|
+
skill: join11(directory, "SKILL.md"),
|
|
8485
|
+
manifest: join11(directory, CURSOR_SKILL_MANIFEST)
|
|
8486
|
+
};
|
|
8487
|
+
}
|
|
8488
|
+
function readCursorSkillManifest(path) {
|
|
8489
|
+
try {
|
|
8490
|
+
const value = JSON.parse(readFileSync8(path, "utf8"));
|
|
8491
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return;
|
|
8492
|
+
const record = value;
|
|
8493
|
+
if (record.version !== 1 || record.owner !== CURSOR_SKILL_OWNER || typeof record.contentSha256 !== "string" || !/^[0-9a-f]{64}$/u.test(record.contentSha256)) {
|
|
8494
|
+
return;
|
|
8495
|
+
}
|
|
8496
|
+
return record;
|
|
8497
|
+
} catch {
|
|
8498
|
+
return;
|
|
8499
|
+
}
|
|
8500
|
+
}
|
|
8501
|
+
function cursorSkillStatus(cwd, scope) {
|
|
8502
|
+
const paths = cursorSkillPaths(cwd, scope);
|
|
8503
|
+
const manifest = readCursorSkillManifest(paths.manifest);
|
|
8504
|
+
const content = existsSync7(paths.skill) ? readFileSync8(paths.skill, "utf8") : void 0;
|
|
8505
|
+
const owned = manifest !== void 0;
|
|
8506
|
+
const installed = owned && content !== void 0 && sha256(content) === manifest.contentSha256;
|
|
8507
|
+
return {
|
|
8508
|
+
installed,
|
|
8509
|
+
owned,
|
|
8510
|
+
edited: owned && content !== void 0 && !installed,
|
|
8511
|
+
target: paths.skill
|
|
8512
|
+
};
|
|
8513
|
+
}
|
|
8514
|
+
function hasUsableCursorSkill(projectRoot2) {
|
|
8515
|
+
return cursorSkillStatus(projectRoot2, "project").installed || cursorSkillStatus(projectRoot2, "user").installed;
|
|
8516
|
+
}
|
|
8067
8517
|
function loadSkill() {
|
|
8068
8518
|
let dir = __dirname;
|
|
8069
|
-
while (dir !==
|
|
8070
|
-
const p =
|
|
8071
|
-
if (
|
|
8072
|
-
dir =
|
|
8519
|
+
while (dir !== dirname8(dir)) {
|
|
8520
|
+
const p = resolve4(dir, "SKILL.md");
|
|
8521
|
+
if (existsSync7(p)) return readFileSync8(p, "utf-8");
|
|
8522
|
+
dir = dirname8(dir);
|
|
8073
8523
|
}
|
|
8074
8524
|
throw new Error("SKILL.md not found in package");
|
|
8075
8525
|
}
|
|
@@ -8078,22 +8528,22 @@ function atomicWrite2(target, content) {
|
|
|
8078
8528
|
}
|
|
8079
8529
|
|
|
8080
8530
|
// src/commands/claude-plugin.ts
|
|
8081
|
-
var __dirname2 =
|
|
8531
|
+
var __dirname2 = dirname9(fileURLToPath3(import.meta.url));
|
|
8082
8532
|
var PLUGIN_DESCRIPTION = "Primitive decision-graph guidance for the prim CLI \u2014 a model-invoked skill installed by prim skill install.";
|
|
8083
|
-
var
|
|
8533
|
+
var MAX_MANIFEST_BYTES2 = 64 * 1024;
|
|
8084
8534
|
var MAX_SKILL_BYTES = 1024 * 1024;
|
|
8085
8535
|
var REFRESH_LOCK_TIMEOUT_MS = 150;
|
|
8086
8536
|
var REFRESH_LOCK_POLL_MS = 10;
|
|
8087
8537
|
function pluginDirFor(cwd, scope) {
|
|
8088
|
-
const base = scope === "user" ?
|
|
8089
|
-
return
|
|
8538
|
+
const base = scope === "user" ? join12(homedir6(), ".claude") : join12(gitToplevel(cwd) ?? cwd, ".claude");
|
|
8539
|
+
return join12(base, "skills", "prim");
|
|
8090
8540
|
}
|
|
8091
8541
|
function packageVersion2() {
|
|
8092
8542
|
let dir = __dirname2;
|
|
8093
|
-
while (dir !==
|
|
8094
|
-
const p =
|
|
8095
|
-
if (
|
|
8096
|
-
dir =
|
|
8543
|
+
while (dir !== dirname9(dir)) {
|
|
8544
|
+
const p = resolve5(dir, "package.json");
|
|
8545
|
+
if (existsSync8(p)) return JSON.parse(readFileSync9(p, "utf-8")).version;
|
|
8546
|
+
dir = dirname9(dir);
|
|
8097
8547
|
}
|
|
8098
8548
|
return "0.0.0";
|
|
8099
8549
|
}
|
|
@@ -8108,27 +8558,27 @@ function renderClaudePlugin() {
|
|
|
8108
8558
|
}
|
|
8109
8559
|
function pluginPaths(dir) {
|
|
8110
8560
|
return {
|
|
8111
|
-
manifestPath:
|
|
8112
|
-
skillPath:
|
|
8561
|
+
manifestPath: join12(dir, ".claude-plugin", "plugin.json"),
|
|
8562
|
+
skillPath: join12(dir, "SKILL.md")
|
|
8113
8563
|
};
|
|
8114
8564
|
}
|
|
8115
8565
|
function pathIsInside(root, path) {
|
|
8116
8566
|
const rel = relative2(root, path);
|
|
8117
|
-
return rel !== ".." && !rel.startsWith(`..${sep2}`) && !
|
|
8567
|
+
return rel !== ".." && !rel.startsWith(`..${sep2}`) && !isAbsolute6(rel);
|
|
8118
8568
|
}
|
|
8119
|
-
function managedPathsAreSafe(paths,
|
|
8569
|
+
function managedPathsAreSafe(paths, projectRoot2) {
|
|
8120
8570
|
try {
|
|
8121
8571
|
const managed = [paths.manifestPath, paths.skillPath];
|
|
8122
|
-
if (managed.some((path) => !
|
|
8123
|
-
if (
|
|
8124
|
-
const realRoot =
|
|
8125
|
-
return managed.every((path) => pathIsInside(realRoot,
|
|
8572
|
+
if (managed.some((path) => !lstatSync4(path).isFile())) return false;
|
|
8573
|
+
if (projectRoot2 === void 0) return true;
|
|
8574
|
+
const realRoot = realpathSync3(projectRoot2);
|
|
8575
|
+
return managed.every((path) => pathIsInside(realRoot, realpathSync3(path)));
|
|
8126
8576
|
} catch {
|
|
8127
8577
|
return false;
|
|
8128
8578
|
}
|
|
8129
8579
|
}
|
|
8130
8580
|
function readBoundedRegularFile(path, maxBytes) {
|
|
8131
|
-
const fd = openSync3(path,
|
|
8581
|
+
const fd = openSync3(path, constants4.O_RDONLY | constants4.O_NOFOLLOW);
|
|
8132
8582
|
try {
|
|
8133
8583
|
const stat = fstatSync2(fd);
|
|
8134
8584
|
if (!stat.isFile() || stat.size > maxBytes) throw new Error("unsafe managed file");
|
|
@@ -8159,10 +8609,10 @@ function hasUsablePrimFrontmatter(skill) {
|
|
|
8159
8609
|
return false;
|
|
8160
8610
|
}
|
|
8161
8611
|
}
|
|
8162
|
-
function inspectRecognizedInstallation(paths,
|
|
8163
|
-
if (!
|
|
8164
|
-
if (!managedPathsAreSafe(paths,
|
|
8165
|
-
const manifest = readBoundedRegularFile(paths.manifestPath,
|
|
8612
|
+
function inspectRecognizedInstallation(paths, projectRoot2) {
|
|
8613
|
+
if (!existsSync8(paths.manifestPath) || !existsSync8(paths.skillPath)) return;
|
|
8614
|
+
if (!managedPathsAreSafe(paths, projectRoot2)) return;
|
|
8615
|
+
const manifest = readBoundedRegularFile(paths.manifestPath, MAX_MANIFEST_BYTES2);
|
|
8166
8616
|
const parsed = JSON.parse(manifest);
|
|
8167
8617
|
if (parsed.name !== "prim") return;
|
|
8168
8618
|
const skill = readBoundedRegularFile(paths.skillPath, MAX_SKILL_BYTES);
|
|
@@ -8174,23 +8624,23 @@ function inspectRecognizedInstallation(paths, projectRoot) {
|
|
|
8174
8624
|
};
|
|
8175
8625
|
}
|
|
8176
8626
|
function refreshLockDir(physicalPluginDir) {
|
|
8177
|
-
const cacheRoot = process.env.XDG_CACHE_HOME ||
|
|
8178
|
-
const identity =
|
|
8179
|
-
return
|
|
8627
|
+
const cacheRoot = process.env.XDG_CACHE_HOME || join12(homedir6(), ".cache");
|
|
8628
|
+
const identity = createHash6("sha256").update(physicalPluginDir).digest("hex");
|
|
8629
|
+
return join12(cacheRoot, "prim", "skill-refresh-locks", `${identity}.lock`);
|
|
8180
8630
|
}
|
|
8181
8631
|
async function refreshClaudePlugins(cwd, options = {}) {
|
|
8182
8632
|
const result = { installed: 0, refreshed: 0 };
|
|
8183
8633
|
const candidates = [];
|
|
8184
8634
|
if (options.includeProject !== false) {
|
|
8185
|
-
const
|
|
8186
|
-
if (
|
|
8187
|
-
candidates.push({ dir:
|
|
8635
|
+
const projectRoot2 = options.projectRoot ?? gitToplevel(cwd);
|
|
8636
|
+
if (projectRoot2 !== null && isAbsolute6(projectRoot2)) {
|
|
8637
|
+
candidates.push({ dir: join12(projectRoot2, ".claude", "skills", "prim"), projectRoot: projectRoot2 });
|
|
8188
8638
|
}
|
|
8189
8639
|
}
|
|
8190
8640
|
candidates.push({ dir: pluginDirFor(cwd, "user") });
|
|
8191
8641
|
const seen = /* @__PURE__ */ new Set();
|
|
8192
8642
|
let desired;
|
|
8193
|
-
for (const { dir, projectRoot } of candidates) {
|
|
8643
|
+
for (const { dir, projectRoot: projectRoot2 } of candidates) {
|
|
8194
8644
|
let counted = false;
|
|
8195
8645
|
const markInstalled = () => {
|
|
8196
8646
|
if (!counted) {
|
|
@@ -8203,21 +8653,21 @@ async function refreshClaudePlugins(cwd, options = {}) {
|
|
|
8203
8653
|
const paths = { manifestPath, skillPath };
|
|
8204
8654
|
try {
|
|
8205
8655
|
let changed = false;
|
|
8206
|
-
const current = inspectRecognizedInstallation(paths,
|
|
8656
|
+
const current = inspectRecognizedInstallation(paths, projectRoot2);
|
|
8207
8657
|
if (!current) return;
|
|
8208
8658
|
desired ??= renderClaudePlugin();
|
|
8209
|
-
if (
|
|
8659
|
+
if (projectRoot2 !== void 0 && current.usable && compareSemver(current.manifestVersion, desired.version) === 1) {
|
|
8210
8660
|
markInstalled();
|
|
8211
8661
|
return;
|
|
8212
8662
|
}
|
|
8213
8663
|
if (current.manifest !== desired.manifest) {
|
|
8214
|
-
if (!managedPathsAreSafe(paths,
|
|
8664
|
+
if (!managedPathsAreSafe(paths, projectRoot2)) throw new Error("unsafe managed path");
|
|
8215
8665
|
atomicWrite2(manifestPath, desired.manifest);
|
|
8216
8666
|
if (!changed) result.refreshed += 1;
|
|
8217
8667
|
changed = true;
|
|
8218
8668
|
}
|
|
8219
8669
|
if (current.skill !== desired.skill) {
|
|
8220
|
-
if (!managedPathsAreSafe(paths,
|
|
8670
|
+
if (!managedPathsAreSafe(paths, projectRoot2)) throw new Error("unsafe managed path");
|
|
8221
8671
|
atomicWrite2(skillPath, desired.skill);
|
|
8222
8672
|
if (!changed) result.refreshed += 1;
|
|
8223
8673
|
changed = true;
|
|
@@ -8225,15 +8675,15 @@ async function refreshClaudePlugins(cwd, options = {}) {
|
|
|
8225
8675
|
markInstalled();
|
|
8226
8676
|
} catch {
|
|
8227
8677
|
try {
|
|
8228
|
-
if (inspectRecognizedInstallation(paths,
|
|
8678
|
+
if (inspectRecognizedInstallation(paths, projectRoot2)?.usable) markInstalled();
|
|
8229
8679
|
} catch {
|
|
8230
8680
|
}
|
|
8231
8681
|
}
|
|
8232
8682
|
};
|
|
8233
8683
|
try {
|
|
8234
8684
|
const paths = pluginPaths(dir);
|
|
8235
|
-
if (!
|
|
8236
|
-
const physicalPluginDir =
|
|
8685
|
+
if (!existsSync8(paths.manifestPath) || !existsSync8(paths.skillPath)) continue;
|
|
8686
|
+
const physicalPluginDir = realpathSync3(dir);
|
|
8237
8687
|
if (seen.has(physicalPluginDir)) continue;
|
|
8238
8688
|
seen.add(physicalPluginDir);
|
|
8239
8689
|
await withFileLock(refreshLockDir(physicalPluginDir), refreshCandidate, {
|
|
@@ -8248,16 +8698,16 @@ async function refreshClaudePlugins(cwd, options = {}) {
|
|
|
8248
8698
|
|
|
8249
8699
|
// src/daemon/client.ts
|
|
8250
8700
|
import { createConnection } from "net";
|
|
8251
|
-
import { join as
|
|
8701
|
+
import { join as join13 } from "path";
|
|
8252
8702
|
|
|
8253
8703
|
// src/daemon/principal.ts
|
|
8254
|
-
import { createHash as
|
|
8704
|
+
import { createHash as createHash7 } from "crypto";
|
|
8255
8705
|
var PRINCIPAL_COMPONENT_MAX_LENGTH = 512;
|
|
8256
8706
|
function boundedClaim(value) {
|
|
8257
8707
|
return typeof value === "string" && value.length > 0 && value.length <= PRINCIPAL_COMPONENT_MAX_LENGTH ? value : void 0;
|
|
8258
8708
|
}
|
|
8259
|
-
function
|
|
8260
|
-
return
|
|
8709
|
+
function sha2562(value) {
|
|
8710
|
+
return createHash7("sha256").update(value).digest("hex");
|
|
8261
8711
|
}
|
|
8262
8712
|
function resolveDaemonPrincipal(token = resolveAuthCredential()?.token) {
|
|
8263
8713
|
if (!token) return void 0;
|
|
@@ -8267,9 +8717,9 @@ function resolveDaemonPrincipal(token = resolveAuthCredential()?.token) {
|
|
|
8267
8717
|
if (!(subject && organizationId)) return void 0;
|
|
8268
8718
|
const issuer = boundedClaim(payload?.iss) ?? "unknown-issuer";
|
|
8269
8719
|
return {
|
|
8270
|
-
principalId:
|
|
8720
|
+
principalId: sha2562(`${issuer}\0${subject}`),
|
|
8271
8721
|
organizationId,
|
|
8272
|
-
credentialFingerprint:
|
|
8722
|
+
credentialFingerprint: sha2562(token)
|
|
8273
8723
|
};
|
|
8274
8724
|
}
|
|
8275
8725
|
function daemonPrincipalsMatch(caller, daemon) {
|
|
@@ -8298,7 +8748,7 @@ function parseDaemonResponseEnvelope(value) {
|
|
|
8298
8748
|
}
|
|
8299
8749
|
|
|
8300
8750
|
// src/daemon/client.ts
|
|
8301
|
-
var SOCK_PATH =
|
|
8751
|
+
var SOCK_PATH = join13(primConfigDirectory(), "sock");
|
|
8302
8752
|
var DEFAULT_TIMEOUT_MS2 = 250;
|
|
8303
8753
|
var nextRequestId = 1;
|
|
8304
8754
|
function daemonRequest(method, params = {}, opts = {}) {
|
|
@@ -8311,7 +8761,7 @@ function daemonRequest(method, params = {}, opts = {}) {
|
|
|
8311
8761
|
...caller ? { caller } : {}
|
|
8312
8762
|
};
|
|
8313
8763
|
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
8314
|
-
return new Promise((
|
|
8764
|
+
return new Promise((resolve9) => {
|
|
8315
8765
|
let settled = false;
|
|
8316
8766
|
let socket;
|
|
8317
8767
|
let buffer = Buffer.alloc(0);
|
|
@@ -8326,7 +8776,7 @@ function daemonRequest(method, params = {}, opts = {}) {
|
|
|
8326
8776
|
} catch {
|
|
8327
8777
|
}
|
|
8328
8778
|
}
|
|
8329
|
-
|
|
8779
|
+
resolve9(value);
|
|
8330
8780
|
};
|
|
8331
8781
|
const timer = setTimeout(() => settle(null), timeoutMs);
|
|
8332
8782
|
timer.unref();
|
|
@@ -8592,16 +9042,16 @@ async function acknowledgeDecisionFeedback(input, dependencies = {}) {
|
|
|
8592
9042
|
|
|
8593
9043
|
// src/lib/activation.ts
|
|
8594
9044
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
8595
|
-
import { existsSync as
|
|
8596
|
-
import { homedir as
|
|
8597
|
-
import { join as
|
|
9045
|
+
import { existsSync as existsSync9, readFileSync as readFileSync10 } from "fs";
|
|
9046
|
+
import { homedir as homedir7 } from "os";
|
|
9047
|
+
import { join as join14 } from "path";
|
|
8598
9048
|
var PRIM_ACTIVE_KEY = "prim.active";
|
|
8599
9049
|
var PRIM_REPO_SYNC_ID_KEY = "prim.repoSyncId";
|
|
8600
9050
|
var PRIM_REPO_SYNC_REPOSITORY_KEY = "prim.repoSyncRepository";
|
|
8601
9051
|
var PRIM_REPO_BINDING_STATE_KEY = "prim.repoBindingState";
|
|
8602
9052
|
var GIT_TIMEOUT_MS2 = 1e3;
|
|
8603
9053
|
var REPO_SYNC_ID_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/;
|
|
8604
|
-
var PROJECT_INSTALL_FILES = [".claude/settings.json", ".codex/hooks.json"];
|
|
9054
|
+
var PROJECT_INSTALL_FILES = [".claude/settings.json", ".codex/hooks.json", ".cursor/hooks.json"];
|
|
8605
9055
|
var PRIM_HOOK_BINS = ["prim-hook", "prim-pre-tool-use", "prim-post-tool-use"];
|
|
8606
9056
|
function repoActiveFlag(cwd) {
|
|
8607
9057
|
try {
|
|
@@ -8690,12 +9140,12 @@ function repositoryBindingState(cwd) {
|
|
|
8690
9140
|
}
|
|
8691
9141
|
function hasProjectPrimInstall(cwd) {
|
|
8692
9142
|
const root = gitToplevel(cwd);
|
|
8693
|
-
if (root === null || root ===
|
|
9143
|
+
if (root === null || root === homedir7()) return false;
|
|
8694
9144
|
for (const rel of PROJECT_INSTALL_FILES) {
|
|
8695
|
-
const path =
|
|
8696
|
-
if (
|
|
9145
|
+
const path = join14(root, rel);
|
|
9146
|
+
if (existsSync9(path)) {
|
|
8697
9147
|
try {
|
|
8698
|
-
const content =
|
|
9148
|
+
const content = readFileSync10(path, "utf-8");
|
|
8699
9149
|
if (PRIM_HOOK_BINS.some((bin) => content.includes(bin))) return true;
|
|
8700
9150
|
} catch {
|
|
8701
9151
|
}
|
|
@@ -9536,7 +9986,7 @@ function validate23(data, { instancePath = "", parentData, parentDataProperty, r
|
|
|
9536
9986
|
}
|
|
9537
9987
|
validate23.evaluated = { "props": true, "dynamicProps": false, "dynamicItems": false };
|
|
9538
9988
|
var isDecisionCollectScopeResponse = validate24;
|
|
9539
|
-
var schema39 = { "type": "object", "properties": { "policy": { "anyOf": [{ "type": "object", "properties": { "repositories": { "type": "array", "items": { "type": "string" } }, "directories": { "type": "array", "items": { "type": "string" } }, "globs": { "type": "array", "items": { "type": "string" } }, "branches": { "type": "array", "items": { "type": "string" } }, "effectiveFrom": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "effectiveUntil": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "users": { "type": "array", "items": { "oneOf": [{ "type": "object", "properties": { "kind": { "type": "string", "const": "user" }, "userId": { "type": "string", "minLength": 1 } }, "required": ["kind", "userId"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "role" }, "role": { "type": "string", "enum": ["owner", "admin", "member"] } }, "required": ["kind", "role"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "agent" }, "agent": { "type": "string", "enum": ["claude_code", "codex", "hermes"] } }, "required": ["kind", "agent"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "credential" }, "credential": { "type": "string", "enum": ["workos_jwt", "workos_api_key", "service_token"] } }, "required": ["kind", "credential"], "additionalProperties": false }] } }, "updatedAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 } }, "required": ["updatedAt"], "additionalProperties": {} }, { "type": "null" }] }, "collectScopeVersion": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "callerIncluded": { "type": "boolean" } }, "required": ["policy", "collectScopeVersion", "callerIncluded"], "additionalProperties": {} };
|
|
9989
|
+
var schema39 = { "type": "object", "properties": { "policy": { "anyOf": [{ "type": "object", "properties": { "repositories": { "type": "array", "items": { "type": "string" } }, "directories": { "type": "array", "items": { "type": "string" } }, "globs": { "type": "array", "items": { "type": "string" } }, "branches": { "type": "array", "items": { "type": "string" } }, "effectiveFrom": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "effectiveUntil": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "users": { "type": "array", "items": { "oneOf": [{ "type": "object", "properties": { "kind": { "type": "string", "const": "user" }, "userId": { "type": "string", "minLength": 1 } }, "required": ["kind", "userId"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "role" }, "role": { "type": "string", "enum": ["owner", "admin", "member"] } }, "required": ["kind", "role"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "agent" }, "agent": { "type": "string", "enum": ["claude_code", "codex", "cursor", "hermes"] } }, "required": ["kind", "agent"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "credential" }, "credential": { "type": "string", "enum": ["workos_jwt", "workos_api_key", "service_token"] } }, "required": ["kind", "credential"], "additionalProperties": false }] } }, "updatedAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 } }, "required": ["updatedAt"], "additionalProperties": {} }, { "type": "null" }] }, "collectScopeVersion": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "callerIncluded": { "type": "boolean" } }, "required": ["policy", "collectScopeVersion", "callerIncluded"], "additionalProperties": {} };
|
|
9540
9990
|
function validate24(data, { instancePath = "", parentData, parentDataProperty, rootData = data, dynamicAnchors = {} } = {}) {
|
|
9541
9991
|
;
|
|
9542
9992
|
let vErrors = null;
|
|
@@ -10087,7 +10537,7 @@ function validate24(data, { instancePath = "", parentData, parentDataProperty, r
|
|
|
10087
10537
|
}
|
|
10088
10538
|
errors++;
|
|
10089
10539
|
}
|
|
10090
|
-
if (!(data18 === "claude_code" || data18 === "codex" || data18 === "hermes")) {
|
|
10540
|
+
if (!(data18 === "claude_code" || data18 === "codex" || data18 === "cursor" || data18 === "hermes")) {
|
|
10091
10541
|
const err34 = { instancePath: instancePath + "/policy/users/" + i4 + "/agent", schemaPath: "https://api.getprimitive.ai/contracts/cli-http-v1.schema.json#/$defs/DecisionCollectScopeResponse/properties/policy/anyOf/0/properties/users/items/oneOf/2/properties/agent/enum", keyword: "enum", params: { allowedValues: schema39.properties.policy.anyOf[0].properties.users.items.oneOf[2].properties.agent.enum }, message: "must be equal to one of the allowed values" };
|
|
10092
10542
|
if (vErrors === null) {
|
|
10093
10543
|
vErrors = [err34];
|
|
@@ -10856,7 +11306,7 @@ function validate26(data, { instancePath = "", parentData, parentDataProperty, r
|
|
|
10856
11306
|
return errors === 0;
|
|
10857
11307
|
}
|
|
10858
11308
|
validate26.evaluated = { "dynamicProps": true, "dynamicItems": false };
|
|
10859
|
-
var schema45 = { "type": "object", "properties": { "intent": { "type": "string", "minLength": 1, "maxLength": 500 }, "attribution": { "type": "string", "enum": ["user", "agent", "unknown"] }, "kind": { "type": "string", "enum": ["change", "exploration", "task_execution", "unclear"] }, "rationale": { "type": "string" }, "area": { "type": "string" }, "decided": { "type": "array", "items": { "type": "string" } }, "alternatives": { "type": "array", "items": { "type": "string" } }, "confidence": { "type": "string", "enum": ["high", "medium", "low"] }, "reversibility": { "type": "string", "enum": ["high", "low"] }, "files": { "type": "array", "items": { "type": "string" } }, "protocolVersion": { "type": "number", "const": 3 }, "repoSyncId": { "type": "string" }, "scope": { "default": {}, "type": "object", "properties": { "location": { "default": {}, "type": "object", "properties": { "repository": { "type": "boolean" }, "directories": { "type": "array", "items": { "type": "string" } }, "globs": { "type": "array", "items": { "type": "string" } }, "branches": { "type": "array", "items": { "type": "string" } } }, "additionalProperties": {} }, "time": { "default": {}, "type": "object", "properties": { "effectiveFrom": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "effectiveUntil": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "additionalProperties": {} }, "users": { "type": "array", "items": { "oneOf": [{ "type": "object", "properties": { "kind": { "type": "string", "const": "user" }, "userId": { "type": "string", "minLength": 1 } }, "required": ["kind", "userId"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "role" }, "role": { "type": "string", "enum": ["owner", "admin", "member"] } }, "required": ["kind", "role"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "agent" }, "agent": { "type": "string", "enum": ["claude_code", "codex", "hermes"] } }, "required": ["kind", "agent"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "credential" }, "credential": { "type": "string", "enum": ["workos_jwt", "workos_api_key", "service_token"] } }, "required": ["kind", "credential"], "additionalProperties": false }] } } }, "additionalProperties": {} }, "stageOverride": { "type": "string", "enum": ["candidate", "draft", "adopted"] } }, "required": ["intent"], "additionalProperties": {}, "x-primitive-runtime-refinements": ["degrade_invalid_rollout_fields", "degrade_invalid_location_scope", "degrade_invalid_time_scope"] };
|
|
11309
|
+
var schema45 = { "type": "object", "properties": { "intent": { "type": "string", "minLength": 1, "maxLength": 500 }, "attribution": { "type": "string", "enum": ["user", "agent", "unknown"] }, "kind": { "type": "string", "enum": ["change", "exploration", "task_execution", "unclear"] }, "rationale": { "type": "string" }, "area": { "type": "string" }, "decided": { "type": "array", "items": { "type": "string" } }, "alternatives": { "type": "array", "items": { "type": "string" } }, "confidence": { "type": "string", "enum": ["high", "medium", "low"] }, "reversibility": { "type": "string", "enum": ["high", "low"] }, "files": { "type": "array", "items": { "type": "string" } }, "protocolVersion": { "type": "number", "const": 3 }, "repoSyncId": { "type": "string" }, "scope": { "default": {}, "type": "object", "properties": { "location": { "default": {}, "type": "object", "properties": { "repository": { "type": "boolean" }, "directories": { "type": "array", "items": { "type": "string" } }, "globs": { "type": "array", "items": { "type": "string" } }, "branches": { "type": "array", "items": { "type": "string" } } }, "additionalProperties": {} }, "time": { "default": {}, "type": "object", "properties": { "effectiveFrom": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "effectiveUntil": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "additionalProperties": {} }, "users": { "type": "array", "items": { "oneOf": [{ "type": "object", "properties": { "kind": { "type": "string", "const": "user" }, "userId": { "type": "string", "minLength": 1 } }, "required": ["kind", "userId"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "role" }, "role": { "type": "string", "enum": ["owner", "admin", "member"] } }, "required": ["kind", "role"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "agent" }, "agent": { "type": "string", "enum": ["claude_code", "codex", "cursor", "hermes"] } }, "required": ["kind", "agent"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "credential" }, "credential": { "type": "string", "enum": ["workos_jwt", "workos_api_key", "service_token"] } }, "required": ["kind", "credential"], "additionalProperties": false }] } } }, "additionalProperties": {} }, "stageOverride": { "type": "string", "enum": ["candidate", "draft", "adopted"] } }, "required": ["intent"], "additionalProperties": {}, "x-primitive-runtime-refinements": ["degrade_invalid_rollout_fields", "degrade_invalid_location_scope", "degrade_invalid_time_scope"] };
|
|
10860
11310
|
function validate27(data, { instancePath = "", parentData, parentDataProperty, rootData = data, dynamicAnchors = {} } = {}) {
|
|
10861
11311
|
;
|
|
10862
11312
|
let vErrors = null;
|
|
@@ -11560,7 +12010,7 @@ function validate27(data, { instancePath = "", parentData, parentDataProperty, r
|
|
|
11560
12010
|
}
|
|
11561
12011
|
errors++;
|
|
11562
12012
|
}
|
|
11563
|
-
if (!(data34 === "claude_code" || data34 === "codex" || data34 === "hermes")) {
|
|
12013
|
+
if (!(data34 === "claude_code" || data34 === "codex" || data34 === "cursor" || data34 === "hermes")) {
|
|
11564
12014
|
const err19 = { instancePath: instancePath + "/scope/users/" + i6 + "/agent", schemaPath: "https://api.getprimitive.ai/contracts/cli-http-v1.schema.json#/$defs/DecisionCreateRequest/properties/scope/properties/users/items/oneOf/2/properties/agent/enum", keyword: "enum", params: { allowedValues: schema45.properties.scope.properties.users.items.oneOf[2].properties.agent.enum }, message: "must be equal to one of the allowed values" };
|
|
11565
12015
|
if (vErrors === null) {
|
|
11566
12016
|
vErrors = [err19];
|
|
@@ -11788,7 +12238,7 @@ function validate27(data, { instancePath = "", parentData, parentDataProperty, r
|
|
|
11788
12238
|
return errors === 0;
|
|
11789
12239
|
}
|
|
11790
12240
|
validate27.evaluated = { "props": true, "dynamicProps": false, "dynamicItems": false };
|
|
11791
|
-
var schema47 = { "type": "object", "properties": { "decisionId": { "type": "string", "minLength": 1 }, "shortId": { "type": "string" }, "createdAt": { "type": "number" }, "scope": { "type": "object", "properties": { "location": { "type": "object", "properties": { "repository": { "type": "boolean" }, "directories": { "type": "array", "items": { "type": "string" } }, "globs": { "type": "array", "items": { "type": "string" } }, "branches": { "type": "array", "items": { "type": "string" } } }, "required": ["repository", "directories", "globs", "branches"], "additionalProperties": {} }, "time": { "type": "object", "properties": { "effectiveFrom": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "effectiveUntil": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "additionalProperties": {} }, "users": { "type": "array", "items": { "oneOf": [{ "type": "object", "properties": { "kind": { "type": "string", "const": "user" }, "userId": { "type": "string", "minLength": 1 } }, "required": ["kind", "userId"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "role" }, "role": { "type": "string", "enum": ["owner", "admin", "member"] } }, "required": ["kind", "role"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "agent" }, "agent": { "type": "string", "enum": ["claude_code", "codex", "hermes"] } }, "required": ["kind", "agent"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "credential" }, "credential": { "type": "string", "enum": ["workos_jwt", "workos_api_key", "service_token"] } }, "required": ["kind", "credential"], "additionalProperties": false }] } } }, "required": ["location", "time", "users"], "additionalProperties": {} }, "scopeWarnings": { "type": "array", "items": { "type": "string" } } }, "required": ["decisionId", "shortId", "createdAt"], "additionalProperties": {} };
|
|
12241
|
+
var schema47 = { "type": "object", "properties": { "decisionId": { "type": "string", "minLength": 1 }, "shortId": { "type": "string" }, "createdAt": { "type": "number" }, "scope": { "type": "object", "properties": { "location": { "type": "object", "properties": { "repository": { "type": "boolean" }, "directories": { "type": "array", "items": { "type": "string" } }, "globs": { "type": "array", "items": { "type": "string" } }, "branches": { "type": "array", "items": { "type": "string" } } }, "required": ["repository", "directories", "globs", "branches"], "additionalProperties": {} }, "time": { "type": "object", "properties": { "effectiveFrom": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "effectiveUntil": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "additionalProperties": {} }, "users": { "type": "array", "items": { "oneOf": [{ "type": "object", "properties": { "kind": { "type": "string", "const": "user" }, "userId": { "type": "string", "minLength": 1 } }, "required": ["kind", "userId"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "role" }, "role": { "type": "string", "enum": ["owner", "admin", "member"] } }, "required": ["kind", "role"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "agent" }, "agent": { "type": "string", "enum": ["claude_code", "codex", "cursor", "hermes"] } }, "required": ["kind", "agent"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "credential" }, "credential": { "type": "string", "enum": ["workos_jwt", "workos_api_key", "service_token"] } }, "required": ["kind", "credential"], "additionalProperties": false }] } } }, "required": ["location", "time", "users"], "additionalProperties": {} }, "scopeWarnings": { "type": "array", "items": { "type": "string" } } }, "required": ["decisionId", "shortId", "createdAt"], "additionalProperties": {} };
|
|
11792
12242
|
function validate28(data, { instancePath = "", parentData, parentDataProperty, rootData = data, dynamicAnchors = {} } = {}) {
|
|
11793
12243
|
;
|
|
11794
12244
|
let vErrors = null;
|
|
@@ -12324,7 +12774,7 @@ function validate28(data, { instancePath = "", parentData, parentDataProperty, r
|
|
|
12324
12774
|
}
|
|
12325
12775
|
errors++;
|
|
12326
12776
|
}
|
|
12327
|
-
if (!(data22 === "claude_code" || data22 === "codex" || data22 === "hermes")) {
|
|
12777
|
+
if (!(data22 === "claude_code" || data22 === "codex" || data22 === "cursor" || data22 === "hermes")) {
|
|
12328
12778
|
const err19 = { instancePath: instancePath + "/scope/users/" + i3 + "/agent", schemaPath: "https://api.getprimitive.ai/contracts/cli-http-v1.schema.json#/$defs/DecisionCreateResponse/properties/scope/properties/users/items/oneOf/2/properties/agent/enum", keyword: "enum", params: { allowedValues: schema47.properties.scope.properties.users.items.oneOf[2].properties.agent.enum }, message: "must be equal to one of the allowed values" };
|
|
12329
12779
|
if (vErrors === null) {
|
|
12330
12780
|
vErrors = [err19];
|
|
@@ -12556,7 +13006,7 @@ function validate28(data, { instancePath = "", parentData, parentDataProperty, r
|
|
|
12556
13006
|
return errors === 0;
|
|
12557
13007
|
}
|
|
12558
13008
|
validate28.evaluated = { "props": true, "dynamicProps": false, "dynamicItems": false };
|
|
12559
|
-
var schema49 = { "type": "object", "properties": { "decision": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1 }, "shortId": { "type": "string" }, "intent": { "type": "string" }, "intentKind": { "type": "string", "enum": ["change", "exploration", "task_execution", "unclear"] }, "rationale": { "type": "string" }, "decided": { "type": "array", "items": { "type": "string" } }, "alternatives": { "type": "array", "items": { "type": "string" } }, "area": { "type": "string" }, "producerKind": { "type": "string" }, "stage": { "type": "string", "enum": ["draft", "provisional", "adopted", "superseded", "abandoned"] }, "status": { "type": "string", "enum": ["active", "superseded", "under_review"] }, "supersededBy": { "anyOf": [{ "type": "string", "minLength": 1 }, { "type": "null" }] }, "confidence": { "type": "string", "enum": ["high", "medium", "low"] }, "reversibility": { "type": "string", "enum": ["high", "low"] }, "confirmed": { "type": "boolean" }, "respondedAt": { "type": "number" }, "fanOut": { "type": "number" }, "classifiedAt": { "type": "number" }, "authorName": { "type": "string" } }, "required": ["id", "intent", "intentKind", "alternatives", "stage", "status", "supersededBy", "confidence", "classifiedAt", "authorName"], "additionalProperties": {} }, "files": { "type": "array", "items": { "type": "string" } }, "flags": { "type": "array", "items": { "type": "object", "properties": { "type": { "type": "string", "enum": ["file_edit", "supersession", "invalidation", "confirmation_request"] }, "file": { "type": "string" }, "flaggedAt": { "type": "number" }, "acknowledgedAt": { "type": "number" }, "gateVerdict": { "type": "string" }, "reason": { "type": "string" } }, "required": ["type", "flaggedAt"], "additionalProperties": {} } }, "dependsOn": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1 }, "shortId": { "type": "string" }, "intent": { "type": "string" }, "area": { "type": "string" }, "authorName": { "type": "string" }, "classifiedAt": { "type": "number" }, "status": { "type": "string", "enum": ["active", "superseded", "under_review"] } }, "required": ["id", "intent", "authorName", "classifiedAt", "status"], "additionalProperties": {} } }, "dependents": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1 }, "shortId": { "type": "string" }, "intent": { "type": "string" }, "area": { "type": "string" }, "authorName": { "type": "string" }, "classifiedAt": { "type": "number" }, "status": { "type": "string", "enum": ["active", "superseded", "under_review"] } }, "required": ["id", "intent", "authorName", "classifiedAt", "status"], "additionalProperties": {} } }, "scope": { "type": "object", "properties": { "location": { "type": "object", "properties": { "repository": { "type": "boolean" }, "directories": { "type": "array", "items": { "type": "string" } }, "globs": { "type": "array", "items": { "type": "string" } }, "branches": { "type": "array", "items": { "type": "string" } } }, "required": ["repository", "directories", "globs", "branches"], "additionalProperties": {} }, "time": { "type": "object", "properties": { "effectiveFrom": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "effectiveUntil": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "additionalProperties": {} }, "users": { "type": "array", "items": { "oneOf": [{ "type": "object", "properties": { "kind": { "type": "string", "const": "user" }, "userId": { "type": "string", "minLength": 1 }, "displayName": { "type": "string" } }, "required": ["kind", "userId", "displayName"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "role" }, "role": { "type": "string", "enum": ["owner", "admin", "member"] } }, "required": ["kind", "role"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "agent" }, "agent": { "type": "string", "enum": ["claude_code", "codex", "hermes"] } }, "required": ["kind", "agent"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "credential" }, "credential": { "type": "string", "enum": ["workos_jwt", "workos_api_key", "service_token"] } }, "required": ["kind", "credential"], "additionalProperties": false }] } } }, "required": ["location", "time", "users"], "additionalProperties": {} }, "truncated": { "type": "boolean" } }, "required": ["decision", "files", "flags", "dependsOn", "dependents", "scope", "truncated"], "additionalProperties": {} };
|
|
13009
|
+
var schema49 = { "type": "object", "properties": { "decision": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1 }, "shortId": { "type": "string" }, "intent": { "type": "string" }, "intentKind": { "type": "string", "enum": ["change", "exploration", "task_execution", "unclear"] }, "rationale": { "type": "string" }, "decided": { "type": "array", "items": { "type": "string" } }, "alternatives": { "type": "array", "items": { "type": "string" } }, "area": { "type": "string" }, "producerKind": { "type": "string" }, "stage": { "type": "string", "enum": ["draft", "provisional", "adopted", "superseded", "abandoned"] }, "status": { "type": "string", "enum": ["active", "superseded", "under_review"] }, "supersededBy": { "anyOf": [{ "type": "string", "minLength": 1 }, { "type": "null" }] }, "confidence": { "type": "string", "enum": ["high", "medium", "low"] }, "reversibility": { "type": "string", "enum": ["high", "low"] }, "confirmed": { "type": "boolean" }, "respondedAt": { "type": "number" }, "fanOut": { "type": "number" }, "classifiedAt": { "type": "number" }, "authorName": { "type": "string" } }, "required": ["id", "intent", "intentKind", "alternatives", "stage", "status", "supersededBy", "confidence", "classifiedAt", "authorName"], "additionalProperties": {} }, "files": { "type": "array", "items": { "type": "string" } }, "flags": { "type": "array", "items": { "type": "object", "properties": { "type": { "type": "string", "enum": ["file_edit", "supersession", "invalidation", "confirmation_request"] }, "file": { "type": "string" }, "flaggedAt": { "type": "number" }, "acknowledgedAt": { "type": "number" }, "gateVerdict": { "type": "string" }, "reason": { "type": "string" } }, "required": ["type", "flaggedAt"], "additionalProperties": {} } }, "dependsOn": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1 }, "shortId": { "type": "string" }, "intent": { "type": "string" }, "area": { "type": "string" }, "authorName": { "type": "string" }, "classifiedAt": { "type": "number" }, "status": { "type": "string", "enum": ["active", "superseded", "under_review"] } }, "required": ["id", "intent", "authorName", "classifiedAt", "status"], "additionalProperties": {} } }, "dependents": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1 }, "shortId": { "type": "string" }, "intent": { "type": "string" }, "area": { "type": "string" }, "authorName": { "type": "string" }, "classifiedAt": { "type": "number" }, "status": { "type": "string", "enum": ["active", "superseded", "under_review"] } }, "required": ["id", "intent", "authorName", "classifiedAt", "status"], "additionalProperties": {} } }, "scope": { "type": "object", "properties": { "location": { "type": "object", "properties": { "repository": { "type": "boolean" }, "directories": { "type": "array", "items": { "type": "string" } }, "globs": { "type": "array", "items": { "type": "string" } }, "branches": { "type": "array", "items": { "type": "string" } } }, "required": ["repository", "directories", "globs", "branches"], "additionalProperties": {} }, "time": { "type": "object", "properties": { "effectiveFrom": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "effectiveUntil": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "additionalProperties": {} }, "users": { "type": "array", "items": { "oneOf": [{ "type": "object", "properties": { "kind": { "type": "string", "const": "user" }, "userId": { "type": "string", "minLength": 1 }, "displayName": { "type": "string" } }, "required": ["kind", "userId", "displayName"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "role" }, "role": { "type": "string", "enum": ["owner", "admin", "member"] } }, "required": ["kind", "role"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "agent" }, "agent": { "type": "string", "enum": ["claude_code", "codex", "cursor", "hermes"] } }, "required": ["kind", "agent"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "credential" }, "credential": { "type": "string", "enum": ["workos_jwt", "workos_api_key", "service_token"] } }, "required": ["kind", "credential"], "additionalProperties": false }] } } }, "required": ["location", "time", "users"], "additionalProperties": {} }, "truncated": { "type": "boolean" } }, "required": ["decision", "files", "flags", "dependsOn", "dependents", "scope", "truncated"], "additionalProperties": {} };
|
|
12560
13010
|
function validate29(data, { instancePath = "", parentData, parentDataProperty, rootData = data, dynamicAnchors = {} } = {}) {
|
|
12561
13011
|
;
|
|
12562
13012
|
let vErrors = null;
|
|
@@ -13850,7 +14300,7 @@ function validate29(data, { instancePath = "", parentData, parentDataProperty, r
|
|
|
13850
14300
|
}
|
|
13851
14301
|
errors++;
|
|
13852
14302
|
}
|
|
13853
|
-
if (!(data70 === "claude_code" || data70 === "codex" || data70 === "hermes")) {
|
|
14303
|
+
if (!(data70 === "claude_code" || data70 === "codex" || data70 === "cursor" || data70 === "hermes")) {
|
|
13854
14304
|
const err24 = { instancePath: instancePath + "/scope/users/" + i9 + "/agent", schemaPath: "https://api.getprimitive.ai/contracts/cli-http-v1.schema.json#/$defs/DecisionDetailResponse/properties/scope/properties/users/items/oneOf/2/properties/agent/enum", keyword: "enum", params: { allowedValues: schema49.properties.scope.properties.users.items.oneOf[2].properties.agent.enum }, message: "must be equal to one of the allowed values" };
|
|
13855
14305
|
if (vErrors === null) {
|
|
13856
14306
|
vErrors = [err24];
|
|
@@ -14411,7 +14861,7 @@ function validate33(data, { instancePath = "", parentData, parentDataProperty, r
|
|
|
14411
14861
|
return errors === 0;
|
|
14412
14862
|
}
|
|
14413
14863
|
validate33.evaluated = { "props": true, "dynamicProps": false, "dynamicItems": false };
|
|
14414
|
-
var schema59 = { "type": "object", "properties": { "id": { "type": "string" }, "location": { "anyOf": [{ "default": {}, "type": "object", "properties": { "repository": { "type": "boolean" }, "directories": { "type": "array", "items": { "type": "string" } }, "globs": { "type": "array", "items": { "type": "string" } }, "branches": { "type": "array", "items": { "type": "string" } } }, "additionalProperties": {} }, { "type": "null" }] }, "time": { "anyOf": [{ "default": {}, "type": "object", "properties": { "effectiveFrom": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "effectiveUntil": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "additionalProperties": {} }, { "type": "null" }] }, "users": { "anyOf": [{ "type": "array", "items": { "oneOf": [{ "type": "object", "properties": { "kind": { "type": "string", "const": "user" }, "userId": { "type": "string", "minLength": 1 } }, "required": ["kind", "userId"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "role" }, "role": { "type": "string", "enum": ["owner", "admin", "member"] } }, "required": ["kind", "role"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "agent" }, "agent": { "type": "string", "enum": ["claude_code", "codex", "hermes"] } }, "required": ["kind", "agent"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "credential" }, "credential": { "type": "string", "enum": ["workos_jwt", "workos_api_key", "service_token"] } }, "required": ["kind", "credential"], "additionalProperties": false }] } }, { "type": "null" }] } }, "required": ["id"], "additionalProperties": {} };
|
|
14864
|
+
var schema59 = { "type": "object", "properties": { "id": { "type": "string" }, "location": { "anyOf": [{ "default": {}, "type": "object", "properties": { "repository": { "type": "boolean" }, "directories": { "type": "array", "items": { "type": "string" } }, "globs": { "type": "array", "items": { "type": "string" } }, "branches": { "type": "array", "items": { "type": "string" } } }, "additionalProperties": {} }, { "type": "null" }] }, "time": { "anyOf": [{ "default": {}, "type": "object", "properties": { "effectiveFrom": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "effectiveUntil": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "additionalProperties": {} }, { "type": "null" }] }, "users": { "anyOf": [{ "type": "array", "items": { "oneOf": [{ "type": "object", "properties": { "kind": { "type": "string", "const": "user" }, "userId": { "type": "string", "minLength": 1 } }, "required": ["kind", "userId"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "role" }, "role": { "type": "string", "enum": ["owner", "admin", "member"] } }, "required": ["kind", "role"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "agent" }, "agent": { "type": "string", "enum": ["claude_code", "codex", "cursor", "hermes"] } }, "required": ["kind", "agent"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "credential" }, "credential": { "type": "string", "enum": ["workos_jwt", "workos_api_key", "service_token"] } }, "required": ["kind", "credential"], "additionalProperties": false }] } }, { "type": "null" }] } }, "required": ["id"], "additionalProperties": {} };
|
|
14415
14865
|
function validate34(data, { instancePath = "", parentData, parentDataProperty, rootData = data, dynamicAnchors = {} } = {}) {
|
|
14416
14866
|
;
|
|
14417
14867
|
let vErrors = null;
|
|
@@ -15052,7 +15502,7 @@ function validate34(data, { instancePath = "", parentData, parentDataProperty, r
|
|
|
15052
15502
|
}
|
|
15053
15503
|
errors++;
|
|
15054
15504
|
}
|
|
15055
|
-
if (!(data19 === "claude_code" || data19 === "codex" || data19 === "hermes")) {
|
|
15505
|
+
if (!(data19 === "claude_code" || data19 === "codex" || data19 === "cursor" || data19 === "hermes")) {
|
|
15056
15506
|
const err38 = { instancePath: instancePath + "/users/" + i3 + "/agent", schemaPath: "https://api.getprimitive.ai/contracts/cli-http-v1.schema.json#/$defs/DecisionRescopeRequest/properties/users/anyOf/0/items/oneOf/2/properties/agent/enum", keyword: "enum", params: { allowedValues: schema59.properties.users.anyOf[0].items.oneOf[2].properties.agent.enum }, message: "must be equal to one of the allowed values" };
|
|
15057
15507
|
if (vErrors === null) {
|
|
15058
15508
|
vErrors = [err38];
|
|
@@ -15280,7 +15730,7 @@ function validate34(data, { instancePath = "", parentData, parentDataProperty, r
|
|
|
15280
15730
|
return errors === 0;
|
|
15281
15731
|
}
|
|
15282
15732
|
validate34.evaluated = { "props": true, "dynamicProps": false, "dynamicItems": false };
|
|
15283
|
-
var schema61 = { "anyOf": [{ "type": "object", "properties": { "outcome": { "type": "string", "const": "no_op" }, "stage": { "type": "string", "enum": ["draft", "provisional", "adopted", "superseded", "abandoned"] }, "scope": { "type": "object", "properties": { "location": { "type": "object", "properties": { "repository": { "type": "boolean" }, "directories": { "type": "array", "items": { "type": "string" } }, "globs": { "type": "array", "items": { "type": "string" } }, "branches": { "type": "array", "items": { "type": "string" } } }, "required": ["repository", "directories", "globs", "branches"], "additionalProperties": {} }, "time": { "type": "object", "properties": { "effectiveFrom": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "effectiveUntil": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "additionalProperties": {} }, "users": { "type": "array", "items": { "oneOf": [{ "type": "object", "properties": { "kind": { "type": "string", "const": "user" }, "userId": { "type": "string", "minLength": 1 } }, "required": ["kind", "userId"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "role" }, "role": { "type": "string", "enum": ["owner", "admin", "member"] } }, "required": ["kind", "role"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "agent" }, "agent": { "type": "string", "enum": ["claude_code", "codex", "hermes"] } }, "required": ["kind", "agent"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "credential" }, "credential": { "type": "string", "enum": ["workos_jwt", "workos_api_key", "service_token"] } }, "required": ["kind", "credential"], "additionalProperties": false }] } } }, "required": ["location", "time", "users"], "additionalProperties": {} }, "scopeWarnings": { "type": "array", "items": { "type": "string" } } }, "required": ["outcome", "stage", "scope"], "additionalProperties": {} }, { "type": "object", "properties": { "outcome": { "type": "string", "const": "ok" }, "decisionId": { "type": "string", "minLength": 1 }, "shortId": { "type": "string" }, "stage": { "type": "string", "enum": ["draft", "provisional", "adopted", "superseded", "abandoned"] }, "scope": { "type": "object", "properties": { "location": { "type": "object", "properties": { "repository": { "type": "boolean" }, "directories": { "type": "array", "items": { "type": "string" } }, "globs": { "type": "array", "items": { "type": "string" } }, "branches": { "type": "array", "items": { "type": "string" } } }, "required": ["repository", "directories", "globs", "branches"], "additionalProperties": {} }, "time": { "type": "object", "properties": { "effectiveFrom": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "effectiveUntil": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "additionalProperties": {} }, "users": { "type": "array", "items": { "oneOf": [{ "type": "object", "properties": { "kind": { "type": "string", "const": "user" }, "userId": { "type": "string", "minLength": 1 } }, "required": ["kind", "userId"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "role" }, "role": { "type": "string", "enum": ["owner", "admin", "member"] } }, "required": ["kind", "role"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "agent" }, "agent": { "type": "string", "enum": ["claude_code", "codex", "hermes"] } }, "required": ["kind", "agent"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "credential" }, "credential": { "type": "string", "enum": ["workos_jwt", "workos_api_key", "service_token"] } }, "required": ["kind", "credential"], "additionalProperties": false }] } } }, "required": ["location", "time", "users"], "additionalProperties": {} }, "scopeWarnings": { "type": "array", "items": { "type": "string" } } }, "required": ["outcome", "decisionId", "stage", "scope"], "additionalProperties": {} }] };
|
|
15733
|
+
var schema61 = { "anyOf": [{ "type": "object", "properties": { "outcome": { "type": "string", "const": "no_op" }, "stage": { "type": "string", "enum": ["draft", "provisional", "adopted", "superseded", "abandoned"] }, "scope": { "type": "object", "properties": { "location": { "type": "object", "properties": { "repository": { "type": "boolean" }, "directories": { "type": "array", "items": { "type": "string" } }, "globs": { "type": "array", "items": { "type": "string" } }, "branches": { "type": "array", "items": { "type": "string" } } }, "required": ["repository", "directories", "globs", "branches"], "additionalProperties": {} }, "time": { "type": "object", "properties": { "effectiveFrom": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "effectiveUntil": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "additionalProperties": {} }, "users": { "type": "array", "items": { "oneOf": [{ "type": "object", "properties": { "kind": { "type": "string", "const": "user" }, "userId": { "type": "string", "minLength": 1 } }, "required": ["kind", "userId"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "role" }, "role": { "type": "string", "enum": ["owner", "admin", "member"] } }, "required": ["kind", "role"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "agent" }, "agent": { "type": "string", "enum": ["claude_code", "codex", "cursor", "hermes"] } }, "required": ["kind", "agent"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "credential" }, "credential": { "type": "string", "enum": ["workos_jwt", "workos_api_key", "service_token"] } }, "required": ["kind", "credential"], "additionalProperties": false }] } } }, "required": ["location", "time", "users"], "additionalProperties": {} }, "scopeWarnings": { "type": "array", "items": { "type": "string" } } }, "required": ["outcome", "stage", "scope"], "additionalProperties": {} }, { "type": "object", "properties": { "outcome": { "type": "string", "const": "ok" }, "decisionId": { "type": "string", "minLength": 1 }, "shortId": { "type": "string" }, "stage": { "type": "string", "enum": ["draft", "provisional", "adopted", "superseded", "abandoned"] }, "scope": { "type": "object", "properties": { "location": { "type": "object", "properties": { "repository": { "type": "boolean" }, "directories": { "type": "array", "items": { "type": "string" } }, "globs": { "type": "array", "items": { "type": "string" } }, "branches": { "type": "array", "items": { "type": "string" } } }, "required": ["repository", "directories", "globs", "branches"], "additionalProperties": {} }, "time": { "type": "object", "properties": { "effectiveFrom": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "effectiveUntil": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "additionalProperties": {} }, "users": { "type": "array", "items": { "oneOf": [{ "type": "object", "properties": { "kind": { "type": "string", "const": "user" }, "userId": { "type": "string", "minLength": 1 } }, "required": ["kind", "userId"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "role" }, "role": { "type": "string", "enum": ["owner", "admin", "member"] } }, "required": ["kind", "role"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "agent" }, "agent": { "type": "string", "enum": ["claude_code", "codex", "cursor", "hermes"] } }, "required": ["kind", "agent"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "credential" }, "credential": { "type": "string", "enum": ["workos_jwt", "workos_api_key", "service_token"] } }, "required": ["kind", "credential"], "additionalProperties": false }] } } }, "required": ["location", "time", "users"], "additionalProperties": {} }, "scopeWarnings": { "type": "array", "items": { "type": "string" } } }, "required": ["outcome", "decisionId", "stage", "scope"], "additionalProperties": {} }] };
|
|
15284
15734
|
function validate35(data, { instancePath = "", parentData, parentDataProperty, rootData = data, dynamicAnchors = {} } = {}) {
|
|
15285
15735
|
;
|
|
15286
15736
|
let vErrors = null;
|
|
@@ -15918,7 +16368,7 @@ function validate35(data, { instancePath = "", parentData, parentDataProperty, r
|
|
|
15918
16368
|
}
|
|
15919
16369
|
errors++;
|
|
15920
16370
|
}
|
|
15921
|
-
if (!(data21 === "claude_code" || data21 === "codex" || data21 === "hermes")) {
|
|
16371
|
+
if (!(data21 === "claude_code" || data21 === "codex" || data21 === "cursor" || data21 === "hermes")) {
|
|
15922
16372
|
const err41 = { instancePath: instancePath + "/scope/users/" + i3 + "/agent", schemaPath: "https://api.getprimitive.ai/contracts/cli-http-v1.schema.json#/$defs/DecisionRescopeResponse/anyOf/0/properties/scope/properties/users/items/oneOf/2/properties/agent/enum", keyword: "enum", params: { allowedValues: schema61.anyOf[0].properties.scope.properties.users.items.oneOf[2].properties.agent.enum }, message: "must be equal to one of the allowed values" };
|
|
15923
16373
|
if (vErrors === null) {
|
|
15924
16374
|
vErrors = [err41];
|
|
@@ -16842,7 +17292,7 @@ function validate35(data, { instancePath = "", parentData, parentDataProperty, r
|
|
|
16842
17292
|
}
|
|
16843
17293
|
errors++;
|
|
16844
17294
|
}
|
|
16845
|
-
if (!(data49 === "claude_code" || data49 === "codex" || data49 === "hermes")) {
|
|
17295
|
+
if (!(data49 === "claude_code" || data49 === "codex" || data49 === "cursor" || data49 === "hermes")) {
|
|
16846
17296
|
const err100 = { instancePath: instancePath + "/scope/users/" + i8 + "/agent", schemaPath: "https://api.getprimitive.ai/contracts/cli-http-v1.schema.json#/$defs/DecisionRescopeResponse/anyOf/1/properties/scope/properties/users/items/oneOf/2/properties/agent/enum", keyword: "enum", params: { allowedValues: schema61.anyOf[1].properties.scope.properties.users.items.oneOf[2].properties.agent.enum }, message: "must be equal to one of the allowed values" };
|
|
16847
17297
|
if (vErrors === null) {
|
|
16848
17298
|
vErrors = [err100];
|
|
@@ -22488,7 +22938,7 @@ function validate50(data, { instancePath = "", parentData, parentDataProperty, r
|
|
|
22488
22938
|
return errors === 0;
|
|
22489
22939
|
}
|
|
22490
22940
|
validate50.evaluated = { "dynamicProps": true, "dynamicItems": false };
|
|
22491
|
-
var schema93 = { "type": "object", "properties": { "batch": { "type": "array", "items": { "anyOf": [{ "type": "object", "properties": { "moveId": { "type": "string" }, "capturedAt": { "type": "number" }, "sessionId": { "type": "string" }, "invocationId": { "type": "string" }, "eventType": { "type": "string" }, "payload": {}, "env": {}, "capturedOrganizationId": { "type": "string", "minLength": 1, "maxLength": 128, "pattern": "^[A-Za-z0-9_-]+$" }, "captureAuthorityKind": { "type": "string", "enum": ["workos", "service_token"] }, "decisionLifecycleProtocolVersion": { "type": "integer", "minimum": 1, "maximum": 9007199254740991 }, "producer": { "type": "string", "enum": ["claude_code", "codex", "hermes"] }, "toolOutcome": { "type": "string", "enum": ["succeeded", "returned", "failed", "interrupted", "prevented", "unknown"] }, "envelopeVersion": { "type": "number", "const": 4 } }, "required": ["moveId", "capturedAt", "sessionId", "eventType", "capturedOrganizationId", "captureAuthorityKind", "decisionLifecycleProtocolVersion", "envelopeVersion"], "additionalProperties": {} }, { "type": "object", "properties": { "moveId": { "type": "string" }, "capturedAt": { "type": "number" }, "sessionId": { "type": "string" }, "invocationId": { "type": "string" }, "eventType": { "type": "string" }, "payload": {}, "env": {}, "capturedOrganizationId": { "type": "string", "minLength": 1, "maxLength": 128, "pattern": "^[A-Za-z0-9_-]+$" }, "captureAuthorityKind": { "type": "string", "enum": ["workos", "service_token"] }, "decisionLifecycleProtocolVersion": { "type": "integer", "minimum": 1, "maximum": 9007199254740991 }, "producer": { "type": "string", "enum": ["claude_code", "codex", "hermes"] }, "toolOutcome": { "type": "string", "enum": ["succeeded", "returned", "failed", "interrupted", "prevented", "unknown"] }, "envelopeVersion": { "type": "number", "exclusiveMaximum": 4 } }, "required": ["moveId", "capturedAt", "sessionId", "eventType"], "additionalProperties": {} }] } } }, "required": ["batch"], "additionalProperties": {} };
|
|
22941
|
+
var schema93 = { "type": "object", "properties": { "batch": { "type": "array", "items": { "anyOf": [{ "type": "object", "properties": { "moveId": { "type": "string" }, "capturedAt": { "type": "number" }, "sessionId": { "type": "string" }, "invocationId": { "type": "string" }, "eventType": { "type": "string" }, "payload": {}, "env": {}, "capturedOrganizationId": { "type": "string", "minLength": 1, "maxLength": 128, "pattern": "^[A-Za-z0-9_-]+$" }, "captureAuthorityKind": { "type": "string", "enum": ["workos", "service_token"] }, "decisionLifecycleProtocolVersion": { "type": "integer", "minimum": 1, "maximum": 9007199254740991 }, "producer": { "type": "string", "enum": ["claude_code", "codex", "cursor", "hermes"] }, "toolOutcome": { "type": "string", "enum": ["succeeded", "returned", "failed", "interrupted", "prevented", "unknown"] }, "envelopeVersion": { "type": "number", "const": 4 } }, "required": ["moveId", "capturedAt", "sessionId", "eventType", "capturedOrganizationId", "captureAuthorityKind", "decisionLifecycleProtocolVersion", "envelopeVersion"], "additionalProperties": {} }, { "type": "object", "properties": { "moveId": { "type": "string" }, "capturedAt": { "type": "number" }, "sessionId": { "type": "string" }, "invocationId": { "type": "string" }, "eventType": { "type": "string" }, "payload": {}, "env": {}, "capturedOrganizationId": { "type": "string", "minLength": 1, "maxLength": 128, "pattern": "^[A-Za-z0-9_-]+$" }, "captureAuthorityKind": { "type": "string", "enum": ["workos", "service_token"] }, "decisionLifecycleProtocolVersion": { "type": "integer", "minimum": 1, "maximum": 9007199254740991 }, "producer": { "type": "string", "enum": ["claude_code", "codex", "cursor", "hermes"] }, "toolOutcome": { "type": "string", "enum": ["succeeded", "returned", "failed", "interrupted", "prevented", "unknown"] }, "envelopeVersion": { "type": "number", "exclusiveMaximum": 4 } }, "required": ["moveId", "capturedAt", "sessionId", "eventType"], "additionalProperties": {} }] } } }, "required": ["batch"], "additionalProperties": {} };
|
|
22492
22942
|
var pattern8 = new RegExp("^[A-Za-z0-9_-]+$", "u");
|
|
22493
22943
|
function validate51(data, { instancePath = "", parentData, parentDataProperty, rootData = data, dynamicAnchors = {} } = {}) {
|
|
22494
22944
|
;
|
|
@@ -22742,7 +23192,7 @@ function validate51(data, { instancePath = "", parentData, parentDataProperty, r
|
|
|
22742
23192
|
}
|
|
22743
23193
|
errors++;
|
|
22744
23194
|
}
|
|
22745
|
-
if (!(data10 === "claude_code" || data10 === "codex" || data10 === "hermes")) {
|
|
23195
|
+
if (!(data10 === "claude_code" || data10 === "codex" || data10 === "cursor" || data10 === "hermes")) {
|
|
22746
23196
|
const err16 = { instancePath: instancePath + "/batch/" + i0 + "/producer", schemaPath: "https://api.getprimitive.ai/contracts/cli-http-v1.schema.json#/$defs/MoveIngestRequest/properties/batch/items/anyOf/0/properties/producer/enum", keyword: "enum", params: { allowedValues: schema93.properties.batch.items.anyOf[0].properties.producer.enum }, message: "must be equal to one of the allowed values" };
|
|
22747
23197
|
if (vErrors === null) {
|
|
22748
23198
|
vErrors = [err16];
|
|
@@ -23054,7 +23504,7 @@ function validate51(data, { instancePath = "", parentData, parentDataProperty, r
|
|
|
23054
23504
|
}
|
|
23055
23505
|
errors++;
|
|
23056
23506
|
}
|
|
23057
|
-
if (!(data21 === "claude_code" || data21 === "codex" || data21 === "hermes")) {
|
|
23507
|
+
if (!(data21 === "claude_code" || data21 === "codex" || data21 === "cursor" || data21 === "hermes")) {
|
|
23058
23508
|
const err38 = { instancePath: instancePath + "/batch/" + i0 + "/producer", schemaPath: "https://api.getprimitive.ai/contracts/cli-http-v1.schema.json#/$defs/MoveIngestRequest/properties/batch/items/anyOf/1/properties/producer/enum", keyword: "enum", params: { allowedValues: schema93.properties.batch.items.anyOf[1].properties.producer.enum }, message: "must be equal to one of the allowed values" };
|
|
23059
23509
|
if (vErrors === null) {
|
|
23060
23510
|
vErrors = [err38];
|
|
@@ -23191,7 +23641,7 @@ function validate51(data, { instancePath = "", parentData, parentDataProperty, r
|
|
|
23191
23641
|
return errors === 0;
|
|
23192
23642
|
}
|
|
23193
23643
|
validate51.evaluated = { "props": true, "dynamicProps": false, "dynamicItems": false };
|
|
23194
|
-
var schema95 = { "type": "object", "properties": { "protocolVersion": { "type": "number", "const": 3 }, "agent": { "type": "string", "enum": ["claude_code", "codex", "hermes"] }, "sessionId": { "type": "string", "pattern": "^[A-Za-z0-9._:-]{1,128}$" }, "invocationId": { "type": "string", "pattern": "^[A-Za-z0-9._:-]{1,128}$" }, "repoSyncId": { "type": "string", "pattern": "^[A-Za-z0-9]{1,64}$" }, "paths": { "maxItems": 32, "type": "array", "items": { "type": "string" } }, "coverage": { "type": "string", "enum": ["complete", "unverified"] }, "branch": { "type": "string", "maxLength": 255, "pattern": "^(?!@?$)(?!\\/)(?!.*\\/$)(?!.*\\/\\/)(?!.*(?:^|\\/)\\.{1,2}(?:\\/|$))(?!.*(?:^|\\/)[^/]*\\.lock(?:\\/|$))(?!.*\\.\\.)(?!.*@\\{)(?!.*[~^:?*\\\\]).+$" }, "clientMode": { "type": "string", "enum": ["block", "warn"] }, "clientVersion": { "type": "string", "maxLength": 32, "pattern": "^[A-Za-z0-9][A-Za-z0-9._+-]*$" }, "proposal": { "type": "string" } }, "required": ["protocolVersion", "agent", "sessionId", "invocationId", "repoSyncId", "paths", "coverage", "proposal"], "additionalProperties": false, "x-primitive-runtime-refinements": ["canonical_repository_paths", "unique_repository_paths", "complete_coverage_requires_path", "proposal_utf8_max_6144", "degrade_invalid_rollout_fields", "degrade_invalid_branch"] };
|
|
23644
|
+
var schema95 = { "type": "object", "properties": { "protocolVersion": { "type": "number", "const": 3 }, "agent": { "type": "string", "enum": ["claude_code", "codex", "cursor", "hermes"] }, "sessionId": { "type": "string", "pattern": "^[A-Za-z0-9._:-]{1,128}$" }, "invocationId": { "type": "string", "pattern": "^[A-Za-z0-9._:-]{1,128}$" }, "repoSyncId": { "type": "string", "pattern": "^[A-Za-z0-9]{1,64}$" }, "paths": { "maxItems": 32, "type": "array", "items": { "type": "string" } }, "coverage": { "type": "string", "enum": ["complete", "unverified"] }, "branch": { "type": "string", "maxLength": 255, "pattern": "^(?!@?$)(?!\\/)(?!.*\\/$)(?!.*\\/\\/)(?!.*(?:^|\\/)\\.{1,2}(?:\\/|$))(?!.*(?:^|\\/)[^/]*\\.lock(?:\\/|$))(?!.*\\.\\.)(?!.*@\\{)(?!.*[~^:?*\\\\]).+$" }, "clientMode": { "type": "string", "enum": ["block", "warn"] }, "clientVersion": { "type": "string", "maxLength": 32, "pattern": "^[A-Za-z0-9][A-Za-z0-9._+-]*$" }, "proposal": { "type": "string" } }, "required": ["protocolVersion", "agent", "sessionId", "invocationId", "repoSyncId", "paths", "coverage", "proposal"], "additionalProperties": false, "x-primitive-runtime-refinements": ["canonical_repository_paths", "unique_repository_paths", "complete_coverage_requires_path", "proposal_utf8_max_6144", "degrade_invalid_rollout_fields", "degrade_invalid_branch"] };
|
|
23195
23645
|
var pattern10 = new RegExp("^[A-Za-z0-9._:-]{1,128}$", "u");
|
|
23196
23646
|
var pattern12 = new RegExp("^[A-Za-z0-9]{1,64}$", "u");
|
|
23197
23647
|
var pattern13 = new RegExp("^(?!@?$)(?!\\/)(?!.*\\/$)(?!.*\\/\\/)(?!.*(?:^|\\/)\\.{1,2}(?:\\/|$))(?!.*(?:^|\\/)[^/]*\\.lock(?:\\/|$))(?!.*\\.\\.)(?!.*@\\{)(?!.*[~^:?*\\\\]).+$", "u");
|
|
@@ -23247,7 +23697,7 @@ function validate52(data, { instancePath = "", parentData, parentDataProperty, r
|
|
|
23247
23697
|
validate52.errors = [{ instancePath: instancePath + "/agent", schemaPath: "https://api.getprimitive.ai/contracts/cli-http-v1.schema.json#/$defs/PreflightRequestV3/properties/agent/type", keyword: "type", params: { type: "string" }, message: "must be string" }];
|
|
23248
23698
|
return false;
|
|
23249
23699
|
}
|
|
23250
|
-
if (!(data1 === "claude_code" || data1 === "codex" || data1 === "hermes")) {
|
|
23700
|
+
if (!(data1 === "claude_code" || data1 === "codex" || data1 === "cursor" || data1 === "hermes")) {
|
|
23251
23701
|
validate52.errors = [{ instancePath: instancePath + "/agent", schemaPath: "https://api.getprimitive.ai/contracts/cli-http-v1.schema.json#/$defs/PreflightRequestV3/properties/agent/enum", keyword: "enum", params: { allowedValues: schema95.properties.agent.enum }, message: "must be equal to one of the allowed values" }];
|
|
23252
23702
|
return false;
|
|
23253
23703
|
}
|
|
@@ -26539,7 +26989,7 @@ function optionalUserScopeMembers(record) {
|
|
|
26539
26989
|
members.push({ kind: "role", role: candidate.role });
|
|
26540
26990
|
continue;
|
|
26541
26991
|
}
|
|
26542
|
-
if (candidate.kind === "agent" && (candidate.agent === "claude_code" || candidate.agent === "codex" || candidate.agent === "hermes")) {
|
|
26992
|
+
if (candidate.kind === "agent" && (candidate.agent === "claude_code" || candidate.agent === "codex" || candidate.agent === "cursor" || candidate.agent === "hermes")) {
|
|
26543
26993
|
members.push({ kind: "agent", agent: candidate.agent });
|
|
26544
26994
|
continue;
|
|
26545
26995
|
}
|
|
@@ -26629,22 +27079,22 @@ async function fetchAndCacheCollectScope(cwd, dependencies = defaultDependencies
|
|
|
26629
27079
|
|
|
26630
27080
|
// src/lib/post-commit-hook.ts
|
|
26631
27081
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
26632
|
-
import { createHash as
|
|
27082
|
+
import { createHash as createHash8, randomUUID as randomUUID2 } from "crypto";
|
|
26633
27083
|
import {
|
|
26634
|
-
constants as
|
|
27084
|
+
constants as constants5,
|
|
26635
27085
|
closeSync as closeSync4,
|
|
26636
|
-
existsSync as
|
|
27086
|
+
existsSync as existsSync10,
|
|
26637
27087
|
fchmodSync as fchmodSync2,
|
|
26638
27088
|
fsyncSync as fsyncSync2,
|
|
26639
|
-
lstatSync as
|
|
26640
|
-
mkdirSync as
|
|
27089
|
+
lstatSync as lstatSync5,
|
|
27090
|
+
mkdirSync as mkdirSync7,
|
|
26641
27091
|
openSync as openSync4,
|
|
26642
|
-
readFileSync as
|
|
26643
|
-
renameSync as
|
|
26644
|
-
unlinkSync,
|
|
26645
|
-
writeFileSync as
|
|
27092
|
+
readFileSync as readFileSync11,
|
|
27093
|
+
renameSync as renameSync3,
|
|
27094
|
+
unlinkSync as unlinkSync2,
|
|
27095
|
+
writeFileSync as writeFileSync4
|
|
26646
27096
|
} from "fs";
|
|
26647
|
-
import { basename as basename2, dirname as
|
|
27097
|
+
import { basename as basename2, dirname as dirname10, isAbsolute as isAbsolute7, resolve as resolve6 } from "path";
|
|
26648
27098
|
var PRIM_POST_COMMIT_BLOCK_START = "# >>> prim post-commit hook >>>";
|
|
26649
27099
|
var PRIM_POST_COMMIT_BLOCK_END = "# <<< prim post-commit hook <<<";
|
|
26650
27100
|
var PRIM_CREATED_MARK = "prim-created-post-commit-hook";
|
|
@@ -26790,7 +27240,7 @@ var SHELL_QUOTED_RE = /^'(?:[^']|'"'"')*'$/u;
|
|
|
26790
27240
|
function decodePinnedPath(token) {
|
|
26791
27241
|
if (!token || !SHELL_QUOTED_RE.test(token)) return void 0;
|
|
26792
27242
|
const value = token.slice(1, -1).replaceAll(`'"'"'`, "'");
|
|
26793
|
-
if (!
|
|
27243
|
+
if (!isAbsolute7(value) || value.includes("\0") || value.includes("\n") || value.includes("\r")) {
|
|
26794
27244
|
return void 0;
|
|
26795
27245
|
}
|
|
26796
27246
|
return value;
|
|
@@ -26835,7 +27285,7 @@ function safeGitPath(root, value) {
|
|
|
26835
27285
|
if (value.length === 0 || value !== value.trim() || value.includes("\0") || value.includes("\n") || value.includes("\r")) {
|
|
26836
27286
|
throw new Error("Git returned an unsafe hooks path");
|
|
26837
27287
|
}
|
|
26838
|
-
return
|
|
27288
|
+
return isAbsolute7(value) ? resolve6(value) : resolve6(root, value);
|
|
26839
27289
|
}
|
|
26840
27290
|
function resolveEffectiveManagedHook(spec, cwd = process.cwd()) {
|
|
26841
27291
|
const gitRoot = gitToplevel(cwd);
|
|
@@ -26847,19 +27297,19 @@ function resolveEffectiveManagedHook(spec, cwd = process.cwd()) {
|
|
|
26847
27297
|
timeout: GIT_TIMEOUT_MS3
|
|
26848
27298
|
}).replace(/\r?\n$/u, "");
|
|
26849
27299
|
const hooksDir = safeGitPath(gitRoot, value);
|
|
26850
|
-
if (basename2(hooksDir) === "_" && basename2(
|
|
27300
|
+
if (basename2(hooksDir) === "_" && basename2(dirname10(hooksDir)) === ".husky") {
|
|
26851
27301
|
return {
|
|
26852
27302
|
gitRoot,
|
|
26853
27303
|
hooksDir,
|
|
26854
|
-
hookPath:
|
|
27304
|
+
hookPath: resolve6(dirname10(hooksDir), spec.hookName),
|
|
26855
27305
|
kind: "husky_v9",
|
|
26856
|
-
dispatcherPath:
|
|
27306
|
+
dispatcherPath: resolve6(hooksDir, spec.hookName)
|
|
26857
27307
|
};
|
|
26858
27308
|
}
|
|
26859
27309
|
return {
|
|
26860
27310
|
gitRoot,
|
|
26861
27311
|
hooksDir,
|
|
26862
|
-
hookPath:
|
|
27312
|
+
hookPath: resolve6(hooksDir, spec.hookName),
|
|
26863
27313
|
kind: "direct"
|
|
26864
27314
|
};
|
|
26865
27315
|
}
|
|
@@ -26870,8 +27320,8 @@ function resolveEffectivePostRewriteHook(cwd = process.cwd()) {
|
|
|
26870
27320
|
return resolveEffectiveManagedHook(POST_REWRITE_MANAGED_HOOK, cwd);
|
|
26871
27321
|
}
|
|
26872
27322
|
function assertSafeFile(path, spec) {
|
|
26873
|
-
if (!
|
|
26874
|
-
const stat =
|
|
27323
|
+
if (!existsSync10(path)) return void 0;
|
|
27324
|
+
const stat = lstatSync5(path);
|
|
26875
27325
|
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > MAX_HOOK_BYTES) {
|
|
26876
27326
|
throw new Error(`unsafe ${spec.hookName} hook target: ${path}`);
|
|
26877
27327
|
}
|
|
@@ -26892,16 +27342,16 @@ function assertUsableHuskyDispatcher(target, spec) {
|
|
|
26892
27342
|
if (!HUSKY_V9_DISPATCHERS.has(normalizedDispatcher)) {
|
|
26893
27343
|
throw new Error(`unrecognized Husky ${spec.hookName} dispatcher: ${target.dispatcherPath}`);
|
|
26894
27344
|
}
|
|
26895
|
-
const huskyRuntime =
|
|
27345
|
+
const huskyRuntime = resolve6(dirname10(target.dispatcherPath), "h");
|
|
26896
27346
|
const runtimeStat = assertSafeFile(huskyRuntime, spec);
|
|
26897
27347
|
const runtime = runtimeStat ? readHookFile(huskyRuntime) : void 0;
|
|
26898
|
-
const runtimeHash = runtime ?
|
|
27348
|
+
const runtimeHash = runtime ? createHash8("sha256").update(runtime).digest("hex") : void 0;
|
|
26899
27349
|
if (!runtimeHash || !HUSKY_V9_RUNTIME_HASHES.has(runtimeHash)) {
|
|
26900
27350
|
throw new Error(`unrecognized Husky v9 hook runtime: ${huskyRuntime}`);
|
|
26901
27351
|
}
|
|
26902
27352
|
}
|
|
26903
27353
|
function readHookFile(path) {
|
|
26904
|
-
const value =
|
|
27354
|
+
const value = readFileSync11(path);
|
|
26905
27355
|
return Buffer.isBuffer(value) ? value : Buffer.from(value);
|
|
26906
27356
|
}
|
|
26907
27357
|
function decodeHookText(content, spec) {
|
|
@@ -27034,7 +27484,7 @@ function errorCode(error) {
|
|
|
27034
27484
|
function assertTargetUnchanged(path, expected, spec, stat) {
|
|
27035
27485
|
let current;
|
|
27036
27486
|
try {
|
|
27037
|
-
current =
|
|
27487
|
+
current = lstatSync5(path);
|
|
27038
27488
|
} catch (error) {
|
|
27039
27489
|
if (expected === void 0 && errorCode(error) === "ENOENT") return;
|
|
27040
27490
|
throw new Error(`${spec.hookName} hook changed concurrently: ${path}`);
|
|
@@ -27047,9 +27497,9 @@ function assertTargetUnchanged(path, expected, spec, stat) {
|
|
|
27047
27497
|
}
|
|
27048
27498
|
}
|
|
27049
27499
|
function rewriteHookAtomically(path, next, expected, spec, stat) {
|
|
27050
|
-
const parent =
|
|
27051
|
-
|
|
27052
|
-
const temporary =
|
|
27500
|
+
const parent = dirname10(path);
|
|
27501
|
+
mkdirSync7(parent, { recursive: true });
|
|
27502
|
+
const temporary = resolve6(
|
|
27053
27503
|
parent,
|
|
27054
27504
|
`.${basename2(path)}.prim-${String(process.pid)}-${randomUUID2()}.tmp`
|
|
27055
27505
|
);
|
|
@@ -27057,16 +27507,16 @@ function rewriteHookAtomically(path, next, expected, spec, stat) {
|
|
|
27057
27507
|
try {
|
|
27058
27508
|
fd = openSync4(
|
|
27059
27509
|
temporary,
|
|
27060
|
-
|
|
27510
|
+
constants5.O_CREAT | constants5.O_EXCL | constants5.O_WRONLY | constants5.O_NOFOLLOW,
|
|
27061
27511
|
stat?.mode ?? 493
|
|
27062
27512
|
);
|
|
27063
|
-
|
|
27513
|
+
writeFileSync4(fd, next);
|
|
27064
27514
|
fchmodSync2(fd, (stat?.mode ?? 493) & 4095);
|
|
27065
27515
|
fsyncSync2(fd);
|
|
27066
27516
|
closeSync4(fd);
|
|
27067
27517
|
fd = void 0;
|
|
27068
27518
|
assertTargetUnchanged(path, expected, spec, stat);
|
|
27069
|
-
|
|
27519
|
+
renameSync3(temporary, path);
|
|
27070
27520
|
} finally {
|
|
27071
27521
|
if (fd !== void 0) {
|
|
27072
27522
|
try {
|
|
@@ -27075,7 +27525,7 @@ function rewriteHookAtomically(path, next, expected, spec, stat) {
|
|
|
27075
27525
|
}
|
|
27076
27526
|
}
|
|
27077
27527
|
try {
|
|
27078
|
-
|
|
27528
|
+
unlinkSync2(temporary);
|
|
27079
27529
|
} catch (error) {
|
|
27080
27530
|
if (errorCode(error) !== "ENOENT") {
|
|
27081
27531
|
}
|
|
@@ -27172,22 +27622,22 @@ async function bindRepository(root, options) {
|
|
|
27172
27622
|
import { execFileSync as execFileSync4 } from "child_process";
|
|
27173
27623
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
27174
27624
|
import {
|
|
27175
|
-
constants as
|
|
27176
|
-
chmodSync as
|
|
27625
|
+
constants as constants6,
|
|
27626
|
+
chmodSync as chmodSync4,
|
|
27177
27627
|
closeSync as closeSync5,
|
|
27178
27628
|
fchmodSync as fchmodSync3,
|
|
27179
27629
|
fsyncSync as fsyncSync3,
|
|
27180
27630
|
linkSync,
|
|
27181
|
-
lstatSync as
|
|
27182
|
-
mkdirSync as
|
|
27631
|
+
lstatSync as lstatSync6,
|
|
27632
|
+
mkdirSync as mkdirSync8,
|
|
27183
27633
|
openSync as openSync5,
|
|
27184
|
-
readFileSync as
|
|
27185
|
-
statSync as
|
|
27186
|
-
unlinkSync as
|
|
27187
|
-
writeFileSync as
|
|
27634
|
+
readFileSync as readFileSync12,
|
|
27635
|
+
statSync as statSync3,
|
|
27636
|
+
unlinkSync as unlinkSync3,
|
|
27637
|
+
writeFileSync as writeFileSync5
|
|
27188
27638
|
} from "fs";
|
|
27189
|
-
import { dirname as
|
|
27190
|
-
var WORKSPACE_ID_RELATIVE_PATH =
|
|
27639
|
+
import { dirname as dirname11, isAbsolute as isAbsolute8, join as join15, resolve as resolve7 } from "path";
|
|
27640
|
+
var WORKSPACE_ID_RELATIVE_PATH = join15("prim", "workspace-id");
|
|
27191
27641
|
var MAX_ANCESTORS = 64;
|
|
27192
27642
|
var MAX_GIT_FILE_BYTES = 4096;
|
|
27193
27643
|
var MAX_ID_FILE_BYTES = 128;
|
|
@@ -27233,7 +27683,7 @@ function resolveWorkspaceIdPath(cwd) {
|
|
|
27233
27683
|
}
|
|
27234
27684
|
return {
|
|
27235
27685
|
status: "resolved",
|
|
27236
|
-
path:
|
|
27686
|
+
path: isAbsolute8(gitPath) ? resolve7(gitPath) : resolve7(cwd, gitPath)
|
|
27237
27687
|
};
|
|
27238
27688
|
} catch (error) {
|
|
27239
27689
|
const code = errorCode2(error);
|
|
@@ -27244,21 +27694,21 @@ function resolveWorkspaceIdPath(cwd) {
|
|
|
27244
27694
|
}
|
|
27245
27695
|
}
|
|
27246
27696
|
function resolveFromFilesystem(cwd) {
|
|
27247
|
-
let current =
|
|
27697
|
+
let current = resolve7(cwd);
|
|
27248
27698
|
for (let depth = 0; depth < MAX_ANCESTORS; depth += 1) {
|
|
27249
|
-
const dotGit =
|
|
27699
|
+
const dotGit = join15(current, ".git");
|
|
27250
27700
|
try {
|
|
27251
|
-
const stat =
|
|
27701
|
+
const stat = lstatSync6(dotGit);
|
|
27252
27702
|
if (stat.isDirectory() && isGitDirectory(dotGit)) {
|
|
27253
|
-
return
|
|
27703
|
+
return join15(dotGit, WORKSPACE_ID_RELATIVE_PATH);
|
|
27254
27704
|
}
|
|
27255
27705
|
if (stat.isFile() && stat.size <= MAX_GIT_FILE_BYTES) {
|
|
27256
|
-
const contents =
|
|
27706
|
+
const contents = readFileSync12(dotGit, "utf8");
|
|
27257
27707
|
const match = /^gitdir: (.+?)(?:\r?\n)?$/.exec(contents);
|
|
27258
27708
|
if (match?.[1]) {
|
|
27259
|
-
const gitDirectory =
|
|
27709
|
+
const gitDirectory = isAbsolute8(match[1]) ? resolve7(match[1]) : resolve7(current, match[1]);
|
|
27260
27710
|
if (isGitDirectory(gitDirectory)) {
|
|
27261
|
-
return
|
|
27711
|
+
return join15(gitDirectory, WORKSPACE_ID_RELATIVE_PATH);
|
|
27262
27712
|
}
|
|
27263
27713
|
}
|
|
27264
27714
|
}
|
|
@@ -27269,7 +27719,7 @@ function resolveFromFilesystem(cwd) {
|
|
|
27269
27719
|
return null;
|
|
27270
27720
|
}
|
|
27271
27721
|
}
|
|
27272
|
-
const parent =
|
|
27722
|
+
const parent = dirname11(current);
|
|
27273
27723
|
if (parent === current) break;
|
|
27274
27724
|
current = parent;
|
|
27275
27725
|
}
|
|
@@ -27277,7 +27727,7 @@ function resolveFromFilesystem(cwd) {
|
|
|
27277
27727
|
}
|
|
27278
27728
|
function isGitDirectory(path) {
|
|
27279
27729
|
try {
|
|
27280
|
-
return
|
|
27730
|
+
return statSync3(join15(path, "HEAD")).isFile();
|
|
27281
27731
|
} catch {
|
|
27282
27732
|
return false;
|
|
27283
27733
|
}
|
|
@@ -27285,7 +27735,7 @@ function isGitDirectory(path) {
|
|
|
27285
27735
|
function inspectPath(path) {
|
|
27286
27736
|
let stat;
|
|
27287
27737
|
try {
|
|
27288
|
-
stat =
|
|
27738
|
+
stat = lstatSync6(path);
|
|
27289
27739
|
} catch (error) {
|
|
27290
27740
|
const code = errorCode2(error);
|
|
27291
27741
|
if (code === "ENOENT" || code === "ENOTDIR") return { status: "missing", path };
|
|
@@ -27296,7 +27746,7 @@ function inspectPath(path) {
|
|
|
27296
27746
|
return { status: "corrupt", path, reason: "invalid_content" };
|
|
27297
27747
|
}
|
|
27298
27748
|
try {
|
|
27299
|
-
const contents =
|
|
27749
|
+
const contents = readFileSync12(path, "utf8");
|
|
27300
27750
|
const workspaceId = contents.endsWith("\n") ? contents.slice(0, -1) : contents;
|
|
27301
27751
|
if ((contents === workspaceId || contents === `${workspaceId}
|
|
27302
27752
|
`) && isCanonicalWorkspaceId(workspaceId)) {
|
|
@@ -27313,22 +27763,22 @@ function inspectPath(path) {
|
|
|
27313
27763
|
}
|
|
27314
27764
|
}
|
|
27315
27765
|
function createWorkspaceId(path) {
|
|
27316
|
-
const parent =
|
|
27766
|
+
const parent = dirname11(path);
|
|
27317
27767
|
const workspaceId = randomUUID3();
|
|
27318
|
-
const temporaryPath =
|
|
27768
|
+
const temporaryPath = join15(parent, `.workspace-id-${process.pid}-${randomUUID3()}.tmp`);
|
|
27319
27769
|
let temporaryCreated = false;
|
|
27320
27770
|
let publishing = false;
|
|
27321
27771
|
try {
|
|
27322
|
-
|
|
27323
|
-
|
|
27772
|
+
mkdirSync8(parent, { recursive: true, mode: 448 });
|
|
27773
|
+
chmodSync4(parent, 448);
|
|
27324
27774
|
const fd = openSync5(
|
|
27325
27775
|
temporaryPath,
|
|
27326
|
-
|
|
27776
|
+
constants6.O_CREAT | constants6.O_EXCL | constants6.O_WRONLY,
|
|
27327
27777
|
384
|
|
27328
27778
|
);
|
|
27329
27779
|
temporaryCreated = true;
|
|
27330
27780
|
try {
|
|
27331
|
-
|
|
27781
|
+
writeFileSync5(fd, `${workspaceId}
|
|
27332
27782
|
`, "utf8");
|
|
27333
27783
|
fchmodSync3(fd, 384);
|
|
27334
27784
|
fsyncSync3(fd);
|
|
@@ -27349,7 +27799,7 @@ function createWorkspaceId(path) {
|
|
|
27349
27799
|
} finally {
|
|
27350
27800
|
if (temporaryCreated) {
|
|
27351
27801
|
try {
|
|
27352
|
-
|
|
27802
|
+
unlinkSync3(temporaryPath);
|
|
27353
27803
|
} catch {
|
|
27354
27804
|
}
|
|
27355
27805
|
}
|
|
@@ -27375,23 +27825,23 @@ function errorCode2(error) {
|
|
|
27375
27825
|
}
|
|
27376
27826
|
|
|
27377
27827
|
// src/hooks/codex-context.ts
|
|
27378
|
-
import { createHash as
|
|
27828
|
+
import { createHash as createHash9, randomBytes as randomBytes4 } from "crypto";
|
|
27379
27829
|
import {
|
|
27380
|
-
chmodSync as
|
|
27381
|
-
existsSync as
|
|
27382
|
-
mkdirSync as
|
|
27383
|
-
readFileSync as
|
|
27384
|
-
readdirSync as
|
|
27385
|
-
renameSync as
|
|
27386
|
-
rmSync as
|
|
27387
|
-
statSync as
|
|
27388
|
-
unlinkSync as
|
|
27389
|
-
writeFileSync as
|
|
27830
|
+
chmodSync as chmodSync5,
|
|
27831
|
+
existsSync as existsSync11,
|
|
27832
|
+
mkdirSync as mkdirSync9,
|
|
27833
|
+
readFileSync as readFileSync13,
|
|
27834
|
+
readdirSync as readdirSync4,
|
|
27835
|
+
renameSync as renameSync4,
|
|
27836
|
+
rmSync as rmSync6,
|
|
27837
|
+
statSync as statSync4,
|
|
27838
|
+
unlinkSync as unlinkSync4,
|
|
27839
|
+
writeFileSync as writeFileSync6
|
|
27390
27840
|
} from "fs";
|
|
27391
|
-
import { join as
|
|
27841
|
+
import { join as join16 } from "path";
|
|
27392
27842
|
|
|
27393
27843
|
// src/daemon/decision-digest-cache.ts
|
|
27394
|
-
import { randomBytes as
|
|
27844
|
+
import { randomBytes as randomBytes3 } from "crypto";
|
|
27395
27845
|
var DECISION_DIGEST_CACHE_LIMIT = 100;
|
|
27396
27846
|
var DECISION_DIGEST_CACHE_WINDOW = "24h";
|
|
27397
27847
|
var DECISION_DIGEST_CACHE_PATH = `/api/cli/decisions/recent?limit=${String(DECISION_DIGEST_CACHE_LIMIT)}&since=${DECISION_DIGEST_CACHE_WINDOW}`;
|
|
@@ -27516,15 +27966,13 @@ var CODEX_DRAFT_DIGEST_MAX_SEEN_IDS = 4096;
|
|
|
27516
27966
|
var CODEX_DIGEST_STATE_RETENTION_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
27517
27967
|
var CODEX_DIGEST_STATE_MAX_FILES = 256;
|
|
27518
27968
|
var STATE_VERSION = 1;
|
|
27519
|
-
var STATE_DIRECTORY = ["codex", "decision-digests"];
|
|
27520
27969
|
var DRAFT_STATE_VERSION = 2;
|
|
27521
|
-
var DRAFT_STATE_DIRECTORY = ["codex", "decision-draft-deliveries"];
|
|
27522
27970
|
var NO_CURSOR = -1;
|
|
27523
|
-
function stateRoot() {
|
|
27524
|
-
return
|
|
27971
|
+
function stateRoot(namespace) {
|
|
27972
|
+
return join16(primConfigDirectory(), namespace, "decision-digests");
|
|
27525
27973
|
}
|
|
27526
|
-
function draftStateRoot() {
|
|
27527
|
-
return
|
|
27974
|
+
function draftStateRoot(namespace) {
|
|
27975
|
+
return join16(primConfigDirectory(), namespace, "decision-draft-deliveries");
|
|
27528
27976
|
}
|
|
27529
27977
|
function workspaceFor(cwd) {
|
|
27530
27978
|
try {
|
|
@@ -27535,13 +27983,13 @@ function workspaceFor(cwd) {
|
|
|
27535
27983
|
}
|
|
27536
27984
|
function statePath(args) {
|
|
27537
27985
|
const identity = `${args.siteUrl}\0${workspaceFor(args.cwd)}\0${args.sessionId}`;
|
|
27538
|
-
const key =
|
|
27539
|
-
return
|
|
27986
|
+
const key = createHash9("sha256").update(identity).digest("hex");
|
|
27987
|
+
return join16(stateRoot(args.namespace), `${key}.json`);
|
|
27540
27988
|
}
|
|
27541
27989
|
function draftStatePath(args) {
|
|
27542
27990
|
const identity = `${args.siteUrl}\0${workspaceFor(args.cwd)}\0${args.sessionId}\0${args.principalId}\0${args.organizationId}\0${args.credentialFingerprint}`;
|
|
27543
|
-
const key =
|
|
27544
|
-
return
|
|
27991
|
+
const key = createHash9("sha256").update(identity).digest("hex");
|
|
27992
|
+
return join16(draftStateRoot(args.namespace), `${key}.json`);
|
|
27545
27993
|
}
|
|
27546
27994
|
function parseState(value) {
|
|
27547
27995
|
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
@@ -27580,58 +28028,58 @@ function parseDraftState(value) {
|
|
|
27580
28028
|
};
|
|
27581
28029
|
}
|
|
27582
28030
|
function readState(path) {
|
|
27583
|
-
if (!
|
|
28031
|
+
if (!existsSync11(path)) return void 0;
|
|
27584
28032
|
try {
|
|
27585
|
-
return parseState(JSON.parse(
|
|
28033
|
+
return parseState(JSON.parse(readFileSync13(path, "utf8")));
|
|
27586
28034
|
} catch {
|
|
27587
28035
|
return void 0;
|
|
27588
28036
|
}
|
|
27589
28037
|
}
|
|
27590
28038
|
function readDraftState(path) {
|
|
27591
|
-
if (!
|
|
28039
|
+
if (!existsSync11(path)) return void 0;
|
|
27592
28040
|
try {
|
|
27593
|
-
return parseDraftState(JSON.parse(
|
|
28041
|
+
return parseDraftState(JSON.parse(readFileSync13(path, "utf8")));
|
|
27594
28042
|
} catch {
|
|
27595
28043
|
return void 0;
|
|
27596
28044
|
}
|
|
27597
28045
|
}
|
|
27598
28046
|
function writeStateFile(path, directory, state) {
|
|
27599
|
-
|
|
27600
|
-
|
|
27601
|
-
const temporary =
|
|
28047
|
+
mkdirSync9(directory, { recursive: true, mode: 448 });
|
|
28048
|
+
chmodSync5(directory, 448);
|
|
28049
|
+
const temporary = join16(
|
|
27602
28050
|
directory,
|
|
27603
|
-
`.${path.slice(directory.length + 1)}.tmp-${process.pid}-${
|
|
28051
|
+
`.${path.slice(directory.length + 1)}.tmp-${process.pid}-${randomBytes4(8).toString("hex")}`
|
|
27604
28052
|
);
|
|
27605
28053
|
try {
|
|
27606
|
-
|
|
28054
|
+
writeFileSync6(temporary, `${JSON.stringify(state)}
|
|
27607
28055
|
`, {
|
|
27608
28056
|
encoding: "utf8",
|
|
27609
28057
|
mode: 384,
|
|
27610
28058
|
flag: "wx"
|
|
27611
28059
|
});
|
|
27612
|
-
|
|
27613
|
-
|
|
28060
|
+
chmodSync5(temporary, 384);
|
|
28061
|
+
renameSync4(temporary, path);
|
|
27614
28062
|
} finally {
|
|
27615
28063
|
try {
|
|
27616
|
-
|
|
28064
|
+
unlinkSync4(temporary);
|
|
27617
28065
|
} catch {
|
|
27618
28066
|
}
|
|
27619
28067
|
}
|
|
27620
28068
|
}
|
|
27621
28069
|
function cleanupStateFiles(directory, now) {
|
|
27622
|
-
if (!
|
|
28070
|
+
if (!existsSync11(directory)) return;
|
|
27623
28071
|
let names;
|
|
27624
28072
|
try {
|
|
27625
|
-
names =
|
|
28073
|
+
names = readdirSync4(directory);
|
|
27626
28074
|
} catch {
|
|
27627
28075
|
return;
|
|
27628
28076
|
}
|
|
27629
28077
|
const files = [];
|
|
27630
28078
|
const residue = [];
|
|
27631
28079
|
for (const name of names) {
|
|
27632
|
-
const path =
|
|
28080
|
+
const path = join16(directory, name);
|
|
27633
28081
|
try {
|
|
27634
|
-
const mtimeMs =
|
|
28082
|
+
const mtimeMs = statSync4(path).mtimeMs;
|
|
27635
28083
|
if (name.endsWith(".json")) {
|
|
27636
28084
|
files.push({ path, mtimeMs });
|
|
27637
28085
|
} else if ((name.includes(".json.tmp-") || name.endsWith(".json.lock")) && now - mtimeMs > CODEX_DIGEST_STATE_RETENTION_MS) {
|
|
@@ -27644,14 +28092,14 @@ function cleanupStateFiles(directory, now) {
|
|
|
27644
28092
|
const excess = files.filter((file) => !stale.some((candidate) => candidate.path === file.path)).sort((a, b) => a.mtimeMs - b.mtimeMs).slice(0, Math.max(0, files.length - CODEX_DIGEST_STATE_MAX_FILES));
|
|
27645
28093
|
for (const file of [...stale, ...excess]) {
|
|
27646
28094
|
try {
|
|
27647
|
-
|
|
28095
|
+
unlinkSync4(file.path);
|
|
27648
28096
|
} catch {
|
|
27649
28097
|
}
|
|
27650
28098
|
}
|
|
27651
28099
|
for (const path of residue) {
|
|
27652
28100
|
try {
|
|
27653
|
-
if (now -
|
|
27654
|
-
|
|
28101
|
+
if (now - statSync4(path).mtimeMs > CODEX_DIGEST_STATE_RETENTION_MS) {
|
|
28102
|
+
rmSync6(path, { recursive: true, force: true });
|
|
27655
28103
|
}
|
|
27656
28104
|
} catch {
|
|
27657
28105
|
}
|
|
@@ -27732,14 +28180,14 @@ function mergeState(latest, args) {
|
|
|
27732
28180
|
updatedAt: args.now
|
|
27733
28181
|
};
|
|
27734
28182
|
}
|
|
27735
|
-
async function commitState(path, args) {
|
|
28183
|
+
async function commitState(path, args, namespace) {
|
|
27736
28184
|
try {
|
|
27737
28185
|
await withFileLock(
|
|
27738
28186
|
`${path}.lock`,
|
|
27739
28187
|
() => {
|
|
27740
28188
|
const latest = readState(path);
|
|
27741
|
-
writeStateFile(path, stateRoot(), mergeState(latest, args));
|
|
27742
|
-
cleanupStateFiles(stateRoot(), args.now);
|
|
28189
|
+
writeStateFile(path, stateRoot(namespace), mergeState(latest, args));
|
|
28190
|
+
cleanupStateFiles(stateRoot(namespace), args.now);
|
|
27743
28191
|
},
|
|
27744
28192
|
{ timeoutMs: 50, pollMs: 10 }
|
|
27745
28193
|
);
|
|
@@ -27761,7 +28209,7 @@ function mergeDraftState(latest, args) {
|
|
|
27761
28209
|
updatedAt: args.now
|
|
27762
28210
|
};
|
|
27763
28211
|
}
|
|
27764
|
-
async function commitDraftState(path, args) {
|
|
28212
|
+
async function commitDraftState(path, args, namespace) {
|
|
27765
28213
|
try {
|
|
27766
28214
|
let next;
|
|
27767
28215
|
await withFileLock(
|
|
@@ -27769,8 +28217,8 @@ async function commitDraftState(path, args) {
|
|
|
27769
28217
|
() => {
|
|
27770
28218
|
const latest = readDraftState(path);
|
|
27771
28219
|
next = mergeDraftState(latest, args);
|
|
27772
|
-
writeStateFile(path, draftStateRoot(), next);
|
|
27773
|
-
cleanupStateFiles(draftStateRoot(), args.now);
|
|
28220
|
+
writeStateFile(path, draftStateRoot(namespace), next);
|
|
28221
|
+
cleanupStateFiles(draftStateRoot(namespace), args.now);
|
|
27774
28222
|
},
|
|
27775
28223
|
{ timeoutMs: 50, pollMs: 10 }
|
|
27776
28224
|
);
|
|
@@ -27780,9 +28228,10 @@ async function commitDraftState(path, args) {
|
|
|
27780
28228
|
}
|
|
27781
28229
|
}
|
|
27782
28230
|
async function prepareCodexContext(options) {
|
|
28231
|
+
const namespace = options.namespace ?? "codex";
|
|
27783
28232
|
const siteUrl = getSiteUrl();
|
|
27784
28233
|
const workspace = workspaceFor(options.cwd);
|
|
27785
|
-
const path = statePath({ cwd: options.cwd, sessionId: options.sessionId, siteUrl });
|
|
28234
|
+
const path = statePath({ cwd: options.cwd, sessionId: options.sessionId, siteUrl, namespace });
|
|
27786
28235
|
const previous = readState(path);
|
|
27787
28236
|
const principal = resolveDaemonPrincipal();
|
|
27788
28237
|
const privatePath = principal ? draftStatePath({
|
|
@@ -27791,7 +28240,8 @@ async function prepareCodexContext(options) {
|
|
|
27791
28240
|
siteUrl,
|
|
27792
28241
|
principalId: principal.principalId,
|
|
27793
28242
|
organizationId: principal.organizationId,
|
|
27794
|
-
credentialFingerprint: principal.credentialFingerprint
|
|
28243
|
+
credentialFingerprint: principal.credentialFingerprint,
|
|
28244
|
+
namespace
|
|
27795
28245
|
}) : void 0;
|
|
27796
28246
|
const previousDraft = privatePath ? readDraftState(privatePath) : void 0;
|
|
27797
28247
|
const startup = options.startup === true;
|
|
@@ -27881,32 +28331,40 @@ async function prepareCodexContext(options) {
|
|
|
27881
28331
|
acknowledge: async (handedOff) => {
|
|
27882
28332
|
if (!handedOff || acknowledged) return;
|
|
27883
28333
|
acknowledged = true;
|
|
27884
|
-
await commitState(
|
|
27885
|
-
|
|
27886
|
-
|
|
27887
|
-
|
|
27888
|
-
|
|
27889
|
-
|
|
27890
|
-
|
|
27891
|
-
|
|
27892
|
-
|
|
27893
|
-
|
|
27894
|
-
|
|
28334
|
+
await commitState(
|
|
28335
|
+
path,
|
|
28336
|
+
{
|
|
28337
|
+
sessionId: options.sessionId,
|
|
28338
|
+
siteUrl,
|
|
28339
|
+
workspace,
|
|
28340
|
+
startedAt,
|
|
28341
|
+
watermarkMs: pageWatermark,
|
|
28342
|
+
seenIds: freshRows.map((row) => row.id),
|
|
28343
|
+
report,
|
|
28344
|
+
feedAvailable,
|
|
28345
|
+
now: Date.now()
|
|
28346
|
+
},
|
|
28347
|
+
namespace
|
|
28348
|
+
);
|
|
27895
28349
|
if (privatePath === void 0 || principal === void 0 || draftPageToken === void 0) {
|
|
27896
28350
|
return;
|
|
27897
28351
|
}
|
|
27898
28352
|
let persistedDraft = previousDraft;
|
|
27899
28353
|
if (draftDigest?.deliveredIds.length) {
|
|
27900
|
-
persistedDraft = await commitDraftState(
|
|
27901
|
-
|
|
27902
|
-
|
|
27903
|
-
|
|
27904
|
-
|
|
27905
|
-
|
|
27906
|
-
|
|
27907
|
-
|
|
27908
|
-
|
|
27909
|
-
|
|
28354
|
+
persistedDraft = await commitDraftState(
|
|
28355
|
+
privatePath,
|
|
28356
|
+
{
|
|
28357
|
+
sessionId: options.sessionId,
|
|
28358
|
+
siteUrl,
|
|
28359
|
+
workspace,
|
|
28360
|
+
principalId: principal.principalId,
|
|
28361
|
+
organizationId: principal.organizationId,
|
|
28362
|
+
credentialFingerprint: principal.credentialFingerprint,
|
|
28363
|
+
deliveredIds: draftDigest.deliveredIds,
|
|
28364
|
+
now: Date.now()
|
|
28365
|
+
},
|
|
28366
|
+
namespace
|
|
28367
|
+
);
|
|
27910
28368
|
}
|
|
27911
28369
|
const seenDrafts = new Set(persistedDraft?.seenDraftIds ?? []);
|
|
27912
28370
|
const deliveredOnThisPage = draftPageActionableIds.filter((id) => seenDrafts.has(id));
|
|
@@ -27924,7 +28382,9 @@ async function prepareCodexContext(options) {
|
|
|
27924
28382
|
}
|
|
27925
28383
|
|
|
27926
28384
|
// src/hooks/normalize.ts
|
|
27927
|
-
import { createHash as
|
|
28385
|
+
import { createHash as createHash10 } from "crypto";
|
|
28386
|
+
import { realpathSync as realpathSync4 } from "fs";
|
|
28387
|
+
import { isAbsolute as isAbsolute9, resolve as resolve8 } from "path";
|
|
27928
28388
|
var HERMES_EVENT_MAP = {
|
|
27929
28389
|
on_session_start: "SessionStart",
|
|
27930
28390
|
on_session_end: "SessionEnd",
|
|
@@ -27934,7 +28394,125 @@ var HERMES_EVENT_MAP = {
|
|
|
27934
28394
|
post_tool_call: "PostToolUse",
|
|
27935
28395
|
subagent_stop: "SubagentStop"
|
|
27936
28396
|
};
|
|
28397
|
+
var CURSOR_EVENT_MAP = {
|
|
28398
|
+
sessionStart: "SessionStart",
|
|
28399
|
+
beforeSubmitPrompt: "UserPromptSubmit",
|
|
28400
|
+
preToolUse: "PreToolUse",
|
|
28401
|
+
postToolUse: "PostToolUse",
|
|
28402
|
+
postToolUseFailure: "PostToolUseFailure",
|
|
28403
|
+
afterAgentResponse: "AssistantResponse",
|
|
28404
|
+
subagentStop: "SubagentStop",
|
|
28405
|
+
stop: "Stop",
|
|
28406
|
+
sessionEnd: "SessionEnd"
|
|
28407
|
+
};
|
|
28408
|
+
var CURSOR_TOOL_EVENTS = /* @__PURE__ */ new Set(["PreToolUse", "PostToolUse", "PostToolUseFailure"]);
|
|
28409
|
+
var SAFE_CORRELATION_ID_RE = /^[A-Za-z0-9._:-]{1,128}$/u;
|
|
28410
|
+
var CURSOR_LOCAL_ONLY_FIELDS = /* @__PURE__ */ new Set([
|
|
28411
|
+
"conversation_id",
|
|
28412
|
+
"generation_id",
|
|
28413
|
+
"user_email",
|
|
28414
|
+
"account_email",
|
|
28415
|
+
"transcript_path",
|
|
28416
|
+
"transcript",
|
|
28417
|
+
"thought",
|
|
28418
|
+
"thoughts",
|
|
28419
|
+
"thinking",
|
|
28420
|
+
"tool_output"
|
|
28421
|
+
]);
|
|
28422
|
+
function requiredId(value, field) {
|
|
28423
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
28424
|
+
throw new TypeError(`Cursor hook envelope is missing ${field}`);
|
|
28425
|
+
}
|
|
28426
|
+
return value;
|
|
28427
|
+
}
|
|
28428
|
+
function cursorToolUseId(value) {
|
|
28429
|
+
if (SAFE_CORRELATION_ID_RE.test(value)) return value;
|
|
28430
|
+
return `cursor:tool:v1:${createHash10("sha256").update(value).digest("hex")}`;
|
|
28431
|
+
}
|
|
28432
|
+
function workspaceCandidates(value) {
|
|
28433
|
+
if (!Array.isArray(value)) return [];
|
|
28434
|
+
const roots = value.filter((item) => typeof item === "string" && item.length > 0);
|
|
28435
|
+
if (roots.some((root) => !isAbsolute9(root))) {
|
|
28436
|
+
throw new TypeError("Cursor workspace roots must be absolute");
|
|
28437
|
+
}
|
|
28438
|
+
return roots;
|
|
28439
|
+
}
|
|
28440
|
+
function pathIdentity(path) {
|
|
28441
|
+
try {
|
|
28442
|
+
return realpathSync4.native(path);
|
|
28443
|
+
} catch {
|
|
28444
|
+
return resolve8(path);
|
|
28445
|
+
}
|
|
28446
|
+
}
|
|
28447
|
+
function resolveCursorCwd(parsed) {
|
|
28448
|
+
const roots = workspaceCandidates(parsed.workspace_roots).map(pathIdentity);
|
|
28449
|
+
const rootRepositories = roots.map((root) => resolveRepositoryContext(root)?.repoRoot);
|
|
28450
|
+
const repositoryRoots = new Set(rootRepositories.filter((root) => !!root));
|
|
28451
|
+
if (repositoryRoots.size > 1) {
|
|
28452
|
+
throw new TypeError("Cursor hook envelope spans multiple repositories");
|
|
28453
|
+
}
|
|
28454
|
+
if (roots.length > 1 && rootRepositories.some((root) => root === void 0)) {
|
|
28455
|
+
throw new TypeError("Cursor hook envelope has ambiguous workspace roots");
|
|
28456
|
+
}
|
|
28457
|
+
const expectedRepo = [...repositoryRoots][0];
|
|
28458
|
+
const rawCwd = typeof parsed.cwd === "string" && parsed.cwd.length > 0 ? parsed.cwd : void 0;
|
|
28459
|
+
if (rawCwd && !isAbsolute9(rawCwd)) {
|
|
28460
|
+
throw new TypeError("Cursor hook cwd must be absolute");
|
|
28461
|
+
}
|
|
28462
|
+
const envelopeCwd = rawCwd ? pathIdentity(rawCwd) : void 0;
|
|
28463
|
+
const input = typeof parsed.tool_input === "object" && parsed.tool_input !== null && !Array.isArray(parsed.tool_input) ? parsed.tool_input : void 0;
|
|
28464
|
+
const rawToolCwd = parsed.tool_name === "Shell" && typeof input?.working_directory === "string" ? input.working_directory : void 0;
|
|
28465
|
+
const base = envelopeCwd ?? (roots.length === 1 ? roots[0] : expectedRepo);
|
|
28466
|
+
if (rawToolCwd && !isAbsolute9(rawToolCwd) && !base) {
|
|
28467
|
+
throw new TypeError("relative Cursor tool cwd has no workspace base");
|
|
28468
|
+
}
|
|
28469
|
+
const toolCwd = rawToolCwd ? pathIdentity(isAbsolute9(rawToolCwd) ? rawToolCwd : resolve8(base, rawToolCwd)) : void 0;
|
|
28470
|
+
const selected = toolCwd ?? envelopeCwd ?? (roots.length === 1 ? roots[0] : expectedRepo);
|
|
28471
|
+
if (!selected) {
|
|
28472
|
+
throw new TypeError("Cursor hook envelope has no unambiguous workspace");
|
|
28473
|
+
}
|
|
28474
|
+
const selectedRepo = resolveRepositoryContext(selected)?.repoRoot;
|
|
28475
|
+
if (expectedRepo && selectedRepo !== expectedRepo) {
|
|
28476
|
+
throw new TypeError("Cursor hook cwd conflicts with workspace repository");
|
|
28477
|
+
}
|
|
28478
|
+
return selected;
|
|
28479
|
+
}
|
|
28480
|
+
function normalizeCursorEnvelope(parsed) {
|
|
28481
|
+
const rawEvent = requiredId(parsed.hook_event_name, "hook_event_name");
|
|
28482
|
+
const event = CURSOR_EVENT_MAP[rawEvent];
|
|
28483
|
+
if (!event) throw new TypeError(`unsupported Cursor hook event: ${rawEvent}`);
|
|
28484
|
+
const sessionId = requiredId(parsed.conversation_id, "conversation_id");
|
|
28485
|
+
const turnId = requiredId(parsed.generation_id, "generation_id");
|
|
28486
|
+
if (parsed.session_id !== void 0 && parsed.session_id !== sessionId) {
|
|
28487
|
+
throw new TypeError("Cursor conversation_id conflicts with session_id");
|
|
28488
|
+
}
|
|
28489
|
+
if (parsed.turn_id !== void 0 && parsed.turn_id !== turnId) {
|
|
28490
|
+
throw new TypeError("Cursor generation_id conflicts with turn_id");
|
|
28491
|
+
}
|
|
28492
|
+
const rawToolUseId = CURSOR_TOOL_EVENTS.has(event) ? requiredId(parsed.tool_use_id, "tool_use_id") : void 0;
|
|
28493
|
+
const normalized = {
|
|
28494
|
+
...Object.fromEntries(
|
|
28495
|
+
Object.entries(parsed).filter(([key]) => !CURSOR_LOCAL_ONLY_FIELDS.has(key))
|
|
28496
|
+
),
|
|
28497
|
+
hook_event_name: event,
|
|
28498
|
+
session_id: sessionId,
|
|
28499
|
+
turn_id: turnId,
|
|
28500
|
+
cwd: resolveCursorCwd(parsed),
|
|
28501
|
+
...rawToolUseId === void 0 ? {} : { tool_use_id: cursorToolUseId(rawToolUseId) }
|
|
28502
|
+
};
|
|
28503
|
+
if (typeof parsed.tool_output === "string") {
|
|
28504
|
+
try {
|
|
28505
|
+
normalized.tool_response = JSON.parse(parsed.tool_output);
|
|
28506
|
+
} catch {
|
|
28507
|
+
normalized.tool_response = parsed.tool_output;
|
|
28508
|
+
}
|
|
28509
|
+
}
|
|
28510
|
+
return normalized;
|
|
28511
|
+
}
|
|
27937
28512
|
function normalizeEnvelope(parsed, agent) {
|
|
28513
|
+
if (agent === "cursor") {
|
|
28514
|
+
return normalizeCursorEnvelope(parsed);
|
|
28515
|
+
}
|
|
27938
28516
|
if (agent === "codex") {
|
|
27939
28517
|
const event = parsed.hook_event_name;
|
|
27940
28518
|
if ((event === "PreToolUse" || event === "PostToolUse") && (typeof parsed.tool_use_id !== "string" || parsed.tool_use_id.length === 0)) {
|
|
@@ -27946,7 +28524,7 @@ function normalizeEnvelope(parsed, agent) {
|
|
|
27946
28524
|
]);
|
|
27947
28525
|
return {
|
|
27948
28526
|
...parsed,
|
|
27949
|
-
tool_use_id: `codex:fallback:v1:${
|
|
28527
|
+
tool_use_id: `codex:fallback:v1:${createHash10("sha256").update(stableToolIdentity).digest("hex")}`
|
|
27950
28528
|
};
|
|
27951
28529
|
}
|
|
27952
28530
|
return parsed;
|
|
@@ -28048,24 +28626,24 @@ async function processSessionStart(raw, agent, feedbackSignal) {
|
|
|
28048
28626
|
{ timeoutMs: DAEMON_TIMEOUT_MS }
|
|
28049
28627
|
);
|
|
28050
28628
|
const cwd = envelope.cwd ?? process.cwd();
|
|
28051
|
-
let
|
|
28629
|
+
let projectRoot2 = null;
|
|
28052
28630
|
let active = false;
|
|
28053
28631
|
let skillState = { installed: 0, refreshed: 0 };
|
|
28054
28632
|
let claudeBinding;
|
|
28055
28633
|
if (agent === "claude_code") {
|
|
28056
28634
|
const activeProject = await activeProjectRoot(cwd);
|
|
28057
|
-
|
|
28058
|
-
active =
|
|
28635
|
+
projectRoot2 = activeProject?.root ?? null;
|
|
28636
|
+
active = projectRoot2 !== null;
|
|
28059
28637
|
claudeBinding = activeProject?.binding;
|
|
28060
28638
|
try {
|
|
28061
28639
|
skillState = await refreshClaudePlugins(
|
|
28062
28640
|
cwd,
|
|
28063
|
-
active &&
|
|
28641
|
+
active && projectRoot2 !== null ? { includeProject: true, projectRoot: projectRoot2 } : { includeProject: false }
|
|
28064
28642
|
);
|
|
28065
28643
|
} catch {
|
|
28066
28644
|
}
|
|
28067
28645
|
}
|
|
28068
|
-
if (isSessionEnded() && agent !== "codex") {
|
|
28646
|
+
if (isSessionEnded() && agent !== "codex" && agent !== "cursor") {
|
|
28069
28647
|
const notice = reauthNoticeFields(agent);
|
|
28070
28648
|
if (notice) {
|
|
28071
28649
|
return {
|
|
@@ -28084,11 +28662,11 @@ async function processSessionStart(raw, agent, feedbackSignal) {
|
|
|
28084
28662
|
});
|
|
28085
28663
|
} catch {
|
|
28086
28664
|
}
|
|
28087
|
-
|
|
28088
|
-
active =
|
|
28665
|
+
projectRoot2 = (await activeProjectRoot(cwd))?.root ?? null;
|
|
28666
|
+
active = projectRoot2 !== null;
|
|
28089
28667
|
let proactive = false;
|
|
28090
28668
|
try {
|
|
28091
|
-
proactive =
|
|
28669
|
+
proactive = projectRoot2 !== null && active && hasUsableCodexGuidance(projectRoot2);
|
|
28092
28670
|
} catch {
|
|
28093
28671
|
}
|
|
28094
28672
|
const additionalContext = [proactive ? CODEX_PRIM_REMINDER : void 0, context?.context].filter((value) => value !== void 0).join("\n\n");
|
|
@@ -28099,6 +28677,34 @@ async function processSessionStart(raw, agent, feedbackSignal) {
|
|
|
28099
28677
|
}
|
|
28100
28678
|
};
|
|
28101
28679
|
}
|
|
28680
|
+
if (agent === "cursor") {
|
|
28681
|
+
const activeProject = await activeProjectRoot(cwd);
|
|
28682
|
+
projectRoot2 = activeProject?.root ?? null;
|
|
28683
|
+
active = projectRoot2 !== null;
|
|
28684
|
+
let context;
|
|
28685
|
+
try {
|
|
28686
|
+
context = await prepareCodexContext({
|
|
28687
|
+
cwd,
|
|
28688
|
+
sessionId: envelope.session_id,
|
|
28689
|
+
startup: true,
|
|
28690
|
+
includeDigest: true,
|
|
28691
|
+
namespace: "cursor"
|
|
28692
|
+
});
|
|
28693
|
+
} catch {
|
|
28694
|
+
}
|
|
28695
|
+
let proactive = false;
|
|
28696
|
+
try {
|
|
28697
|
+
proactive = projectRoot2 !== null && active && hasUsableCursorSkill(projectRoot2);
|
|
28698
|
+
} catch {
|
|
28699
|
+
}
|
|
28700
|
+
const additionalContext = [proactive ? CODEX_PRIM_REMINDER : void 0, context?.context].filter((value) => value !== void 0).join("\n\n");
|
|
28701
|
+
return {
|
|
28702
|
+
output: additionalContext ? { additional_context: additionalContext } : {},
|
|
28703
|
+
acknowledge: async () => {
|
|
28704
|
+
await context?.acknowledge(true);
|
|
28705
|
+
}
|
|
28706
|
+
};
|
|
28707
|
+
}
|
|
28102
28708
|
if (agent === "claude_code") {
|
|
28103
28709
|
const additionalContext = [
|
|
28104
28710
|
claudeBinding ? claudeBindingReminder(claudeBinding) : void 0,
|
|
@@ -28145,33 +28751,26 @@ function emitOutput(output, acknowledge) {
|
|
|
28145
28751
|
outputAttempted = true;
|
|
28146
28752
|
return handoffHookOutput(output, acknowledge);
|
|
28147
28753
|
}
|
|
28148
|
-
function readStdin() {
|
|
28149
|
-
return new Promise((resolve7, reject) => {
|
|
28150
|
-
const chunks = [];
|
|
28151
|
-
const timer = setTimeout(() => {
|
|
28152
|
-
reject(new Error("stdin read timeout"));
|
|
28153
|
-
}, STDIN_TIMEOUT_MS);
|
|
28154
|
-
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
28155
|
-
process.stdin.on("end", () => {
|
|
28156
|
-
clearTimeout(timer);
|
|
28157
|
-
resolve7(Buffer.concat(chunks).toString("utf-8"));
|
|
28158
|
-
});
|
|
28159
|
-
process.stdin.on("error", (err) => {
|
|
28160
|
-
clearTimeout(timer);
|
|
28161
|
-
reject(err);
|
|
28162
|
-
});
|
|
28163
|
-
});
|
|
28164
|
-
}
|
|
28165
28754
|
async function main() {
|
|
28166
28755
|
warmBinCache();
|
|
28167
28756
|
const agent = parseAgent(process.argv);
|
|
28168
28757
|
let raw;
|
|
28169
28758
|
try {
|
|
28170
|
-
raw = await
|
|
28759
|
+
raw = await readHookStdin(STDIN_TIMEOUT_MS);
|
|
28171
28760
|
} catch {
|
|
28172
28761
|
await emitOutput(buildHookOutput({}));
|
|
28173
28762
|
return;
|
|
28174
28763
|
}
|
|
28764
|
+
if (agent !== "cursor") {
|
|
28765
|
+
try {
|
|
28766
|
+
const incoming = JSON.parse(raw);
|
|
28767
|
+
if (shouldSuppressImportedCursorHandler(incoming, "prim-session-start")) {
|
|
28768
|
+
await emitOutput({});
|
|
28769
|
+
return;
|
|
28770
|
+
}
|
|
28771
|
+
} catch {
|
|
28772
|
+
}
|
|
28773
|
+
}
|
|
28175
28774
|
const result = await processSessionStart(raw, agent);
|
|
28176
28775
|
await emitOutput(result.output, result.acknowledge);
|
|
28177
28776
|
}
|