@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
|
@@ -1,26 +1,30 @@
|
|
|
1
1
|
import {
|
|
2
|
-
formatStatusline
|
|
3
|
-
|
|
4
|
-
} from "./chunk-PMRDE2DA.js";
|
|
2
|
+
formatStatusline
|
|
3
|
+
} from "./chunk-WX52U7Z2.js";
|
|
5
4
|
import {
|
|
6
5
|
decisionIngestionStatus,
|
|
7
|
-
gitToplevel,
|
|
8
6
|
repositoryBindingState
|
|
9
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-M6RIJVRE.js";
|
|
10
8
|
import {
|
|
11
9
|
getSiteUrl,
|
|
12
10
|
isSessionEnded,
|
|
13
|
-
terminalSafeText
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
terminalSafeText
|
|
12
|
+
} from "./chunk-PCVGBE5B.js";
|
|
13
|
+
import {
|
|
14
|
+
packageVersion
|
|
15
|
+
} from "./chunk-26P57LAR.js";
|
|
16
|
+
import {
|
|
17
|
+
gitToplevel
|
|
18
|
+
} from "./chunk-H4UNYFUC.js";
|
|
16
19
|
import {
|
|
17
20
|
daemonPrincipalsMatch,
|
|
18
21
|
daemonRequest,
|
|
19
22
|
resolveDaemonPrincipal
|
|
20
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-KFXF2V5G.js";
|
|
21
24
|
import {
|
|
22
|
-
primConfigDirectory
|
|
23
|
-
|
|
25
|
+
primConfigDirectory,
|
|
26
|
+
withFileLock
|
|
27
|
+
} from "./chunk-67VNLLBN.js";
|
|
24
28
|
|
|
25
29
|
// src/hooks/codex-context.ts
|
|
26
30
|
import { createHash, randomBytes as randomBytes2 } from "crypto";
|
|
@@ -61,9 +65,7 @@ var CODEX_DRAFT_DIGEST_MAX_SEEN_IDS = 4096;
|
|
|
61
65
|
var CODEX_DIGEST_STATE_RETENTION_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
62
66
|
var CODEX_DIGEST_STATE_MAX_FILES = 256;
|
|
63
67
|
var STATE_VERSION = 1;
|
|
64
|
-
var STATE_DIRECTORY = ["codex", "decision-digests"];
|
|
65
68
|
var DRAFT_STATE_VERSION = 2;
|
|
66
|
-
var DRAFT_STATE_DIRECTORY = ["codex", "decision-draft-deliveries"];
|
|
67
69
|
var NO_CURSOR = -1;
|
|
68
70
|
function hasVisibleCodexMessage(output) {
|
|
69
71
|
if (typeof output !== "object" || output === null || Array.isArray(output)) return false;
|
|
@@ -95,11 +97,11 @@ function appendCodexContext(output, context) {
|
|
|
95
97
|
}
|
|
96
98
|
return next;
|
|
97
99
|
}
|
|
98
|
-
function stateRoot() {
|
|
99
|
-
return join(primConfigDirectory(),
|
|
100
|
+
function stateRoot(namespace) {
|
|
101
|
+
return join(primConfigDirectory(), namespace, "decision-digests");
|
|
100
102
|
}
|
|
101
|
-
function draftStateRoot() {
|
|
102
|
-
return join(primConfigDirectory(),
|
|
103
|
+
function draftStateRoot(namespace) {
|
|
104
|
+
return join(primConfigDirectory(), namespace, "decision-draft-deliveries");
|
|
103
105
|
}
|
|
104
106
|
function workspaceFor(cwd) {
|
|
105
107
|
try {
|
|
@@ -111,12 +113,12 @@ function workspaceFor(cwd) {
|
|
|
111
113
|
function statePath(args) {
|
|
112
114
|
const identity = `${args.siteUrl}\0${workspaceFor(args.cwd)}\0${args.sessionId}`;
|
|
113
115
|
const key = createHash("sha256").update(identity).digest("hex");
|
|
114
|
-
return join(stateRoot(), `${key}.json`);
|
|
116
|
+
return join(stateRoot(args.namespace), `${key}.json`);
|
|
115
117
|
}
|
|
116
118
|
function draftStatePath(args) {
|
|
117
119
|
const identity = `${args.siteUrl}\0${workspaceFor(args.cwd)}\0${args.sessionId}\0${args.principalId}\0${args.organizationId}\0${args.credentialFingerprint}`;
|
|
118
120
|
const key = createHash("sha256").update(identity).digest("hex");
|
|
119
|
-
return join(draftStateRoot(), `${key}.json`);
|
|
121
|
+
return join(draftStateRoot(args.namespace), `${key}.json`);
|
|
120
122
|
}
|
|
121
123
|
function parseState(value) {
|
|
122
124
|
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
@@ -307,14 +309,14 @@ function mergeState(latest, args) {
|
|
|
307
309
|
updatedAt: args.now
|
|
308
310
|
};
|
|
309
311
|
}
|
|
310
|
-
async function commitState(path, args) {
|
|
312
|
+
async function commitState(path, args, namespace) {
|
|
311
313
|
try {
|
|
312
314
|
await withFileLock(
|
|
313
315
|
`${path}.lock`,
|
|
314
316
|
() => {
|
|
315
317
|
const latest = readState(path);
|
|
316
|
-
writeStateFile(path, stateRoot(), mergeState(latest, args));
|
|
317
|
-
cleanupStateFiles(stateRoot(), args.now);
|
|
318
|
+
writeStateFile(path, stateRoot(namespace), mergeState(latest, args));
|
|
319
|
+
cleanupStateFiles(stateRoot(namespace), args.now);
|
|
318
320
|
},
|
|
319
321
|
{ timeoutMs: 50, pollMs: 10 }
|
|
320
322
|
);
|
|
@@ -336,7 +338,7 @@ function mergeDraftState(latest, args) {
|
|
|
336
338
|
updatedAt: args.now
|
|
337
339
|
};
|
|
338
340
|
}
|
|
339
|
-
async function commitDraftState(path, args) {
|
|
341
|
+
async function commitDraftState(path, args, namespace) {
|
|
340
342
|
try {
|
|
341
343
|
let next;
|
|
342
344
|
await withFileLock(
|
|
@@ -344,8 +346,8 @@ async function commitDraftState(path, args) {
|
|
|
344
346
|
() => {
|
|
345
347
|
const latest = readDraftState(path);
|
|
346
348
|
next = mergeDraftState(latest, args);
|
|
347
|
-
writeStateFile(path, draftStateRoot(), next);
|
|
348
|
-
cleanupStateFiles(draftStateRoot(), args.now);
|
|
349
|
+
writeStateFile(path, draftStateRoot(namespace), next);
|
|
350
|
+
cleanupStateFiles(draftStateRoot(namespace), args.now);
|
|
349
351
|
},
|
|
350
352
|
{ timeoutMs: 50, pollMs: 10 }
|
|
351
353
|
);
|
|
@@ -355,9 +357,10 @@ async function commitDraftState(path, args) {
|
|
|
355
357
|
}
|
|
356
358
|
}
|
|
357
359
|
async function prepareCodexContext(options) {
|
|
360
|
+
const namespace = options.namespace ?? "codex";
|
|
358
361
|
const siteUrl = getSiteUrl();
|
|
359
362
|
const workspace = workspaceFor(options.cwd);
|
|
360
|
-
const path = statePath({ cwd: options.cwd, sessionId: options.sessionId, siteUrl });
|
|
363
|
+
const path = statePath({ cwd: options.cwd, sessionId: options.sessionId, siteUrl, namespace });
|
|
361
364
|
const previous = readState(path);
|
|
362
365
|
const principal = resolveDaemonPrincipal();
|
|
363
366
|
const privatePath = principal ? draftStatePath({
|
|
@@ -366,7 +369,8 @@ async function prepareCodexContext(options) {
|
|
|
366
369
|
siteUrl,
|
|
367
370
|
principalId: principal.principalId,
|
|
368
371
|
organizationId: principal.organizationId,
|
|
369
|
-
credentialFingerprint: principal.credentialFingerprint
|
|
372
|
+
credentialFingerprint: principal.credentialFingerprint,
|
|
373
|
+
namespace
|
|
370
374
|
}) : void 0;
|
|
371
375
|
const previousDraft = privatePath ? readDraftState(privatePath) : void 0;
|
|
372
376
|
const startup = options.startup === true;
|
|
@@ -456,32 +460,40 @@ async function prepareCodexContext(options) {
|
|
|
456
460
|
acknowledge: async (handedOff) => {
|
|
457
461
|
if (!handedOff || acknowledged) return;
|
|
458
462
|
acknowledged = true;
|
|
459
|
-
await commitState(
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
463
|
+
await commitState(
|
|
464
|
+
path,
|
|
465
|
+
{
|
|
466
|
+
sessionId: options.sessionId,
|
|
467
|
+
siteUrl,
|
|
468
|
+
workspace,
|
|
469
|
+
startedAt,
|
|
470
|
+
watermarkMs: pageWatermark,
|
|
471
|
+
seenIds: freshRows.map((row) => row.id),
|
|
472
|
+
report,
|
|
473
|
+
feedAvailable,
|
|
474
|
+
now: Date.now()
|
|
475
|
+
},
|
|
476
|
+
namespace
|
|
477
|
+
);
|
|
470
478
|
if (privatePath === void 0 || principal === void 0 || draftPageToken === void 0) {
|
|
471
479
|
return;
|
|
472
480
|
}
|
|
473
481
|
let persistedDraft = previousDraft;
|
|
474
482
|
if (draftDigest?.deliveredIds.length) {
|
|
475
|
-
persistedDraft = await commitDraftState(
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
483
|
+
persistedDraft = await commitDraftState(
|
|
484
|
+
privatePath,
|
|
485
|
+
{
|
|
486
|
+
sessionId: options.sessionId,
|
|
487
|
+
siteUrl,
|
|
488
|
+
workspace,
|
|
489
|
+
principalId: principal.principalId,
|
|
490
|
+
organizationId: principal.organizationId,
|
|
491
|
+
credentialFingerprint: principal.credentialFingerprint,
|
|
492
|
+
deliveredIds: draftDigest.deliveredIds,
|
|
493
|
+
now: Date.now()
|
|
494
|
+
},
|
|
495
|
+
namespace
|
|
496
|
+
);
|
|
485
497
|
}
|
|
486
498
|
const seenDrafts = new Set(persistedDraft?.seenDraftIds ?? []);
|
|
487
499
|
const deliveredOnThisPage = draftPageActionableIds.filter((id) => seenDrafts.has(id));
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getSiteUrl
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-PCVGBE5B.js";
|
|
4
4
|
import {
|
|
5
5
|
jwtOrganizationId,
|
|
6
6
|
primConfigDirectory,
|
|
7
7
|
resolveAuthCredential
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-67VNLLBN.js";
|
|
9
9
|
|
|
10
10
|
// src/journal.ts
|
|
11
11
|
import {
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
// src/lib/git.ts
|
|
2
|
+
import { execFileSync } from "child_process";
|
|
3
|
+
import { createHash } from "crypto";
|
|
4
|
+
import { lstatSync, realpathSync } from "fs";
|
|
5
|
+
import { basename, dirname, isAbsolute, relative, resolve, sep } from "path";
|
|
6
|
+
var GIT_TIMEOUT_MS = 1e3;
|
|
7
|
+
var GITHUB_OWNER_PATTERN = /^(?![A-Za-z0-9-]*--)[A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?$/u;
|
|
8
|
+
var GITHUB_REPOSITORY_PATTERN = /^[A-Za-z0-9._-]{1,100}$/u;
|
|
9
|
+
function gitToplevel(cwd) {
|
|
10
|
+
try {
|
|
11
|
+
return execFileSync("git", ["rev-parse", "--show-toplevel"], {
|
|
12
|
+
cwd,
|
|
13
|
+
encoding: "utf-8",
|
|
14
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
15
|
+
timeout: GIT_TIMEOUT_MS
|
|
16
|
+
}).trim();
|
|
17
|
+
} catch {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function gitValue(cwd, args) {
|
|
22
|
+
try {
|
|
23
|
+
const value = execFileSync("git", args, {
|
|
24
|
+
cwd,
|
|
25
|
+
encoding: "utf-8",
|
|
26
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
27
|
+
timeout: GIT_TIMEOUT_MS
|
|
28
|
+
}).trim();
|
|
29
|
+
return value || void 0;
|
|
30
|
+
} catch {
|
|
31
|
+
return void 0;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function currentBranch(cwd) {
|
|
35
|
+
return gitValue(cwd, ["symbolic-ref", "--quiet", "--short", "HEAD"]);
|
|
36
|
+
}
|
|
37
|
+
function githubRepositoryFullName(cwd) {
|
|
38
|
+
const remote = gitValue(cwd, ["config", "--get", "remote.origin.url"]);
|
|
39
|
+
if (!remote || [...remote].some((char) => char < " " || char === "\x7F")) return null;
|
|
40
|
+
const match = /^(?:git@github\.com:([^?#]+)|(?:https|ssh):\/\/(?:[^/@]+@)?github\.com(?::\d+)?\/([^?#]+))$/i.exec(
|
|
41
|
+
remote
|
|
42
|
+
);
|
|
43
|
+
const path = match?.[1] ?? match?.[2];
|
|
44
|
+
if (!path) return null;
|
|
45
|
+
const parts = path.replace(/^\/+|\/+$/g, "").replace(/\.git$/i, "").split("/");
|
|
46
|
+
if (parts.length !== 2 || !GITHUB_OWNER_PATTERN.test(parts[0] ?? "") || !GITHUB_REPOSITORY_PATTERN.test(parts[1] ?? "")) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
return `${parts[0]}/${parts[1]}`;
|
|
50
|
+
}
|
|
51
|
+
function canonicalGitRoot(cwd) {
|
|
52
|
+
try {
|
|
53
|
+
const top = gitToplevel(cwd);
|
|
54
|
+
return top ? realpathSync.native(top) : null;
|
|
55
|
+
} catch {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function normalizeOriginRemote(remote) {
|
|
60
|
+
const value = remote.trim();
|
|
61
|
+
if (!value) return void 0;
|
|
62
|
+
const scp = !value.includes("://") ? /^(?:[^@/\s]+@)?(?<host>[^:/\s]+):(?<path>.+)$/.exec(value)?.groups : void 0;
|
|
63
|
+
if (scp?.host && scp.path) {
|
|
64
|
+
const path = scp.path.replace(/^\/+|\/+$/g, "").replace(/\.git$/i, "");
|
|
65
|
+
return path ? `${scp.host.toLowerCase()}/${path}` : void 0;
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
const url = new URL(value);
|
|
69
|
+
url.username = "";
|
|
70
|
+
url.password = "";
|
|
71
|
+
url.search = "";
|
|
72
|
+
url.hash = "";
|
|
73
|
+
const path = url.pathname.replace(/^\/+|\/+$/g, "").replace(/\.git$/i, "");
|
|
74
|
+
if (url.host && path) return `${url.host.toLowerCase()}/${path}`;
|
|
75
|
+
return void 0;
|
|
76
|
+
} catch {
|
|
77
|
+
return void 0;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function opaqueRepoKey(source, value) {
|
|
81
|
+
return `repo_v1_${createHash("sha256").update(`${source}\0${value}`).digest("hex")}`;
|
|
82
|
+
}
|
|
83
|
+
function resolveRepositoryContext(cwd = process.cwd()) {
|
|
84
|
+
const top = gitToplevel(cwd);
|
|
85
|
+
if (!top) return null;
|
|
86
|
+
let repoRoot;
|
|
87
|
+
try {
|
|
88
|
+
repoRoot = realpathSync.native(top);
|
|
89
|
+
} catch {
|
|
90
|
+
repoRoot = resolve(top);
|
|
91
|
+
}
|
|
92
|
+
const origin = gitValue(repoRoot, ["config", "--get", "remote.origin.url"]);
|
|
93
|
+
const repoFullName = githubRepositoryFullName(repoRoot) ?? void 0;
|
|
94
|
+
const normalizedOrigin = origin ? normalizeOriginRemote(origin) : void 0;
|
|
95
|
+
if (normalizedOrigin) {
|
|
96
|
+
return {
|
|
97
|
+
repoRoot,
|
|
98
|
+
repoKey: opaqueRepoKey("origin", normalizedOrigin),
|
|
99
|
+
identitySource: "origin",
|
|
100
|
+
repoFullName
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
const roots = gitValue(repoRoot, ["rev-list", "--max-parents=0", "HEAD"])?.split(/\s+/).filter(Boolean).sort();
|
|
104
|
+
if (roots && roots.length > 0) {
|
|
105
|
+
return {
|
|
106
|
+
repoRoot,
|
|
107
|
+
repoKey: opaqueRepoKey("root_commit", roots.join("\n")),
|
|
108
|
+
identitySource: "root_commit",
|
|
109
|
+
repoFullName
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
return { repoRoot, repoFullName };
|
|
113
|
+
}
|
|
114
|
+
function nearestExistingAncestor(path) {
|
|
115
|
+
const suffix = [];
|
|
116
|
+
let cursor = path;
|
|
117
|
+
while (true) {
|
|
118
|
+
try {
|
|
119
|
+
lstatSync(cursor);
|
|
120
|
+
break;
|
|
121
|
+
} catch (error) {
|
|
122
|
+
const code = typeof error === "object" && error !== null && "code" in error ? error.code : void 0;
|
|
123
|
+
if (code !== "ENOENT" && code !== "ENOTDIR") return null;
|
|
124
|
+
const parent = dirname(cursor);
|
|
125
|
+
if (parent === cursor) return null;
|
|
126
|
+
suffix.unshift(cursor.slice(parent.length + (parent.endsWith(sep) ? 0 : 1)));
|
|
127
|
+
cursor = parent;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
return { real: realpathSync.native(cursor), suffix };
|
|
132
|
+
} catch {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
function canonicalRepositoryPathScoped(filePath, context, baseDir) {
|
|
137
|
+
if (!filePath || filePath !== filePath.trim() || filePath.includes("\0")) {
|
|
138
|
+
return { ok: false, reason: "invalid_path" };
|
|
139
|
+
}
|
|
140
|
+
const absolute = resolve(baseDir, filePath);
|
|
141
|
+
const resolved = nearestExistingAncestor(absolute);
|
|
142
|
+
if (!resolved) return { ok: false, reason: "invalid_path" };
|
|
143
|
+
const target = resolve(resolved.real, ...resolved.suffix);
|
|
144
|
+
const rel = relative(context.repoRoot, target);
|
|
145
|
+
if (!rel || rel === ".") return { ok: false, reason: "invalid_path" };
|
|
146
|
+
if (isAbsolute(rel) || rel === ".." || rel.startsWith(`..${sep}`)) {
|
|
147
|
+
return { ok: false, reason: "outside_repository" };
|
|
148
|
+
}
|
|
149
|
+
return { ok: true, file: sep === "/" ? rel : rel.split(sep).join("/") };
|
|
150
|
+
}
|
|
151
|
+
function canonicalRepositoryPathLegacy(filePath, cwd, repositoryRoot = canonicalGitRoot(cwd)) {
|
|
152
|
+
if (!repositoryRoot || !filePath || [...filePath].some((char) => char < " " || char === "\x7F" || "~*?[]{}$`\\".includes(char)))
|
|
153
|
+
return null;
|
|
154
|
+
const absolute = resolve(cwd, filePath);
|
|
155
|
+
let target;
|
|
156
|
+
try {
|
|
157
|
+
const stat = lstatSync(absolute);
|
|
158
|
+
if (!stat.isFile() || stat.isSymbolicLink()) return null;
|
|
159
|
+
target = realpathSync.native(absolute);
|
|
160
|
+
} catch (error) {
|
|
161
|
+
if (!(error instanceof Error) || error.code !== "ENOENT") {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
try {
|
|
165
|
+
const parent = realpathSync.native(dirname(absolute));
|
|
166
|
+
if (!lstatSync(parent).isDirectory()) return null;
|
|
167
|
+
target = resolve(parent, basename(absolute));
|
|
168
|
+
} catch {
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
const rel = relative(repositoryRoot, target);
|
|
173
|
+
if (!rel || isAbsolute(rel) || rel === ".." || rel.startsWith(`..${sep}`)) {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
return sep === "/" ? rel : rel.split(sep).join("/");
|
|
177
|
+
}
|
|
178
|
+
function canonicalRepositoryPath(filePath, contextOrCwd, baseDirOrRoot) {
|
|
179
|
+
if (typeof contextOrCwd === "string") {
|
|
180
|
+
return canonicalRepositoryPathLegacy(filePath, contextOrCwd, baseDirOrRoot);
|
|
181
|
+
}
|
|
182
|
+
return canonicalRepositoryPathScoped(
|
|
183
|
+
filePath,
|
|
184
|
+
contextOrCwd,
|
|
185
|
+
baseDirOrRoot ?? contextOrCwd.repoRoot
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export {
|
|
190
|
+
gitToplevel,
|
|
191
|
+
currentBranch,
|
|
192
|
+
githubRepositoryFullName,
|
|
193
|
+
canonicalGitRoot,
|
|
194
|
+
resolveRepositoryContext,
|
|
195
|
+
canonicalRepositoryPath
|
|
196
|
+
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
analyzeShellTargets,
|
|
3
3
|
extractFileTargets
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-ZB4F75SZ.js";
|
|
5
5
|
import {
|
|
6
6
|
canonicalRepositoryPath
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-H4UNYFUC.js";
|
|
8
8
|
|
|
9
9
|
// src/hooks/file-refs.ts
|
|
10
10
|
var MAX_PREFLIGHT_FILE_TARGETS = 25;
|
|
@@ -26,7 +26,8 @@ function preserveHookFileMetadata(payload, resolution) {
|
|
|
26
26
|
return { ...payload, primitive };
|
|
27
27
|
}
|
|
28
28
|
function resolveHookFileRefs(args) {
|
|
29
|
-
const
|
|
29
|
+
const isShellTool = (args.agent === "claude_code" || args.agent === "codex") && args.toolName === "Bash" || args.agent === "cursor" && args.toolName === "Shell";
|
|
30
|
+
const command = isShellTool ? typeof args.toolInput === "string" ? args.toolInput : args.toolInput && typeof args.toolInput === "object" && typeof args.toolInput.command === "string" ? args.toolInput.command : void 0 : void 0;
|
|
30
31
|
const shell = command === void 0 ? void 0 : analyzeShellTargets(command);
|
|
31
32
|
const shellMutation = shell?.mutation === "none" ? "none" : shell?.coverage === "complete" ? "resolved" : shell ? "unresolved" : void 0;
|
|
32
33
|
const readPath = args.agent === "claude_code" && args.toolName === "Read" && args.toolInput && typeof args.toolInput === "object" && typeof args.toolInput.file_path === "string" ? [args.toolInput.file_path] : void 0;
|