@primitive.ai/prim 0.1.0-alpha.93 → 0.1.0-alpha.96

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.
Files changed (41) hide show
  1. package/README.md +57 -12
  2. package/SKILL.md +5 -2
  3. package/dist/{chunk-UKUAAAXE.js → chunk-27ADT6FQ.js} +2 -2
  4. package/dist/{chunk-OTHKG76J.js → chunk-35FMRWJH.js} +1 -1
  5. package/dist/{chunk-DXJQR4QI.js → chunk-4GHANPWQ.js} +2 -2
  6. package/dist/{chunk-DCJN6LZH.js → chunk-7KABYYWG.js} +747 -430
  7. package/dist/{chunk-LFFLHSQO.js → chunk-CU7RW7XU.js} +63 -6
  8. package/dist/{chunk-H4UNYFUC.js → chunk-DHOQGHKQ.js} +184 -1
  9. package/dist/{chunk-2GP5UFV7.js → chunk-DWRSEC34.js} +5 -3
  10. package/dist/{chunk-36TWVNBE.js → chunk-FVDBULGZ.js} +9 -11
  11. package/dist/{chunk-G2VMA2QO.js → chunk-LY6NJ7KL.js} +6 -4
  12. package/dist/{chunk-ZB4F75SZ.js → chunk-MXVCP33E.js} +5 -1
  13. package/dist/{chunk-TYAHC25F.js → chunk-QCBB5HFX.js} +1 -1
  14. package/dist/{chunk-C3VAA5CG.js → chunk-RK4ZS3HG.js} +2 -2
  15. package/dist/{chunk-ZU563PQI.js → chunk-ROLYLXJS.js} +2 -2
  16. package/dist/{chunk-OH3EZXYX.js → chunk-UO2U6IKF.js} +1 -1
  17. package/dist/{chunk-K7D2EYBS.js → chunk-URLLSALP.js} +2 -2
  18. package/dist/chunk-XEDJ5N3M.js +177 -0
  19. package/dist/{chunk-X64HTHUF.js → chunk-Y5W4TZM7.js} +202 -10
  20. package/dist/{chunk-ICM2XCXS.js → chunk-YYE2NLWX.js} +2 -2
  21. package/dist/{chunk-DSWT6BCC.js → chunk-Z6NPNLOT.js} +825 -665
  22. package/dist/daemon/server.js +836 -540
  23. package/dist/hook-runtime/daemon/server.js +836 -540
  24. package/dist/hook-runtime/hooks/post-commit.js +978 -566
  25. package/dist/hook-runtime/hooks/post-rewrite.js +836 -540
  26. package/dist/hook-runtime/hooks/post-tool-use.js +1215 -796
  27. package/dist/hook-runtime/hooks/pre-tool-use.js +2100 -1741
  28. package/dist/hook-runtime/hooks/prim-hook.js +1312 -861
  29. package/dist/hook-runtime/hooks/session-end.js +232 -134
  30. package/dist/hook-runtime/hooks/session-start.js +1799 -935
  31. package/dist/hook-runtime/index.js +3628 -2461
  32. package/dist/hooks/post-commit.js +14 -10
  33. package/dist/hooks/post-rewrite.js +10 -10
  34. package/dist/hooks/post-tool-use.js +20 -20
  35. package/dist/hooks/pre-commit.js +4 -4
  36. package/dist/hooks/pre-tool-use.js +29 -17
  37. package/dist/hooks/prim-hook.js +22 -18
  38. package/dist/hooks/session-end.js +11 -5
  39. package/dist/hooks/session-start.js +46 -28
  40. package/dist/index.js +623 -390
  41. package/package.json +1 -1
@@ -1,30 +1,33 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ recordPostCommitFired
4
+ } from "../chunk-XEDJ5N3M.js";
2
5
  import {
3
6
  unattendedEnv
4
7
  } from "../chunk-OYHYCK4K.js";
