@primitive.ai/prim 0.1.0-alpha.63 → 0.1.0-alpha.65
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-QGVHLP5J.js → chunk-5CKL5EYQ.js} +55 -6
- package/dist/{chunk-DA4BMHEB.js → chunk-BDGQEJA5.js} +3 -3
- package/dist/{chunk-WNIY6Z6N.js → chunk-CPHJUQNE.js} +38 -13
- package/dist/chunk-G5D3FF3D.js +853 -0
- package/dist/{chunk-KBFFVYBC.js → chunk-LNU44OJV.js} +3 -5
- package/dist/{chunk-XTNMSS4C.js → chunk-TDRXHBEX.js} +15 -0
- package/dist/hooks/post-commit.js +29 -5
- package/dist/hooks/post-tool-use.js +31 -19
- package/dist/hooks/pre-tool-use.js +11 -3
- package/dist/hooks/prim-hook.js +5 -5
- package/dist/hooks/session-start.js +9 -12
- package/dist/index.js +103 -20
- package/package.json +1 -1
- package/dist/chunk-GF5QII7T.js +0 -411
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
// src/lib/bin-cache.ts
|
|
2
|
-
import { chmodSync, mkdirSync, renameSync, writeFileSync } from "fs";
|
|
3
|
-
import { homedir } from "os";
|
|
4
|
-
import { join as join2 } from "path";
|
|
5
|
-
|
|
6
1
|
// src/lib/bin-path.ts
|
|
7
2
|
import { existsSync, readFileSync } from "fs";
|
|
8
3
|
import { dirname, isAbsolute, join } from "path";
|
|
@@ -76,6 +71,9 @@ function commandMatchesBin(command, bin) {
|
|
|
76
71
|
}
|
|
77
72
|
|
|
78
73
|
// src/lib/bin-cache.ts
|
|
74
|
+
import { chmodSync, mkdirSync, renameSync, writeFileSync } from "fs";
|
|
75
|
+
import { homedir } from "os";
|
|
76
|
+
import { join as join2 } from "path";
|
|
79
77
|
var CACHED_BINS = [
|
|
80
78
|
"prim",
|
|
81
79
|
"prim-hook",
|
|
@@ -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-5CKL5EYQ.js";
|
|
6
6
|
import {
|
|
7
7
|
appendMove,
|
|
8
8
|
resolveOrg
|
|
@@ -15,17 +15,35 @@ 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
|
|
22
22
|
import { execFileSync, spawn } from "child_process";
|
|
23
|
-
import { readFileSync } from "fs";
|
|
24
|
-
import { dirname, join } from "path";
|
|
23
|
+
import { lstatSync, readFileSync } from "fs";
|
|
24
|
+
import { basename, dirname, isAbsolute, join } from "path";
|
|
25
25
|
import { fileURLToPath } from "url";
|
|
26
26
|
var here = dirname(fileURLToPath(import.meta.url));
|
|
27
27
|
var GIT_TIMEOUT_MS = 1e3;
|
|
28
28
|
var FULL_SHA_RE = /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/u;
|
|
29
|
+
var OBSERVATION_MARKER_RE = /^prim-post-commit-observed\.[A-Za-z0-9]+$/u;
|
|
30
|
+
var MAX_OBSERVATION_MARKER_AGE_MS = 10 * 60 * 1e3;
|
|
31
|
+
var MAX_OBSERVATION_MARKER_FUTURE_SKEW_MS = 5e3;
|
|
32
|
+
function capturedAtFromLauncher(env = process.env, now = Date.now()) {
|
|
33
|
+
const path = env.PRIM_COMMIT_OBSERVED_FILE;
|
|
34
|
+
if (!path || !isAbsolute(path) || !OBSERVATION_MARKER_RE.test(basename(path))) return;
|
|
35
|
+
try {
|
|
36
|
+
const stat = lstatSync(path);
|
|
37
|
+
const capturedAt = Math.trunc(stat.mtimeMs);
|
|
38
|
+
const uid = process.getuid?.();
|
|
39
|
+
if (!stat.isFile() || stat.isSymbolicLink() || stat.size !== 0 || stat.nlink !== 1 || (stat.mode & 63) !== 0 || uid !== void 0 && stat.uid !== uid || !Number.isSafeInteger(capturedAt) || capturedAt <= 0 || capturedAt < now - MAX_OBSERVATION_MARKER_AGE_MS || capturedAt > now + MAX_OBSERVATION_MARKER_FUTURE_SKEW_MS) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
return capturedAt;
|
|
43
|
+
} catch {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
29
47
|
function gitText(args) {
|
|
30
48
|
try {
|
|
31
49
|
return execFileSync("git", args, {
|
|
@@ -117,6 +135,10 @@ function runPostCommit() {
|
|
|
117
135
|
if (!isRepoActiveForCapture(cwd)) {
|
|
118
136
|
return;
|
|
119
137
|
}
|
|
138
|
+
const capturedAt = capturedAtFromLauncher();
|
|
139
|
+
if (process.env.PRIM_COMMIT_OBSERVED_FILE !== void 0 && capturedAt === void 0) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
120
142
|
const commit = readCommit();
|
|
121
143
|
if (commit) {
|
|
122
144
|
const repository = resolveRepositoryContext(cwd);
|
|
@@ -128,7 +150,8 @@ function runPostCommit() {
|
|
|
128
150
|
repoFullName: githubRepositoryFullName(cwd) ?? void 0,
|
|
129
151
|
repoSyncId: repoSyncId(cwd),
|
|
130
152
|
workspaceId,
|
|
131
|
-
attribution
|
|
153
|
+
attribution,
|
|
154
|
+
...capturedAt === void 0 ? {} : { capturedAt }
|
|
132
155
|
});
|
|
133
156
|
const { orgId } = resolveOrg({ sessionId: move.sessionId, cwd });
|
|
134
157
|
appendMove(move, orgId);
|
|
@@ -148,5 +171,6 @@ if (!process.env.VITEST) {
|
|
|
148
171
|
process.exit(0);
|
|
149
172
|
}
|
|
150
173
|
export {
|
|
174
|
+
capturedAtFromLauncher,
|
|
151
175
|
runPostCommit
|
|
152
176
|
};
|
|
@@ -7,29 +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
|
-
toMove
|
|
14
|
-
|
|
13
|
+
toMove,
|
|
14
|
+
toolOutcomeFor
|
|
15
|
+
} from "../chunk-5CKL5EYQ.js";
|
|
15
16
|
import {
|
|
16
17
|
appendMove,
|
|
17
18
|
resolveOrg
|
|
18
19
|
} from "../chunk-HIMWM526.js";
|
|
19
20
|
import {
|
|
20
21
|
scrubFromCwd
|
|
21
|
-
} from "../chunk-
|
|
22
|
+
} from "../chunk-G5D3FF3D.js";
|
|
22
23
|
import {
|
|
23
24
|
getOrCreateWorkspaceId
|
|
24
25
|
} from "../chunk-UVIWZWM6.js";
|
|
25
26
|
import {
|
|
26
27
|
warmBinCache
|
|
27
|
-
} from "../chunk-
|
|
28
|
+
} from "../chunk-LNU44OJV.js";
|
|
28
29
|
import {
|
|
29
30
|
isRepoActiveForCapture,
|
|
30
31
|
repoSyncId,
|
|
31
32
|
resolveRepositoryContext
|
|
32
|
-
} from "../chunk-
|
|
33
|
+
} from "../chunk-TDRXHBEX.js";
|
|
33
34
|
import {
|
|
34
35
|
getClient
|
|
35
36
|
} from "../chunk-CPX3BUOC.js";
|
|
@@ -74,7 +75,7 @@ function isVerdictFooterContext(value) {
|
|
|
74
75
|
// src/hooks/post-tool-use.ts
|
|
75
76
|
var STDIN_TIMEOUT_MS = 1e3;
|
|
76
77
|
var EDITING_TOOLS = /* @__PURE__ */ new Set(["Edit", "Write", "MultiEdit", "NotebookEdit", "Bash"]);
|
|
77
|
-
var CODEX_EDITING_TOOLS = /* @__PURE__ */ new Set(["apply_patch"]);
|
|
78
|
+
var CODEX_EDITING_TOOLS = /* @__PURE__ */ new Set(["apply_patch", "Bash"]);
|
|
78
79
|
var HERMES_EDITING_TOOLS = /* @__PURE__ */ new Set(["write_file", "patch"]);
|
|
79
80
|
function editingToolsFor(agent) {
|
|
80
81
|
if (agent === "codex") {
|
|
@@ -137,17 +138,27 @@ async function main() {
|
|
|
137
138
|
emit();
|
|
138
139
|
return;
|
|
139
140
|
}
|
|
140
|
-
|
|
141
|
-
|
|
141
|
+
let envelope = parsed;
|
|
142
|
+
const isToolResult = envelope.hook_event_name === "PostToolUse" || agent === "claude_code" && envelope.hook_event_name === "PostToolUseFailure";
|
|
143
|
+
const isHermesDenial = agent === "hermes" && envelope.hook_event_name === "post_approval_response" && toolOutcomeFor(parsed, agent) === "prevented";
|
|
144
|
+
if (!isToolResult && !isHermesDenial) {
|
|
145
|
+
emit();
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const invocationId = postToolInvocationId(parsed, agent);
|
|
149
|
+
if (isHermesDenial && !invocationId) {
|
|
142
150
|
emit();
|
|
143
151
|
return;
|
|
144
152
|
}
|
|
145
153
|
const toolName = typeof envelope.tool_name === "string" ? envelope.tool_name : "";
|
|
146
|
-
|
|
147
|
-
if (!editingTools.has(toolName)) {
|
|
154
|
+
if (!isHermesDenial && !editingToolsFor(agent).has(toolName)) {
|
|
148
155
|
emit();
|
|
149
156
|
return;
|
|
150
157
|
}
|
|
158
|
+
if (isHermesDenial && (typeof envelope.session_id !== "string" || envelope.session_id.length === 0) && typeof envelope.extra?.session_key === "string" && envelope.extra.session_key.length > 0) {
|
|
159
|
+
parsed = { ...parsed, session_id: envelope.extra.session_key };
|
|
160
|
+
envelope = parsed;
|
|
161
|
+
}
|
|
151
162
|
if (typeof envelope.session_id !== "string" || envelope.session_id.length === 0) {
|
|
152
163
|
emit();
|
|
153
164
|
return;
|
|
@@ -170,18 +181,19 @@ async function main() {
|
|
|
170
181
|
repository
|
|
171
182
|
});
|
|
172
183
|
const { resolution } = enrichment;
|
|
173
|
-
if (
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
184
|
+
if (!isHermesDenial) {
|
|
185
|
+
if (resolution.shellMutation === "none") {
|
|
186
|
+
emit();
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (resolution.shellMutation === void 0 && resolution.fileRefs.length === 0) {
|
|
190
|
+
emit();
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
180
193
|
}
|
|
181
194
|
const enriched = enrichment.parsed;
|
|
182
195
|
const identity = getOrCreateWorkspaceId(cwd);
|
|
183
196
|
const workspaceId = identity.status === "ready" ? identity.workspaceId : void 0;
|
|
184
|
-
const invocationId = postToolInvocationId(enriched, agent);
|
|
185
197
|
const base = toMove(enriched, resolveCliVersion(), agent, workspaceId, repository, invocationId);
|
|
186
198
|
const scrubbed = scrubFromCwd(enriched, cwd);
|
|
187
199
|
const move = {
|
|
@@ -12,16 +12,17 @@ import {
|
|
|
12
12
|
failOpenOutput,
|
|
13
13
|
readHookMode,
|
|
14
14
|
scrub
|
|
15
|
-
} from "../chunk-
|
|
15
|
+
} from "../chunk-G5D3FF3D.js";
|
|
16
16
|
import {
|
|
17
|
+
packageVersion,
|
|
17
18
|
warmBinCache
|
|
18
|
-
} from "../chunk-
|
|
19
|
+
} from "../chunk-LNU44OJV.js";
|
|
19
20
|
import {
|
|
20
21
|
canonicalGitRoot,
|
|
21
22
|
canonicalRepositoryPath,
|
|
22
23
|
isRepoActive,
|
|
23
24
|
repoSyncId
|
|
24
|
-
} from "../chunk-
|
|
25
|
+
} from "../chunk-TDRXHBEX.js";
|
|
25
26
|
import {
|
|
26
27
|
getClient
|
|
27
28
|
} from "../chunk-CPX3BUOC.js";
|
|
@@ -36,6 +37,11 @@ var PREFLIGHT_PROTOCOL_VERSION = 3;
|
|
|
36
37
|
var PREFLIGHT_TIMEOUT_MS = 6500;
|
|
37
38
|
var MAX_PREFLIGHT_PATHS = 32;
|
|
38
39
|
var MAX_PROPOSAL_BYTES = 6144;
|
|
40
|
+
var MAX_CLIENT_VERSION_CHARS = 32;
|
|
41
|
+
var CLIENT_VERSION_RE = /^[A-Za-z0-9][A-Za-z0-9._+-]*$/;
|
|
42
|
+
function boundedClientVersion(raw) {
|
|
43
|
+
return typeof raw === "string" && raw.length <= MAX_CLIENT_VERSION_CHARS && CLIENT_VERSION_RE.test(raw) ? raw : "unknown";
|
|
44
|
+
}
|
|
39
45
|
function resolvePreflightTargets(args) {
|
|
40
46
|
let rawPaths;
|
|
41
47
|
let coverage = "complete";
|
|
@@ -224,6 +230,8 @@ async function main() {
|
|
|
224
230
|
const request = {
|
|
225
231
|
protocolVersion: PREFLIGHT_PROTOCOL_VERSION,
|
|
226
232
|
agent,
|
|
233
|
+
clientMode: mode,
|
|
234
|
+
clientVersion: boundedClientVersion(packageVersion()),
|
|
227
235
|
sessionId,
|
|
228
236
|
invocationId: callId,
|
|
229
237
|
repoSyncId: binding,
|
package/dist/hooks/prim-hook.js
CHANGED
|
@@ -2,19 +2,19 @@
|
|
|
2
2
|
import {
|
|
3
3
|
enrichHookPayloadWithFileRefs,
|
|
4
4
|
preserveHookFileMetadata
|
|
5
|
-
} from "../chunk-
|
|
5
|
+
} from "../chunk-BDGQEJA5.js";
|
|
6
6
|
import {
|
|
7
7
|
postToolInvocationId,
|
|
8
8
|
shouldFlushAfter,
|
|
9
9
|
toMove
|
|
10
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-5CKL5EYQ.js";
|
|
11
11
|
import {
|
|
12
12
|
appendMove,
|
|
13
13
|
resolveOrg
|
|
14
14
|
} from "../chunk-HIMWM526.js";
|
|
15
15
|
import {
|
|
16
16
|
scrubFromCwd
|
|
17
|
-
} from "../chunk-
|
|
17
|
+
} from "../chunk-G5D3FF3D.js";
|
|
18
18
|
import {
|
|
19
19
|
buildHookOutput,
|
|
20
20
|
handoffHookOutput
|
|
@@ -30,12 +30,12 @@ import {
|
|
|
30
30
|
} from "../chunk-UVIWZWM6.js";
|
|
31
31
|
import {
|
|
32
32
|
warmBinCache
|
|
33
|
-
} from "../chunk-
|
|
33
|
+
} from "../chunk-LNU44OJV.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,
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
ensureEffectivePostCommitHook,
|
|
5
5
|
hasUsableCodexGuidance,
|
|
6
6
|
refreshClaudePlugins
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-CPHJUQNE.js";
|
|
8
8
|
import {
|
|
9
9
|
buildHookOutput,
|
|
10
10
|
handoffHookOutput
|
|
@@ -21,14 +21,13 @@ import {
|
|
|
21
21
|
import {
|
|
22
22
|
binFile,
|
|
23
23
|
warmBinCache
|
|
24
|
-
} from "../chunk-
|
|
24
|
+
} from "../chunk-LNU44OJV.js";
|
|
25
25
|
import {
|
|
26
26
|
gitToplevel,
|
|
27
27
|
isRepoActiveForCapture,
|
|
28
28
|
repoActiveFlag,
|
|
29
|
-
repoSyncId,
|
|
30
29
|
setRepoActive
|
|
31
|
-
} from "../chunk-
|
|
30
|
+
} from "../chunk-TDRXHBEX.js";
|
|
32
31
|
import {
|
|
33
32
|
getSiteUrl,
|
|
34
33
|
isSessionEnded
|
|
@@ -102,14 +101,12 @@ async function activeProjectRoot(cwd) {
|
|
|
102
101
|
} catch {
|
|
103
102
|
}
|
|
104
103
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
} catch {
|
|
112
|
-
}
|
|
104
|
+
try {
|
|
105
|
+
await bindRepository(root, {
|
|
106
|
+
signal: AbortSignal.timeout(REPOSITORY_BIND_TIMEOUT_MS),
|
|
107
|
+
quietRefresh: true
|
|
108
|
+
});
|
|
109
|
+
} catch {
|
|
113
110
|
}
|
|
114
111
|
return root;
|
|
115
112
|
} catch {
|
package/dist/index.js
CHANGED
|
@@ -32,9 +32,10 @@ import {
|
|
|
32
32
|
postCommitHookBlock,
|
|
33
33
|
printJson,
|
|
34
34
|
registerSkillCommands,
|
|
35
|
+
resolveRepositoryBinding,
|
|
35
36
|
uninstallPostCommitHookAtPath,
|
|
36
37
|
uninstallProjectPostCommitHook
|
|
37
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-CPHJUQNE.js";
|
|
38
39
|
import {
|
|
39
40
|
fetchFeedbackCapability
|
|
40
41
|
} from "./chunk-KHZNYEUV.js";
|
|
@@ -48,7 +49,7 @@ import {
|
|
|
48
49
|
packageVersion,
|
|
49
50
|
pinnedHookCommand,
|
|
50
51
|
warmBinCache
|
|
51
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-LNU44OJV.js";
|
|
52
53
|
import {
|
|
53
54
|
canonicalGitRoot,
|
|
54
55
|
canonicalRepositoryPath,
|
|
@@ -58,7 +59,7 @@ import {
|
|
|
58
59
|
isValidRepoSyncId,
|
|
59
60
|
repoSyncId,
|
|
60
61
|
setRepoActive
|
|
61
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-TDRXHBEX.js";
|
|
62
63
|
import {
|
|
63
64
|
HttpError,
|
|
64
65
|
REFRESH_TOKEN_PATH,
|
|
@@ -96,22 +97,48 @@ async function applyActivation(active) {
|
|
|
96
97
|
);
|
|
97
98
|
process.exit(1);
|
|
98
99
|
}
|
|
100
|
+
let phase = active ? "post-commit hook coverage" : "local deactivation";
|
|
99
101
|
try {
|
|
100
|
-
let
|
|
102
|
+
let binding;
|
|
101
103
|
let postCommitHook;
|
|
102
104
|
if (active) {
|
|
103
105
|
postCommitHook = ensureEffectivePostCommitHook(root).path;
|
|
104
|
-
|
|
106
|
+
phase = "repository binding";
|
|
107
|
+
binding = await bindRepository(root);
|
|
108
|
+
phase = "local activation";
|
|
105
109
|
}
|
|
106
110
|
setRepoActive(root, active);
|
|
107
111
|
await daemonRequest("statusline_invalidate", {}, { timeoutMs: 250 });
|
|
108
|
-
|
|
112
|
+
if (binding?.status === "pending") {
|
|
113
|
+
process.stderr.write(`[prim] Prim is enabled locally in ${root}
|
|
109
114
|
`);
|
|
110
|
-
|
|
115
|
+
process.stderr.write(
|
|
116
|
+
`[prim] repository ${binding.repositoryFullName} is not connected to Primitive; Moves still ingest into the team graph without repository-specific file attribution, Conflict Gate verification, or commit correlation
|
|
117
|
+
`
|
|
118
|
+
);
|
|
119
|
+
process.stderr.write(
|
|
120
|
+
`[prim] ask an organization owner or administrator to grant Primitive's GitHub App access to this repository through Primitive's GitHub App onboarding; binding retries automatically at the next agent SessionStart
|
|
121
|
+
`
|
|
122
|
+
);
|
|
123
|
+
} else {
|
|
124
|
+
process.stderr.write(`[prim] prim ${active ? "enabled" : "disabled"} in ${root}
|
|
125
|
+
`);
|
|
126
|
+
}
|
|
127
|
+
printJson({
|
|
128
|
+
active,
|
|
129
|
+
repo: root,
|
|
130
|
+
...binding ? {
|
|
131
|
+
bindingStatus: binding.status,
|
|
132
|
+
repositoryFullName: binding.repositoryFullName,
|
|
133
|
+
...binding.status === "connected" ? { repoSyncId: binding.repoSyncId } : {}
|
|
134
|
+
} : {},
|
|
135
|
+
...postCommitHook ? { postCommitHook } : {}
|
|
136
|
+
});
|
|
111
137
|
} catch (err) {
|
|
112
138
|
const detail = err instanceof Error ? err.message : String(err);
|
|
113
139
|
process.stderr.write(
|
|
114
|
-
`[prim] failed to
|
|
140
|
+
active ? `[prim] failed to enable prim during ${phase}: ${detail}
|
|
141
|
+
` : `[prim] failed to disable prim: ${detail}
|
|
115
142
|
`
|
|
116
143
|
);
|
|
117
144
|
process.exit(1);
|
|
@@ -1473,6 +1500,7 @@ var CAPTURE_EVENTS = [
|
|
|
1473
1500
|
"UserPromptSubmit",
|
|
1474
1501
|
"PreToolUse",
|
|
1475
1502
|
"PostToolUse",
|
|
1503
|
+
"PostToolUseFailure",
|
|
1476
1504
|
"Stop",
|
|
1477
1505
|
"SessionEnd",
|
|
1478
1506
|
"SubagentStop"
|
|
@@ -1494,6 +1522,11 @@ var REGISTRATIONS = [
|
|
|
1494
1522
|
),
|
|
1495
1523
|
makeRegistration("PreToolUse", "Edit|Write|MultiEdit|NotebookEdit|Bash", GATE_BIN),
|
|
1496
1524
|
makeRegistration("PostToolUse", "Edit|Write|MultiEdit|NotebookEdit|Bash", POST_TOOL_USE_BIN),
|
|
1525
|
+
makeRegistration(
|
|
1526
|
+
"PostToolUseFailure",
|
|
1527
|
+
"Edit|Write|MultiEdit|NotebookEdit|Bash",
|
|
1528
|
+
POST_TOOL_USE_BIN
|
|
1529
|
+
),
|
|
1497
1530
|
makeRegistration("SessionStart", "*", SESSION_START_BIN),
|
|
1498
1531
|
makeDetachedRegistration("SessionEnd", "*", SESSION_END_BIN)
|
|
1499
1532
|
];
|
|
@@ -1875,6 +1908,8 @@ var GATE_BIN2 = "prim-pre-tool-use";
|
|
|
1875
1908
|
var POST_TOOL_USE_BIN2 = "prim-post-tool-use";
|
|
1876
1909
|
var SESSION_START_BIN2 = "prim-session-start";
|
|
1877
1910
|
var CODEX_ARGS = "--agent codex";
|
|
1911
|
+
var CODEX_EDIT_MATCHER = "apply_patch";
|
|
1912
|
+
var CODEX_POST_TOOL_MATCHER = "apply_patch|Bash";
|
|
1878
1913
|
var JSON_INDENT2 = 2;
|
|
1879
1914
|
var CODEX_CAPTURE_EVENTS = [
|
|
1880
1915
|
"SessionStart",
|
|
@@ -1887,8 +1922,8 @@ var CODEX_CAPTURE_EVENTS = [
|
|
|
1887
1922
|
var PRIM_BINS2 = [CAPTURE_BIN2, GATE_BIN2, POST_TOOL_USE_BIN2, SESSION_START_BIN2];
|
|
1888
1923
|
var CODEX_REGISTRATIONS = [
|
|
1889
1924
|
...CODEX_CAPTURE_EVENTS.map((event) => makeRegistration(event, "*", CAPTURE_BIN2, CODEX_ARGS)),
|
|
1890
|
-
makeRegistration("PreToolUse",
|
|
1891
|
-
makeRegistration("PostToolUse",
|
|
1925
|
+
makeRegistration("PreToolUse", CODEX_EDIT_MATCHER, GATE_BIN2, CODEX_ARGS),
|
|
1926
|
+
makeRegistration("PostToolUse", CODEX_POST_TOOL_MATCHER, POST_TOOL_USE_BIN2, CODEX_ARGS),
|
|
1892
1927
|
makeRegistration("SessionStart", "*", SESSION_START_BIN2, CODEX_ARGS)
|
|
1893
1928
|
];
|
|
1894
1929
|
var USER_SCOPE_PATH2 = join3(homedir3(), ".codex", "hooks.json");
|
|
@@ -3908,19 +3943,66 @@ function checkWorkspaceIdentity() {
|
|
|
3908
3943
|
};
|
|
3909
3944
|
}
|
|
3910
3945
|
}
|
|
3911
|
-
function classifyRepositoryBinding(value) {
|
|
3912
|
-
|
|
3946
|
+
function classifyRepositoryBinding(value, current, active) {
|
|
3947
|
+
if (current.status === "pending") {
|
|
3948
|
+
if (value !== void 0) {
|
|
3949
|
+
return {
|
|
3950
|
+
name: "repo-binding",
|
|
3951
|
+
status: "fail",
|
|
3952
|
+
detail: `local repository binding is stale for ${current.repositoryFullName} \u2014 run \`prim enable\``
|
|
3953
|
+
};
|
|
3954
|
+
}
|
|
3955
|
+
if (!active) {
|
|
3956
|
+
return {
|
|
3957
|
+
name: "repo-binding",
|
|
3958
|
+
status: "fail",
|
|
3959
|
+
detail: "passive capture is inactive \u2014 run `prim enable`"
|
|
3960
|
+
};
|
|
3961
|
+
}
|
|
3962
|
+
return {
|
|
3963
|
+
name: "repo-binding",
|
|
3964
|
+
status: "warn",
|
|
3965
|
+
detail: `${current.repositoryFullName} is not connected to Primitive \u2014 local capture is active, but file scoping, Conflict Gate verification, and commit correlation are unavailable; ask an organization owner/admin to grant the Primitive GitHub App access (retried automatically next SessionStart)`
|
|
3966
|
+
};
|
|
3967
|
+
}
|
|
3968
|
+
if (!isValidRepoSyncId(value)) {
|
|
3969
|
+
return {
|
|
3970
|
+
name: "repo-binding",
|
|
3971
|
+
status: "fail",
|
|
3972
|
+
detail: "missing or invalid local prim.repoSyncId \u2014 run `prim enable`"
|
|
3973
|
+
};
|
|
3974
|
+
}
|
|
3975
|
+
if (value !== current.repoSyncId) {
|
|
3976
|
+
return {
|
|
3977
|
+
name: "repo-binding",
|
|
3978
|
+
status: "fail",
|
|
3979
|
+
detail: "local repository binding is stale for the current origin \u2014 run `prim enable`"
|
|
3980
|
+
};
|
|
3981
|
+
}
|
|
3982
|
+
return {
|
|
3913
3983
|
name: "repo-binding",
|
|
3914
3984
|
status: "ok",
|
|
3915
|
-
detail: "
|
|
3916
|
-
} : {
|
|
3917
|
-
name: "repo-binding",
|
|
3918
|
-
status: "fail",
|
|
3919
|
-
detail: "missing or invalid local prim.repoSyncId \u2014 run `prim enable`"
|
|
3985
|
+
detail: "local repository binding matches the current server binding"
|
|
3920
3986
|
};
|
|
3921
3987
|
}
|
|
3922
|
-
function checkRepositoryBinding() {
|
|
3923
|
-
|
|
3988
|
+
async function checkRepositoryBinding() {
|
|
3989
|
+
const root = process.cwd();
|
|
3990
|
+
const local = repoSyncId(root);
|
|
3991
|
+
try {
|
|
3992
|
+
const current = await resolveRepositoryBinding(root, {
|
|
3993
|
+
signal: AbortSignal.timeout(CONNECTIVITY_TIMEOUT_MS),
|
|
3994
|
+
quietRefresh: true
|
|
3995
|
+
});
|
|
3996
|
+
return classifyRepositoryBinding(local, current, isRepoActiveForCapture(root));
|
|
3997
|
+
} catch (error) {
|
|
3998
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3999
|
+
const detail = boundedHealthError(`could not verify the current repository binding \u2014 ${message}`) ?? "could not verify the current repository binding";
|
|
4000
|
+
return {
|
|
4001
|
+
name: "repo-binding",
|
|
4002
|
+
status: "fail",
|
|
4003
|
+
detail
|
|
4004
|
+
};
|
|
4005
|
+
}
|
|
3924
4006
|
}
|
|
3925
4007
|
function classifyPostCommitHook(inspection) {
|
|
3926
4008
|
if (inspection.covered) {
|
|
@@ -4067,7 +4149,7 @@ async function collectChecks() {
|
|
|
4067
4149
|
checkStranded(),
|
|
4068
4150
|
checkFeedbackHooks(),
|
|
4069
4151
|
checkWorkspaceIdentity(),
|
|
4070
|
-
checkRepositoryBinding(),
|
|
4152
|
+
await checkRepositoryBinding(),
|
|
4071
4153
|
checkPostCommitHook(),
|
|
4072
4154
|
...backend,
|
|
4073
4155
|
await checkFeedbackCapability()
|
|
@@ -4176,6 +4258,7 @@ var REGISTRATIONS2 = [
|
|
|
4176
4258
|
...CAPTURE_EVENTS2.map((event) => ({ event, bin: CAPTURE_BIN3 })),
|
|
4177
4259
|
{ event: "pre_tool_call", matcher: EDIT_MATCHER, bin: GATE_BIN3, timeout: GATE_TIMEOUT_SECONDS },
|
|
4178
4260
|
{ event: "post_tool_call", matcher: EDIT_MATCHER, bin: POST_TOOL_USE_BIN3 },
|
|
4261
|
+
{ event: "post_approval_response", bin: POST_TOOL_USE_BIN3 },
|
|
4179
4262
|
{ event: "on_session_start", bin: SESSION_START_BIN3 },
|
|
4180
4263
|
{ event: "on_session_end", bin: SESSION_END_BIN2 }
|
|
4181
4264
|
];
|
package/package.json
CHANGED