@primitive.ai/prim 0.1.0-alpha.64 → 0.1.0-alpha.66
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 +5 -4
- package/dist/{chunk-VYGY3OOX.js → chunk-BDGQEJA5.js} +1 -1
- package/dist/{chunk-7X7SFOPJ.js → chunk-CPSE3Y3T.js} +63 -1
- package/dist/{chunk-LNU44OJV.js → chunk-CZ24W5QU.js} +2 -1
- package/dist/{chunk-MCPHIB4W.js → chunk-DR66XM5L.js} +250 -96
- package/dist/{chunk-XTNMSS4C.js → chunk-TDRXHBEX.js} +15 -0
- package/dist/hooks/post-commit.js +2 -2
- package/dist/hooks/post-rewrite.js +194 -0
- package/dist/hooks/post-tool-use.js +7 -7
- package/dist/hooks/pre-tool-use.js +2 -2
- package/dist/hooks/prim-hook.js +17 -17
- package/dist/hooks/session-start.js +8 -3
- package/dist/index.js +156 -70
- package/package.json +5 -4
|
@@ -241,6 +241,20 @@ function setRepoSyncId(cwd, value) {
|
|
|
241
241
|
timeout: GIT_TIMEOUT_MS2
|
|
242
242
|
});
|
|
243
243
|
}
|
|
244
|
+
function clearRepoSyncId(cwd) {
|
|
245
|
+
try {
|
|
246
|
+
execFileSync2("git", ["config", "--local", "--unset-all", PRIM_REPO_SYNC_ID_KEY], {
|
|
247
|
+
cwd,
|
|
248
|
+
stdio: ["ignore", "ignore", "pipe"],
|
|
249
|
+
timeout: GIT_TIMEOUT_MS2
|
|
250
|
+
});
|
|
251
|
+
} catch (error) {
|
|
252
|
+
if (typeof error === "object" && error !== null && "status" in error && error.status === 5) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
throw error;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
244
258
|
function hasProjectPrimInstall(cwd) {
|
|
245
259
|
const root = gitToplevel(cwd);
|
|
246
260
|
if (root === null || root === homedir()) return false;
|
|
@@ -278,6 +292,7 @@ export {
|
|
|
278
292
|
isValidRepoSyncId,
|
|
279
293
|
repoSyncId,
|
|
280
294
|
setRepoSyncId,
|
|
295
|
+
clearRepoSyncId,
|
|
281
296
|
isRepoActiveForCapture,
|
|
282
297
|
decisionIngestionStatus
|
|
283
298
|
};
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
commitAttributionFromEnvironment,
|
|
4
4
|
toCommitMove
|
|
5
|
-
} from "../chunk-
|
|
5
|
+
} from "../chunk-CPSE3Y3T.js";
|
|
6
6
|
import {
|
|
7
7
|
appendMove,
|
|
8
8
|
resolveOrg
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
isRepoActiveForCapture,
|
|
16
16
|
repoSyncId,
|
|
17
17
|
resolveRepositoryContext
|
|
18
|
-
} from "../chunk-
|
|
18
|
+
} from "../chunk-TDRXHBEX.js";
|
|
19
19
|
import "../chunk-CPX3BUOC.js";
|
|
20
20
|
|
|
21
21
|
// src/hooks/post-commit.ts
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
canonicalRewritePairs,
|
|
4
|
+
toRewriteMove
|
|
5
|
+
} from "../chunk-CPSE3Y3T.js";
|
|
6
|
+
import {
|
|
7
|
+
appendMove,
|
|
8
|
+
resolveOrg
|
|
9
|
+
} from "../chunk-HIMWM526.js";
|
|
10
|
+
import {
|
|
11
|
+
getOrCreateWorkspaceId
|
|
12
|
+
} from "../chunk-UVIWZWM6.js";
|
|
13
|
+
import {
|
|
14
|
+
githubRepositoryFullName,
|
|
15
|
+
isRepoActiveForCapture,
|
|
16
|
+
repoSyncId,
|
|
17
|
+
resolveRepositoryContext
|
|
18
|
+
} from "../chunk-TDRXHBEX.js";
|
|
19
|
+
import "../chunk-CPX3BUOC.js";
|
|
20
|
+
|
|
21
|
+
// src/hooks/post-rewrite.ts
|
|
22
|
+
import { execFileSync, spawn } from "child_process";
|
|
23
|
+
import {
|
|
24
|
+
constants,
|
|
25
|
+
closeSync,
|
|
26
|
+
fstatSync,
|
|
27
|
+
lstatSync,
|
|
28
|
+
openSync,
|
|
29
|
+
readFileSync,
|
|
30
|
+
unlinkSync
|
|
31
|
+
} from "fs";
|
|
32
|
+
import { basename, dirname, isAbsolute, join } from "path";
|
|
33
|
+
import { fileURLToPath } from "url";
|
|
34
|
+
var here = dirname(fileURLToPath(import.meta.url));
|
|
35
|
+
var GIT_TIMEOUT_MS = 1e3;
|
|
36
|
+
var MAX_PAIRS_FILE_BYTES = 1048576;
|
|
37
|
+
var MAX_PAIRS_FILE_AGE_MS = 10 * 60 * 1e3;
|
|
38
|
+
var MAX_PAIRS_FILE_FUTURE_SKEW_MS = 5e3;
|
|
39
|
+
var PAIRS_FILE_RE = /^prim-post-rewrite-pairs\.[A-Za-z0-9]+$/u;
|
|
40
|
+
var FULL_SHA_SOURCE = "(?:[0-9a-fA-F]{40}|[0-9a-fA-F]{64})";
|
|
41
|
+
var REWRITE_PAIR_RE = new RegExp(
|
|
42
|
+
`^(${FULL_SHA_SOURCE}) (${FULL_SHA_SOURCE})(?: ([^\\s]+))?$`,
|
|
43
|
+
"u"
|
|
44
|
+
);
|
|
45
|
+
function parseRewritePairs(value) {
|
|
46
|
+
if (value.length === 0) return [];
|
|
47
|
+
const body = value.endsWith("\n") ? value.slice(0, -1) : value;
|
|
48
|
+
if (body.length === 0) return [];
|
|
49
|
+
const parsed = [];
|
|
50
|
+
for (const line of body.split("\n")) {
|
|
51
|
+
const match = REWRITE_PAIR_RE.exec(line);
|
|
52
|
+
if (!match?.[1] || !match[2]) return;
|
|
53
|
+
parsed.push({ oldSha: match[1], newSha: match[2] });
|
|
54
|
+
}
|
|
55
|
+
return canonicalRewritePairs(parsed) ?? void 0;
|
|
56
|
+
}
|
|
57
|
+
function privatePairsFileStat(stat, now) {
|
|
58
|
+
const capturedAt = Math.trunc(stat.mtimeMs);
|
|
59
|
+
const uid = process.getuid?.();
|
|
60
|
+
return stat.isFile() && !stat.isSymbolicLink() && stat.size <= MAX_PAIRS_FILE_BYTES && stat.nlink === 1 && (stat.mode & 511) === 384 && (uid === void 0 || stat.uid === uid) && Number.isSafeInteger(capturedAt) && capturedAt > 0 && capturedAt >= now - MAX_PAIRS_FILE_AGE_MS && capturedAt <= now + MAX_PAIRS_FILE_FUTURE_SKEW_MS;
|
|
61
|
+
}
|
|
62
|
+
function rewritePairsFromLauncher(env = process.env, now = Date.now()) {
|
|
63
|
+
const path = env.PRIM_REWRITE_PAIRS_FILE;
|
|
64
|
+
if (!path || !isAbsolute(path) || !PAIRS_FILE_RE.test(basename(path))) return;
|
|
65
|
+
let fd;
|
|
66
|
+
try {
|
|
67
|
+
const pathStat = lstatSync(path);
|
|
68
|
+
if (!privatePairsFileStat(pathStat, now)) return;
|
|
69
|
+
fd = openSync(path, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
70
|
+
const openStat = fstatSync(fd);
|
|
71
|
+
if (!privatePairsFileStat(openStat, now) || openStat.dev !== pathStat.dev || openStat.ino !== pathStat.ino) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const bytes = readFileSync(fd);
|
|
75
|
+
if (bytes.length !== openStat.size) return;
|
|
76
|
+
let text;
|
|
77
|
+
try {
|
|
78
|
+
text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
79
|
+
} catch {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const pairs = parseRewritePairs(text);
|
|
83
|
+
if (!pairs) return;
|
|
84
|
+
return {
|
|
85
|
+
path,
|
|
86
|
+
dev: openStat.dev,
|
|
87
|
+
ino: openStat.ino,
|
|
88
|
+
capturedAt: Math.trunc(openStat.mtimeMs),
|
|
89
|
+
pairs
|
|
90
|
+
};
|
|
91
|
+
} catch {
|
|
92
|
+
return;
|
|
93
|
+
} finally {
|
|
94
|
+
if (fd !== void 0) {
|
|
95
|
+
try {
|
|
96
|
+
closeSync(fd);
|
|
97
|
+
} catch {
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function unlinkSnapshot(snapshot) {
|
|
103
|
+
try {
|
|
104
|
+
const current = lstatSync(snapshot.path);
|
|
105
|
+
if (current.isFile() && !current.isSymbolicLink() && current.dev === snapshot.dev && current.ino === snapshot.ino) {
|
|
106
|
+
unlinkSync(snapshot.path);
|
|
107
|
+
}
|
|
108
|
+
} catch {
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function gitText(args) {
|
|
112
|
+
try {
|
|
113
|
+
return execFileSync("git", args, {
|
|
114
|
+
encoding: "utf-8",
|
|
115
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
116
|
+
timeout: GIT_TIMEOUT_MS
|
|
117
|
+
}).trim();
|
|
118
|
+
} catch {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function validSource(value) {
|
|
123
|
+
return value === "amend" || value === "rebase";
|
|
124
|
+
}
|
|
125
|
+
function validBranch(value) {
|
|
126
|
+
return value && value === value.trim() && ![...value].some((char) => char < " " || char === "\x7F") ? value : void 0;
|
|
127
|
+
}
|
|
128
|
+
function resolveCliVersion() {
|
|
129
|
+
try {
|
|
130
|
+
const pkg = JSON.parse(readFileSync(join(here, "..", "..", "package.json"), "utf-8"));
|
|
131
|
+
return pkg.version ?? "unknown";
|
|
132
|
+
} catch {
|
|
133
|
+
return "unknown";
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
function spawnBackgroundFlush() {
|
|
137
|
+
const entry = join(here, "..", "index.js");
|
|
138
|
+
spawn(process.execPath, [entry, "moves", "flush"], {
|
|
139
|
+
detached: true,
|
|
140
|
+
stdio: "ignore"
|
|
141
|
+
}).unref();
|
|
142
|
+
}
|
|
143
|
+
function runPostRewrite() {
|
|
144
|
+
const snapshot = rewritePairsFromLauncher();
|
|
145
|
+
if (!snapshot) return;
|
|
146
|
+
try {
|
|
147
|
+
const source = process.env.PRIM_REWRITE_SOURCE;
|
|
148
|
+
if (!validSource(source) || snapshot.pairs.length === 0) return;
|
|
149
|
+
const cwd = gitText(["rev-parse", "--show-toplevel"]) ?? process.cwd();
|
|
150
|
+
if (!isRepoActiveForCapture(cwd)) return;
|
|
151
|
+
const repository = resolveRepositoryContext(cwd);
|
|
152
|
+
const identity = getOrCreateWorkspaceId(cwd);
|
|
153
|
+
const workspaceId = identity.status === "ready" ? identity.workspaceId : void 0;
|
|
154
|
+
const moves = toRewriteMove(
|
|
155
|
+
{
|
|
156
|
+
source,
|
|
157
|
+
pairs: snapshot.pairs,
|
|
158
|
+
branch: validBranch(process.env.PRIM_REWRITE_BRANCH)
|
|
159
|
+
},
|
|
160
|
+
resolveCliVersion(),
|
|
161
|
+
cwd,
|
|
162
|
+
{
|
|
163
|
+
repository,
|
|
164
|
+
repoFullName: githubRepositoryFullName(cwd) ?? void 0,
|
|
165
|
+
repoSyncId: repoSyncId(cwd),
|
|
166
|
+
workspaceId,
|
|
167
|
+
capturedAt: snapshot.capturedAt
|
|
168
|
+
}
|
|
169
|
+
);
|
|
170
|
+
if (moves.length === 0) return;
|
|
171
|
+
const { orgId } = resolveOrg({ sessionId: "", cwd });
|
|
172
|
+
for (const move of moves) appendMove(move, orgId);
|
|
173
|
+
spawnBackgroundFlush();
|
|
174
|
+
} finally {
|
|
175
|
+
unlinkSnapshot(snapshot);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
if (!process.env.VITEST) {
|
|
179
|
+
try {
|
|
180
|
+
runPostRewrite();
|
|
181
|
+
} catch (error) {
|
|
182
|
+
if (process.env.PRIM_HOOK_DEBUG) {
|
|
183
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
184
|
+
process.stderr.write(`[prim-post-rewrite] capture failed: ${detail}
|
|
185
|
+
`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
process.exit(0);
|
|
189
|
+
}
|
|
190
|
+
export {
|
|
191
|
+
parseRewritePairs,
|
|
192
|
+
rewritePairsFromLauncher,
|
|
193
|
+
runPostRewrite
|
|
194
|
+
};
|
|
@@ -7,30 +7,30 @@ import {
|
|
|
7
7
|
import {
|
|
8
8
|
enrichHookPayloadWithFileRefs,
|
|
9
9
|
preserveHookFileMetadata
|
|
10
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-BDGQEJA5.js";
|
|
11
11
|
import {
|
|
12
12
|
postToolInvocationId,
|
|
13
13
|
toMove,
|
|
14
14
|
toolOutcomeFor
|
|
15
|
-
} from "../chunk-
|
|
15
|
+
} from "../chunk-CPSE3Y3T.js";
|
|
16
16
|
import {
|
|
17
17
|
appendMove,
|
|
18
18
|
resolveOrg
|
|
19
19
|
} from "../chunk-HIMWM526.js";
|
|
20
|
-
import {
|
|
21
|
-
scrubFromCwd
|
|
22
|
-
} from "../chunk-G5D3FF3D.js";
|
|
23
20
|
import {
|
|
24
21
|
getOrCreateWorkspaceId
|
|
25
22
|
} from "../chunk-UVIWZWM6.js";
|
|
23
|
+
import {
|
|
24
|
+
scrubFromCwd
|
|
25
|
+
} from "../chunk-G5D3FF3D.js";
|
|
26
26
|
import {
|
|
27
27
|
warmBinCache
|
|
28
|
-
} from "../chunk-
|
|
28
|
+
} from "../chunk-CZ24W5QU.js";
|
|
29
29
|
import {
|
|
30
30
|
isRepoActiveForCapture,
|
|
31
31
|
repoSyncId,
|
|
32
32
|
resolveRepositoryContext
|
|
33
|
-
} from "../chunk-
|
|
33
|
+
} from "../chunk-TDRXHBEX.js";
|
|
34
34
|
import {
|
|
35
35
|
getClient
|
|
36
36
|
} from "../chunk-CPX3BUOC.js";
|
|
@@ -16,13 +16,13 @@ import {
|
|
|
16
16
|
import {
|
|
17
17
|
packageVersion,
|
|
18
18
|
warmBinCache
|
|
19
|
-
} from "../chunk-
|
|
19
|
+
} from "../chunk-CZ24W5QU.js";
|
|
20
20
|
import {
|
|
21
21
|
canonicalGitRoot,
|
|
22
22
|
canonicalRepositoryPath,
|
|
23
23
|
isRepoActive,
|
|
24
24
|
repoSyncId
|
|
25
|
-
} from "../chunk-
|
|
25
|
+
} from "../chunk-TDRXHBEX.js";
|
|
26
26
|
import {
|
|
27
27
|
getClient
|
|
28
28
|
} from "../chunk-CPX3BUOC.js";
|
package/dist/hooks/prim-hook.js
CHANGED
|
@@ -1,41 +1,41 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
buildHookOutput,
|
|
4
|
+
handoffHookOutput
|
|
5
|
+
} from "../chunk-4GLVJLEQ.js";
|
|
6
|
+
import {
|
|
7
|
+
FEEDBACK_DEADLINE_MS,
|
|
8
|
+
acknowledgeDecisionFeedback,
|
|
9
|
+
leaseDecisionFeedback,
|
|
10
|
+
renderFeedback
|
|
11
|
+
} from "../chunk-KHZNYEUV.js";
|
|
2
12
|
import {
|
|
3
13
|
enrichHookPayloadWithFileRefs,
|
|
4
14
|
preserveHookFileMetadata
|
|
5
|
-
} from "../chunk-
|
|
15
|
+
} from "../chunk-BDGQEJA5.js";
|
|
6
16
|
import {
|
|
7
17
|
postToolInvocationId,
|
|
8
18
|
shouldFlushAfter,
|
|
9
19
|
toMove
|
|
10
|
-
} from "../chunk-
|
|
20
|
+
} from "../chunk-CPSE3Y3T.js";
|
|
11
21
|
import {
|
|
12
22
|
appendMove,
|
|
13
23
|
resolveOrg
|
|
14
24
|
} from "../chunk-HIMWM526.js";
|
|
15
|
-
import {
|
|
16
|
-
scrubFromCwd
|
|
17
|
-
} from "../chunk-G5D3FF3D.js";
|
|
18
|
-
import {
|
|
19
|
-
buildHookOutput,
|
|
20
|
-
handoffHookOutput
|
|
21
|
-
} from "../chunk-4GLVJLEQ.js";
|
|
22
|
-
import {
|
|
23
|
-
FEEDBACK_DEADLINE_MS,
|
|
24
|
-
acknowledgeDecisionFeedback,
|
|
25
|
-
leaseDecisionFeedback,
|
|
26
|
-
renderFeedback
|
|
27
|
-
} from "../chunk-KHZNYEUV.js";
|
|
28
25
|
import {
|
|
29
26
|
getOrCreateWorkspaceId
|
|
30
27
|
} from "../chunk-UVIWZWM6.js";
|
|
28
|
+
import {
|
|
29
|
+
scrubFromCwd
|
|
30
|
+
} from "../chunk-G5D3FF3D.js";
|
|
31
31
|
import {
|
|
32
32
|
warmBinCache
|
|
33
|
-
} from "../chunk-
|
|
33
|
+
} from "../chunk-CZ24W5QU.js";
|
|
34
34
|
import {
|
|
35
35
|
isRepoActiveForCapture,
|
|
36
36
|
repoSyncId,
|
|
37
37
|
resolveRepositoryContext
|
|
38
|
-
} from "../chunk-
|
|
38
|
+
} from "../chunk-TDRXHBEX.js";
|
|
39
39
|
import "../chunk-CPX3BUOC.js";
|
|
40
40
|
import {
|
|
41
41
|
normalizeEnvelope,
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
import {
|
|
3
3
|
bindRepository,
|
|
4
4
|
ensureEffectivePostCommitHook,
|
|
5
|
+
ensureEffectivePostRewriteHook,
|
|
5
6
|
hasUsableCodexGuidance,
|
|
6
7
|
refreshClaudePlugins
|
|
7
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-DR66XM5L.js";
|
|
8
9
|
import {
|
|
9
10
|
buildHookOutput,
|
|
10
11
|
handoffHookOutput
|
|
@@ -21,13 +22,13 @@ import {
|
|
|
21
22
|
import {
|
|
22
23
|
binFile,
|
|
23
24
|
warmBinCache
|
|
24
|
-
} from "../chunk-
|
|
25
|
+
} from "../chunk-CZ24W5QU.js";
|
|
25
26
|
import {
|
|
26
27
|
gitToplevel,
|
|
27
28
|
isRepoActiveForCapture,
|
|
28
29
|
repoActiveFlag,
|
|
29
30
|
setRepoActive
|
|
30
|
-
} from "../chunk-
|
|
31
|
+
} from "../chunk-TDRXHBEX.js";
|
|
31
32
|
import {
|
|
32
33
|
getSiteUrl,
|
|
33
34
|
isSessionEnded
|
|
@@ -100,6 +101,10 @@ async function activeProjectRoot(cwd) {
|
|
|
100
101
|
ensureEffectivePostCommitHook(root);
|
|
101
102
|
} catch {
|
|
102
103
|
}
|
|
104
|
+
try {
|
|
105
|
+
ensureEffectivePostRewriteHook(root);
|
|
106
|
+
} catch {
|
|
107
|
+
}
|
|
103
108
|
}
|
|
104
109
|
try {
|
|
105
110
|
await bindRepository(root, {
|