5
8
  import {
6
9
  commitAttributionFromEnvironment,
7
10
  toCommitMove
8
- } from "../chunk-ICM2XCXS.js";
11
+ } from "../chunk-YYE2NLWX.js";
9
12
  import {
10
13
  getOrCreateWorkspaceId
11
14
  } from "../chunk-EZXEWFDG.js";
12
15
  import {
13
16
  appendMove,
14
17
  resolveOrg
15
- } from "../chunk-DXJQR4QI.js";
16
- import "../chunk-K7D2EYBS.js";
18
+ } from "../chunk-4GHANPWQ.js";
19
+ import "../chunk-URLLSALP.js";
17
20
  import {
18
- cachedCollectScopeAdmits,
19
- isRepoActiveForCapture,
20
- repoSyncId
21
- } from "../chunk-DSWT6BCC.js";
22
- import "../chunk-G2VMA2QO.js";
21
+ cachedCollectScopeAdmits
22
+ } from "../chunk-Z6NPNLOT.js";
23
+ import "../chunk-LY6NJ7KL.js";
23
24
  import {
24
25
  githubRepositoryFullName,
26
+ isRepoActiveForCapture,
27
+ repoSyncId,
25
28
  resolveRepositoryContext
26
- } from "../chunk-H4UNYFUC.js";
27
- import "../chunk-2GP5UFV7.js";
29
+ } from "../chunk-DHOQGHKQ.js";
30
+ import "../chunk-DWRSEC34.js";
28
31
 
29
32
  // src/hooks/post-commit.ts
30
33
  import { execFileSync, spawn } from "child_process";
@@ -141,6 +144,7 @@ function spawnBackgroundFlush() {
141
144
  }
142
145
  function runPostCommit() {
143
146
  const cwd = gitText(["rev-parse", "--show-toplevel"]) ?? process.cwd();
147
+ recordPostCommitFired(cwd, process.env.PRIM_COMMIT_SHA);
144
148
  if (!isRepoActiveForCapture(cwd)) {
145
149
  return;
146
150
  }
@@ -5,26 +5,26 @@ import {
5
5
  import {
6
6
  canonicalRewritePairs,
7
7
  toRewriteMove
8
- } from "../chunk-ICM2XCXS.js";
8
+ } from "../chunk-YYE2NLWX.js";
9
9
  import {
10
10
  getOrCreateWorkspaceId
11
11
  } from "../chunk-EZXEWFDG.js";
12
12
  import {
13
13
  appendMove,
14
14
  resolveOrg
15
- } from "../chunk-DXJQR4QI.js";
16
- import "../chunk-K7D2EYBS.js";
15
+ } from "../chunk-4GHANPWQ.js";
16
+ import "../chunk-URLLSALP.js";
17
17
  import {
18
- cachedCollectScopeAdmits,
19
- isRepoActiveForCapture,
20
- repoSyncId
21
- } from "../chunk-DSWT6BCC.js";
22
- import "../chunk-G2VMA2QO.js";
18
+ cachedCollectScopeAdmits
19
+ } from "../chunk-Z6NPNLOT.js";
20
+ import "../chunk-LY6NJ7KL.js";
23
21
  import {
24
22
  githubRepositoryFullName,
23
+ isRepoActiveForCapture,
24
+ repoSyncId,
25
25
  resolveRepositoryContext
26
- } from "../chunk-H4UNYFUC.js";
27
- import "../chunk-2GP5UFV7.js";
26
+ } from "../chunk-DHOQGHKQ.js";
27
+ import "../chunk-DWRSEC34.js";
28
28
 
29
29
  // src/hooks/post-rewrite.ts
30
30
  import { execFileSync, spawn } from "child_process";
@@ -1,56 +1,56 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  requireDurableIngestAcknowledgement
4
- } from "../chunk-TYAHC25F.js";
4
+ } from "../chunk-QCBB5HFX.js";
5
5
  import {
6
6
  enrichHookPayloadWithFileRefs,
7
7
  preserveHookFileMetadata
8
- } from "../chunk-LFFLHSQO.js";
8
+ } from "../chunk-CU7RW7XU.js";
9
9
  import {
10
10
  postToolInvocationId,
11
11
  toMove,
12
12
  toolOutcomeFor
13
- } from "../chunk-ICM2XCXS.js";
13
+ } from "../chunk-YYE2NLWX.js";
14
14
  import {
15
15
  getOrCreateWorkspaceId
16
16
  } from "../chunk-EZXEWFDG.js";
17
17
  import {
18
18
  appendMove,
19
19
  resolveOrg
20
- } from "../chunk-DXJQR4QI.js";
21
- import "../chunk-ZB4F75SZ.js";
20
+ } from "../chunk-4GHANPWQ.js";
21
+ import "../chunk-MXVCP33E.js";
22
22
  import {
23
23
  appendCodexContext,
24
24
  prepareCodexContext
25
- } from "../chunk-36TWVNBE.js";
26
- import "../chunk-ZU563PQI.js";
25
+ } from "../chunk-FVDBULGZ.js";
26
+ import "../chunk-ROLYLXJS.js";
27
27
  import {
28
28
  scrubFromCwd
29
- } from "../chunk-K7D2EYBS.js";
29
+ } from "../chunk-URLLSALP.js";
30
30
  import {
31
31
  bold,
32
32
  cachedCollectScopeAdmits,
33
- color,
34
- isRepoActiveForCapture,
35
- repoSyncId
36
- } from "../chunk-DSWT6BCC.js";
33
+ color
34
+ } from "../chunk-Z6NPNLOT.js";
37
35
  import {
38
36
  getClient,
39
37
  terminalSafeLine
40
- } from "../chunk-G2VMA2QO.js";
38
+ } from "../chunk-LY6NJ7KL.js";
41
39
  import {
42
40
  normalizeEnvelope,
43
41
  parseAgent,
44
42
  readHookStdin,
45
43
  shouldSuppressImportedCursorHandler
46
- } from "../chunk-C3VAA5CG.js";
47
- import "../chunk-X64HTHUF.js";
44
+ } from "../chunk-RK4ZS3HG.js";
45
+ import "../chunk-Y5W4TZM7.js";
48
46
  import {
49
47
  currentBranch,
48
+ isRepoActiveForCapture,
49
+ repoSyncId,
50
50
  resolveRepositoryContext
51
- } from "../chunk-H4UNYFUC.js";
52
- import "../chunk-OTHKG76J.js";
53
- import "../chunk-2GP5UFV7.js";
51
+ } from "../chunk-DHOQGHKQ.js";
52
+ import "../chunk-35FMRWJH.js";
53
+ import "../chunk-DWRSEC34.js";
54
54
 
55
55
  // src/hooks/post-tool-use.ts
56
56
  import { readFileSync } from "fs";
@@ -127,7 +127,7 @@ async function emitWithAcknowledgment(output, acknowledge) {
127
127
  await acknowledge?.(handedOff);
128
128
  }
129
129
  async function emitCursorContext(envelope) {
130
- if (typeof envelope.session_id !== "string" || envelope.session_id.length === 0 || typeof envelope.cwd !== "string" || envelope.cwd.length === 0) {
130
+ if (!isRepoActiveForCapture(envelope.cwd ?? process.cwd()) || typeof envelope.session_id !== "string" || envelope.session_id.length === 0 || typeof envelope.cwd !== "string" || envelope.cwd.length === 0) {
131
131
  await emit();
132
132
  return;
133
133
  }
@@ -225,7 +225,7 @@ async function main() {
225
225
  await finish(agent, envelope);
226
226
  return;
227
227
  }
228
- if (resolution.shellMutation === void 0 && resolution.fileRefs.length === 0) {
228
+ if (resolution.shellMutation === void 0 && resolution.fileRefs.length === 0 && !resolution.targetCheckouts?.length) {
229
229
  await finish(agent, envelope);
230
230
  return;
231
231
  }
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  checkAffectedDecisions,
4
4
  formatDecisionsWarning
5
- } from "../chunk-UKUAAAXE.js";
6
- import "../chunk-G2VMA2QO.js";
7
- import "../chunk-OTHKG76J.js";
8
- import "../chunk-2GP5UFV7.js";
5
+ } from "../chunk-27ADT6FQ.js";
6
+ import "../chunk-LY6NJ7KL.js";
7
+ import "../chunk-35FMRWJH.js";
8
+ import "../chunk-DWRSEC34.js";
9
9
 
10
10
  // src/hooks/pre-commit.ts
11
11
  import { execSync } from "child_process";
@@ -12,43 +12,46 @@ import {
12
12
  failOpenHermes,
13
13
  failOpenOutput,
14
14
  readHookMode
15
- } from "../chunk-ZB4F75SZ.js";
15
+ } from "../chunk-MXVCP33E.js";
16
16
  import {
17
17
  appendCodexContext,
18
18
  hasVisibleCodexMessage,
19
19
  prepareCodexContext
20
- } from "../chunk-36TWVNBE.js";
21
- import "../chunk-ZU563PQI.js";
20
+ } from "../chunk-FVDBULGZ.js";
21
+ import "../chunk-ROLYLXJS.js";
22
22
  import {
23
23
  DEFAULT_RULES,
24
24
  scrub
25
- } from "../chunk-K7D2EYBS.js";
25
+ } from "../chunk-URLLSALP.js";
26
26
  import {
27
27
  boundedHealthError,
28
- cachedCollectScopeAdmits,
29
- isRepoActive,
30
- repoSyncId
31
- } from "../chunk-DSWT6BCC.js";
28
+ cachedCollectScopeAdmits
29
+ } from "../chunk-Z6NPNLOT.js";
32
30
  import {
31
+ HttpError,
33
32
  getClient
34
- } from "../chunk-G2VMA2QO.js";
33
+ } from "../chunk-LY6NJ7KL.js";
35
34
  import {
36
35
  normalizeEnvelope,
37
36
  parseAgent,
38
37
  readHookStdin,
39
38
  shouldSuppressImportedCursorHandler
40
- } from "../chunk-C3VAA5CG.js";
39
+ } from "../chunk-RK4ZS3HG.js";
41
40
  import {
42
41
  packageVersion
43
- } from "../chunk-X64HTHUF.js";
42
+ } from "../chunk-Y5W4TZM7.js";
44
43
  import {
45
44
  canonicalGitRoot,
46
45
  canonicalRepositoryPath,
47
46
  currentBranch,
48
- githubRepositoryFullName
49
- } from "../chunk-H4UNYFUC.js";
50
- import "../chunk-OTHKG76J.js";
51
- import "../chunk-2GP5UFV7.js";
47
+ githubRepositoryFullName,
48
+ isRepoActive,
49
+ repoSyncId
50
+ } from "../chunk-DHOQGHKQ.js";
51
+ import "../chunk-35FMRWJH.js";
52
+ import {
53
+ resolveAuthCredential
54
+ } from "../chunk-DWRSEC34.js";
52
55
 
53
56
  // src/hooks/preflight-v3.ts
54
57
  import { Buffer } from "buffer";
@@ -216,6 +219,15 @@ function hermesAdvisory(result, aggregate) {
216
219
  const message = [...new Set(parts.filter(Boolean))].join("\n");
217
220
  return message.startsWith("[primitive]") ? message : message ? `[primitive] ${message}` : "";
218
221
  }
222
+ function preflightFailure(error) {
223
+ if (!(error instanceof HttpError && error.status === 401)) {
224
+ return "enforcement service unavailable; change was not verified";
225
+ }
226
+ if (resolveAuthCredential()?.source === "environment") {
227
+ return "PRIM_TOKEN was rejected; change was not verified";
228
+ }
229
+ return "authentication required; run `prim auth login`; change was not verified";
230
+ }
219
231
  async function emitUnverified(message, envelope) {
220
232
  const result = unverifiedResult(message);
221
233
  if (agent === "hermes") {
@@ -337,8 +349,8 @@ async function main() {
337
349
  return;
338
350
  }
339
351
  result = resultForPreflight(response);
340
- } catch {
341
- await emitUnverified("enforcement service unavailable; change was not verified", envelope);
352
+ } catch (error) {
353
+ await emitUnverified(preflightFailure(error), envelope);
342
354
  return;
343
355
  }
344
356
  const aggregate = demoteForMode(
@@ -8,54 +8,57 @@ import {
8
8
  acknowledgeDecisionFeedback,
9
9
  leaseDecisionFeedback,
10
10
  renderFeedback
11
- } from "../chunk-OH3EZXYX.js";
11
+ } from "../chunk-UO2U6IKF.js";
12
+ import {
13
+ recordConversationCaptured
14
+ } from "../chunk-XEDJ5N3M.js";
12
15
  import {
13
16
  unattendedEnv
14
17
  } from "../chunk-OYHYCK4K.js";
15
18
  import {
16
19
  enrichHookPayloadWithFileRefs,
17
20
  preserveHookFileMetadata
18
- } from "../chunk-LFFLHSQO.js";
21
+ } from "../chunk-CU7RW7XU.js";
19
22
  import {
20
23
  postToolInvocationId,
21
24
  shouldFlushAfter,
22
25
  toMove
23
- } from "../chunk-ICM2XCXS.js";
26
+ } from "../chunk-YYE2NLWX.js";
24
27
  import {
25
28
  getOrCreateWorkspaceId
26
29
  } from "../chunk-EZXEWFDG.js";
27
30
  import {
28
31
  appendMove,
29
32
  resolveOrg
30
- } from "../chunk-DXJQR4QI.js";
31
- import "../chunk-ZB4F75SZ.js";
33
+ } from "../chunk-4GHANPWQ.js";
34
+ import "../chunk-MXVCP33E.js";
32
35
  import {
33
36
  prepareCodexContext
34
- } from "../chunk-36TWVNBE.js";
35
- import "../chunk-ZU563PQI.js";
37
+ } from "../chunk-FVDBULGZ.js";
38
+ import "../chunk-ROLYLXJS.js";
36
39
  import {
37
40
  scrubFromCwd,
38
41
  writeHookDebug
39
- } from "../chunk-K7D2EYBS.js";
42
+ } from "../chunk-URLLSALP.js";
40
43
  import {
41
- cachedCollectScopeAdmits,
42
- isRepoActiveForCapture,
43
- repoSyncId
44
- } from "../chunk-DSWT6BCC.js";
45
- import "../chunk-G2VMA2QO.js";
44
+ cachedCollectScopeAdmits
45
+ } from "../chunk-Z6NPNLOT.js";
46
+ import "../chunk-LY6NJ7KL.js";
46
47
  import {
47
48
  normalizeEnvelope,
48
49
  parseAgent,
49
50
  readHookStdin,
50
51
  shouldSuppressImportedCursorHandler
51
- } from "../chunk-C3VAA5CG.js";
52
- import "../chunk-X64HTHUF.js";
52
+ } from "../chunk-RK4ZS3HG.js";
53
+ import "../chunk-Y5W4TZM7.js";
53
54
  import {
54
55
  currentBranch,
56
+ isRepoActiveForCapture,
57
+ repoSyncId,
55
58
  resolveRepositoryContext
56
- } from "../chunk-H4UNYFUC.js";
57
- import "../chunk-OTHKG76J.js";
58
- import "../chunk-2GP5UFV7.js";
59
+ } from "../chunk-DHOQGHKQ.js";
60
+ import "../chunk-35FMRWJH.js";
61
+ import "../chunk-DWRSEC34.js";
59
62
 
60
63
  // src/hooks/prim-hook.ts
61
64
  import { spawn } from "child_process";
@@ -176,6 +179,7 @@ async function main() {
176
179
  };
177
180
  const { orgId } = resolveOrg({ sessionId: move.sessionId, cwd });
178
181
  appendMove(move, orgId);
182
+ if (move.eventType === "UserPromptSubmit") recordConversationCaptured(cwd, agent);
179
183
  if (shouldFlushAfter(move.eventType, agent)) {
180
184
  spawnBackgroundFlush();
181
185
  }
@@ -4,13 +4,15 @@ import {
4
4
  parseAgent,
5
5
  readHookStdin,
6
6
  shouldSuppressImportedCursorHandler
7
- } from "../chunk-C3VAA5CG.js";
8
- import "../chunk-X64HTHUF.js";
9
- import "../chunk-H4UNYFUC.js";
7
+ } from "../chunk-RK4ZS3HG.js";
8
+ import "../chunk-Y5W4TZM7.js";
9
+ import {
10
+ isRepoActiveForCapture
11
+ } from "../chunk-DHOQGHKQ.js";
10
12
  import {
11
13
  daemonRequest
12
- } from "../chunk-OTHKG76J.js";
13
- import "../chunk-2GP5UFV7.js";
14
+ } from "../chunk-35FMRWJH.js";
15
+ import "../chunk-DWRSEC34.js";
14
16
 
15
17
  // src/hooks/session-end.ts
16
18
  var STDIN_TIMEOUT_MS = 1e3;
@@ -47,6 +49,10 @@ async function main() {
47
49
  emit();
48
50
  return;
49
51
  }
52
+ if (!isRepoActiveForCapture(envelope.cwd ?? process.cwd())) {
53
+ emit();
54
+ return;
55
+ }
50
56
  await daemonRequest(
51
57
  "session_end",
52
58
  { sessionId: envelope.session_id },
@@ -1,14 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  bindRepository,
4
- ensureEffectivePostCommitHook,
5
- ensureEffectivePostRewriteHook,
4
+ ensureEffectiveGitHook,
6
5
  hasUsableCodexGuidance,
7
6
  hasUsableCursorSkill,
8
7
  kickDaemonEnsure,
9
8
  refreshClaudePlugins,
10
9
  warmBinCache
11
- } from "../chunk-DCJN6LZH.js";
10
+ } from "../chunk-7KABYYWG.js";
12
11
  import {
13
12
  buildHookOutput,
14
13
  handoffHookOutput
@@ -18,39 +17,45 @@ import {
18
17
  acknowledgeDecisionFeedback,
19
18
  leaseDecisionFeedback,
20
19
  renderFeedback
21
- } from "../chunk-OH3EZXYX.js";
20
+ } from "../chunk-UO2U6IKF.js";
21
+ import {
22
+ clearHooksWired,
23
+ recordHooksWired
24
+ } from "../chunk-XEDJ5N3M.js";
22
25
  import "../chunk-OYHYCK4K.js";
23
26
  import {
24
27
  getOrCreateWorkspaceId
25
28
  } from "../chunk-EZXEWFDG.js";
26
29
  import {
27
30
  prepareCodexContext
28
- } from "../chunk-36TWVNBE.js";
29
- import "../chunk-ZU563PQI.js";
31
+ } from "../chunk-FVDBULGZ.js";
32
+ import "../chunk-ROLYLXJS.js";
30
33
  import {
31
- fetchAndCacheCollectScope,
32
- isRepoActiveForCapture,
33
- repoActiveFlag,
34
- setRepoActive
35
- } from "../chunk-DSWT6BCC.js";
34
+ fetchAndCacheCollectScope
35
+ } from "../chunk-Z6NPNLOT.js";
36
36
  import {
37
37
  getSiteUrl,
38
38
  isSessionEnded
39
- } from "../chunk-G2VMA2QO.js";
39
+ } from "../chunk-LY6NJ7KL.js";
40
40
  import {
41
41
  normalizeEnvelope,
42
42
  parseAgent,
43
43
  readHookStdin,
44
44
  shouldSuppressImportedCursorHandler
45
- } from "../chunk-C3VAA5CG.js";
46
- import "../chunk-X64HTHUF.js";
45
+ } from "../chunk-RK4ZS3HG.js";
46
+ import {
47
+ MANAGED_GIT_HOOK_NAMES
48
+ } from "../chunk-Y5W4TZM7.js";
47
49
  import {
48
- gitToplevel
49
- } from "../chunk-H4UNYFUC.js";
50
+ gitToplevel,
51
+ isRepoActiveForCapture,
52
+ repoActiveFlag,
53
+ setRepoActive
54
+ } from "../chunk-DHOQGHKQ.js";
50
55
  import {
51
56
  daemonRequest
52
- } from "../chunk-OTHKG76J.js";
53
- import "../chunk-2GP5UFV7.js";
57
+ } from "../chunk-35FMRWJH.js";
58
+ import "../chunk-DWRSEC34.js";
54
59
 
55
60
  // src/hooks/reauth-notice.ts
56
61
  var REAUTH_NOTICE = "[prim] authentication ended \u2014 run `prim auth login` to resume decision capture";
@@ -73,7 +78,11 @@ var CODEX_PRIM_REMINDER = primReminder(CODEX_PRIM_ACTION, CODEX_PRIM_ACTION);
73
78
  async function activeProjectRoot(cwd) {
74
79
  try {
75
80
  const root = gitToplevel(cwd);
76
- if (!root || !isRepoActiveForCapture(cwd)) return null;
81
+ if (!root) return null;
82
+ if (!isRepoActiveForCapture(cwd)) {
83
+ if (repoActiveFlag(root) === "false") clearHooksWired(root);
84
+ return null;
85
+ }
77
86
  let shellGateActive = repoActiveFlag(root) === "true";
78
87
  if (!shellGateActive) {
79
88
  try {
@@ -83,13 +92,18 @@ async function activeProjectRoot(cwd) {
83
92
  }
84
93
  }
85
94
  if (shellGateActive) {
86
- try {
87
- ensureEffectivePostCommitHook(root);
88
- } catch {
89
- }
90
- try {
91
- ensureEffectivePostRewriteHook(root);
92
- } catch {
95
+ for (const hookName of MANAGED_GIT_HOOK_NAMES) {
96
+ try {
97
+ const result = ensureEffectiveGitHook(hookName, root, {
98
+ context: "ambient",
99
+ repairOnly: hookName === "pre-commit"
100
+ });
101
+ if (hookName === "post-commit" && // Manual mode: the user's own wiring is expected to reach prim too.
102
+ ["created", "updated", "unchanged", "manual"].includes(result.outcome)) {
103
+ recordHooksWired(root, { onlyIfAbsent: true });
104
+ }
105
+ } catch {
106
+ }
93
107
  }
94
108
  }
95
109
  try {
@@ -132,13 +146,18 @@ async function processSessionStart(raw, agent, feedbackSignal) {
132
146
  if (typeof envelope.session_id !== "string" || envelope.session_id.length === 0) {
133
147
  return { output: buildHookOutput({}) };
134
148
  }
149
+ const cwd = envelope.cwd ?? process.cwd();
150
+ if (!gitToplevel(cwd) || !isRepoActiveForCapture(cwd)) {
151
+ if (repoActiveFlag(cwd) === "false") clearHooksWired(cwd);
152
+ return { output: agent === "cursor" ? {} : buildHookOutput({}) };
153
+ }
154
+ warmBinCache();
135
155
  kickDaemonEnsure();
136
156
  await daemonRequest(
137
157
  "session_start",
138
158
  { sessionId: envelope.session_id, callerEnv: getSiteUrl() },
139
159
  { timeoutMs: DAEMON_TIMEOUT_MS }
140
160
  );
141
- const cwd = envelope.cwd ?? process.cwd();
142
161
  let projectRoot = null;
143
162
  let active = false;
144
163
  let skillState = { installed: 0, refreshed: 0 };
@@ -265,7 +284,6 @@ function emitOutput(output, acknowledge) {
265
284
  return handoffHookOutput(output, acknowledge);
266
285
  }
267
286
  async function main() {
268
- warmBinCache();
269
287
  const agent = parseAgent(process.argv);
270
288
  let raw;
271
289
  try {