@neurcode-ai/cli 0.14.0 → 0.15.0

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 (188) hide show
  1. package/README.md +60 -8
  2. package/dist/api-client.d.ts +284 -0
  3. package/dist/api-client.d.ts.map +1 -1
  4. package/dist/api-client.js +111 -0
  5. package/dist/api-client.js.map +1 -1
  6. package/dist/commands/activate.d.ts +82 -0
  7. package/dist/commands/activate.d.ts.map +1 -0
  8. package/dist/commands/activate.js +551 -0
  9. package/dist/commands/activate.js.map +1 -0
  10. package/dist/commands/admission.d.ts +67 -0
  11. package/dist/commands/admission.d.ts.map +1 -0
  12. package/dist/commands/admission.js +350 -0
  13. package/dist/commands/admission.js.map +1 -0
  14. package/dist/commands/agent.d.ts +3 -0
  15. package/dist/commands/agent.d.ts.map +1 -0
  16. package/dist/commands/agent.js +2045 -0
  17. package/dist/commands/agent.js.map +1 -0
  18. package/dist/commands/demo.d.ts +3 -0
  19. package/dist/commands/demo.d.ts.map +1 -0
  20. package/dist/commands/demo.js +102 -0
  21. package/dist/commands/demo.js.map +1 -0
  22. package/dist/commands/init.d.ts.map +1 -1
  23. package/dist/commands/init.js +58 -44
  24. package/dist/commands/init.js.map +1 -1
  25. package/dist/commands/login.d.ts +1 -1
  26. package/dist/commands/login.d.ts.map +1 -1
  27. package/dist/commands/login.js +44 -22
  28. package/dist/commands/login.js.map +1 -1
  29. package/dist/commands/profile.d.ts +14 -0
  30. package/dist/commands/profile.d.ts.map +1 -0
  31. package/dist/commands/profile.js +118 -0
  32. package/dist/commands/profile.js.map +1 -0
  33. package/dist/commands/quickstart.d.ts +2 -2
  34. package/dist/commands/quickstart.d.ts.map +1 -1
  35. package/dist/commands/quickstart.js +31 -30
  36. package/dist/commands/quickstart.js.map +1 -1
  37. package/dist/commands/remediate-export.d.ts +6 -1
  38. package/dist/commands/remediate-export.d.ts.map +1 -1
  39. package/dist/commands/remediate-export.js +359 -7
  40. package/dist/commands/remediate-export.js.map +1 -1
  41. package/dist/commands/replay.d.ts.map +1 -1
  42. package/dist/commands/replay.js +84 -0
  43. package/dist/commands/replay.js.map +1 -1
  44. package/dist/commands/run.d.ts +3 -0
  45. package/dist/commands/run.d.ts.map +1 -0
  46. package/dist/commands/run.js +98 -0
  47. package/dist/commands/run.js.map +1 -0
  48. package/dist/commands/runtime-adapter.d.ts +8 -0
  49. package/dist/commands/runtime-adapter.d.ts.map +1 -0
  50. package/dist/commands/runtime-adapter.js +375 -0
  51. package/dist/commands/runtime-adapter.js.map +1 -0
  52. package/dist/commands/runtime-doctor.d.ts +6 -0
  53. package/dist/commands/runtime-doctor.d.ts.map +1 -0
  54. package/dist/commands/runtime-doctor.js +478 -0
  55. package/dist/commands/runtime-doctor.js.map +1 -0
  56. package/dist/commands/runtime-report.d.ts +13 -0
  57. package/dist/commands/runtime-report.d.ts.map +1 -0
  58. package/dist/commands/runtime-report.js +81 -0
  59. package/dist/commands/runtime-report.js.map +1 -0
  60. package/dist/commands/runtime-sync.d.ts +17 -0
  61. package/dist/commands/runtime-sync.d.ts.map +1 -0
  62. package/dist/commands/runtime-sync.js +656 -0
  63. package/dist/commands/runtime-sync.js.map +1 -0
  64. package/dist/commands/runtime.d.ts +16 -0
  65. package/dist/commands/runtime.d.ts.map +1 -0
  66. package/dist/commands/runtime.js +380 -0
  67. package/dist/commands/runtime.js.map +1 -0
  68. package/dist/commands/session-hook.d.ts +35 -0
  69. package/dist/commands/session-hook.d.ts.map +1 -0
  70. package/dist/commands/session-hook.js +1297 -0
  71. package/dist/commands/session-hook.js.map +1 -0
  72. package/dist/commands/session.d.ts +91 -0
  73. package/dist/commands/session.d.ts.map +1 -1
  74. package/dist/commands/session.js +1226 -0
  75. package/dist/commands/session.js.map +1 -1
  76. package/dist/commands/whoami.d.ts +7 -4
  77. package/dist/commands/whoami.d.ts.map +1 -1
  78. package/dist/commands/whoami.js +59 -34
  79. package/dist/commands/whoami.js.map +1 -1
  80. package/dist/config.d.ts.map +1 -1
  81. package/dist/config.js +24 -5
  82. package/dist/config.js.map +1 -1
  83. package/dist/daemon/routes.d.ts.map +1 -1
  84. package/dist/daemon/routes.js +8 -0
  85. package/dist/daemon/routes.js.map +1 -1
  86. package/dist/daemon/server.d.ts.map +1 -1
  87. package/dist/daemon/server.js +88 -0
  88. package/dist/daemon/server.js.map +1 -1
  89. package/dist/governance/impact-analysis.d.ts +27 -0
  90. package/dist/governance/impact-analysis.d.ts.map +1 -0
  91. package/dist/governance/impact-analysis.js +274 -0
  92. package/dist/governance/impact-analysis.js.map +1 -0
  93. package/dist/index.js +472 -29
  94. package/dist/index.js.map +1 -1
  95. package/dist/intent-engine/matcher.d.ts.map +1 -1
  96. package/dist/intent-engine/matcher.js +3 -12
  97. package/dist/intent-engine/matcher.js.map +1 -1
  98. package/dist/utils/admission-artifact.d.ts +59 -0
  99. package/dist/utils/admission-artifact.d.ts.map +1 -0
  100. package/dist/utils/admission-artifact.js +410 -0
  101. package/dist/utils/admission-artifact.js.map +1 -0
  102. package/dist/utils/agent-adapter-setup.d.ts +80 -0
  103. package/dist/utils/agent-adapter-setup.d.ts.map +1 -0
  104. package/dist/utils/agent-adapter-setup.js +577 -0
  105. package/dist/utils/agent-adapter-setup.js.map +1 -0
  106. package/dist/utils/agent-guard-supervisor.d.ts +75 -0
  107. package/dist/utils/agent-guard-supervisor.d.ts.map +1 -0
  108. package/dist/utils/agent-guard-supervisor.js +388 -0
  109. package/dist/utils/agent-guard-supervisor.js.map +1 -0
  110. package/dist/utils/agent-guard.d.ts +92 -0
  111. package/dist/utils/agent-guard.d.ts.map +1 -0
  112. package/dist/utils/agent-guard.js +326 -0
  113. package/dist/utils/agent-guard.js.map +1 -0
  114. package/dist/utils/agent-session-launcher.d.ts +89 -0
  115. package/dist/utils/agent-session-launcher.d.ts.map +1 -0
  116. package/dist/utils/agent-session-launcher.js +308 -0
  117. package/dist/utils/agent-session-launcher.js.map +1 -0
  118. package/dist/utils/bash-command-analysis.d.ts +19 -0
  119. package/dist/utils/bash-command-analysis.d.ts.map +1 -0
  120. package/dist/utils/bash-command-analysis.js +295 -0
  121. package/dist/utils/bash-command-analysis.js.map +1 -0
  122. package/dist/utils/consequence-nudges.d.ts +30 -0
  123. package/dist/utils/consequence-nudges.d.ts.map +1 -0
  124. package/dist/utils/consequence-nudges.js +313 -0
  125. package/dist/utils/consequence-nudges.js.map +1 -0
  126. package/dist/utils/drift-intelligence.d.ts.map +1 -1
  127. package/dist/utils/drift-intelligence.js +29 -7
  128. package/dist/utils/drift-intelligence.js.map +1 -1
  129. package/dist/utils/git-coverage.d.ts +57 -0
  130. package/dist/utils/git-coverage.d.ts.map +1 -0
  131. package/dist/utils/git-coverage.js +302 -0
  132. package/dist/utils/git-coverage.js.map +1 -0
  133. package/dist/utils/gitignore.d.ts.map +1 -1
  134. package/dist/utils/gitignore.js +2 -1
  135. package/dist/utils/gitignore.js.map +1 -1
  136. package/dist/utils/governed-intent.d.ts +10 -0
  137. package/dist/utils/governed-intent.d.ts.map +1 -0
  138. package/dist/utils/governed-intent.js +108 -0
  139. package/dist/utils/governed-intent.js.map +1 -0
  140. package/dist/utils/hook-heartbeat.d.ts +55 -0
  141. package/dist/utils/hook-heartbeat.d.ts.map +1 -0
  142. package/dist/utils/hook-heartbeat.js +116 -0
  143. package/dist/utils/hook-heartbeat.js.map +1 -0
  144. package/dist/utils/intent-continuity.d.ts +21 -0
  145. package/dist/utils/intent-continuity.d.ts.map +1 -0
  146. package/dist/utils/intent-continuity.js +192 -0
  147. package/dist/utils/intent-continuity.js.map +1 -0
  148. package/dist/utils/messages.d.ts +1 -1
  149. package/dist/utils/messages.d.ts.map +1 -1
  150. package/dist/utils/messages.js +24 -21
  151. package/dist/utils/messages.js.map +1 -1
  152. package/dist/utils/runtime-companion.d.ts +137 -0
  153. package/dist/utils/runtime-companion.d.ts.map +1 -0
  154. package/dist/utils/runtime-companion.js +231 -0
  155. package/dist/utils/runtime-companion.js.map +1 -0
  156. package/dist/utils/runtime-connection.d.ts +46 -0
  157. package/dist/utils/runtime-connection.d.ts.map +1 -0
  158. package/dist/utils/runtime-connection.js +148 -0
  159. package/dist/utils/runtime-connection.js.map +1 -0
  160. package/dist/utils/runtime-evidence.d.ts +68 -0
  161. package/dist/utils/runtime-evidence.d.ts.map +1 -0
  162. package/dist/utils/runtime-evidence.js +248 -0
  163. package/dist/utils/runtime-evidence.js.map +1 -0
  164. package/dist/utils/runtime-live.d.ts +33 -0
  165. package/dist/utils/runtime-live.d.ts.map +1 -0
  166. package/dist/utils/runtime-live.js +361 -0
  167. package/dist/utils/runtime-live.js.map +1 -0
  168. package/dist/utils/runtime-outbox.d.ts +76 -0
  169. package/dist/utils/runtime-outbox.d.ts.map +1 -0
  170. package/dist/utils/runtime-outbox.js +410 -0
  171. package/dist/utils/runtime-outbox.js.map +1 -0
  172. package/dist/utils/runtime-receipt.d.ts +50 -0
  173. package/dist/utils/runtime-receipt.d.ts.map +1 -0
  174. package/dist/utils/runtime-receipt.js +223 -0
  175. package/dist/utils/runtime-receipt.js.map +1 -0
  176. package/dist/utils/state.d.ts +21 -0
  177. package/dist/utils/state.d.ts.map +1 -1
  178. package/dist/utils/state.js +30 -0
  179. package/dist/utils/state.js.map +1 -1
  180. package/dist/utils/structural-understanding.d.ts +334 -0
  181. package/dist/utils/structural-understanding.d.ts.map +1 -0
  182. package/dist/utils/structural-understanding.js +2316 -0
  183. package/dist/utils/structural-understanding.js.map +1 -0
  184. package/dist/utils/v0-governance.d.ts +197 -0
  185. package/dist/utils/v0-governance.d.ts.map +1 -0
  186. package/dist/utils/v0-governance.js +904 -0
  187. package/dist/utils/v0-governance.js.map +1 -0
  188. package/package.json +5 -5
@@ -0,0 +1,302 @@
1
+ "use strict";
2
+ /**
3
+ * Runtime Admission — git capture (Phase A, CLI side).
4
+ *
5
+ * Produces RawDeltaInput[] for the pure governance-runtime core. Two modes:
6
+ *
7
+ * 1. captureWorktreeCoverage — governed-session finish. Post-image object
8
+ * ids are computed with `git hash-object` (Git-native, applies .gitattributes
9
+ * clean filters) so they equal the blobs that will later be committed.
10
+ * We do NOT trust `git diff --raw` new-side ids for unstaged files.
11
+ *
12
+ * 2. captureCommittedDelta — base..head over committed trees (reliable old
13
+ * AND new object ids straight from `git diff --raw`). For future Action use.
14
+ *
15
+ * Source-free: only paths, modes, and content-addressed object ids leave git.
16
+ * No file bytes, no diff hunks.
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.isAdmissionSupportArtifactPath = isAdmissionSupportArtifactPath;
20
+ exports.detectGitObjectFormat = detectGitObjectFormat;
21
+ exports.computeWorktreeObject = computeWorktreeObject;
22
+ exports.captureWorktreeCoverage = captureWorktreeCoverage;
23
+ exports.captureCommittedDelta = captureCommittedDelta;
24
+ const child_process_1 = require("child_process");
25
+ const fs_1 = require("fs");
26
+ const path_1 = require("path");
27
+ /**
28
+ * Local runtime state and public admission records are provenance support
29
+ * artifacts, never governed source effects. Repo-authored policy files such as
30
+ * `.neurcode/governance.json` remain visible to capture; session/profile/cache
31
+ * state does not pollute admission coverage.
32
+ */
33
+ function isAdmissionSupportArtifactPath(path) {
34
+ const normalized = path.replace(/\\/g, '/').replace(/^\.\//, '');
35
+ return normalized.startsWith('.neurcode-admission/')
36
+ || normalized.startsWith('.neurcode/admission/')
37
+ || normalized.startsWith('.neurcode/sessions/')
38
+ || normalized.startsWith('.neurcode/evidence/')
39
+ || normalized.startsWith('.neurcode/executions/')
40
+ || normalized.startsWith('.neurcode/runtime-events/')
41
+ || normalized.startsWith('.neurcode/brain/cache/')
42
+ || normalized === '.neurcode/profile.json'
43
+ || normalized === '.neurcode/active-session.json'
44
+ || normalized === '.neurcode/runtime-connection.json'
45
+ || normalized === '.neurcode/runtime-outbox.json'
46
+ || normalized === '.neurcode/runtime-outbox.lock'
47
+ || normalized === '.neurcode/pilot-validation.latest.json'
48
+ || normalized === '.claude/settings.json'
49
+ || normalized === '.claude/settings.local.json';
50
+ }
51
+ const NEURCODE_GITIGNORE_HYGIENE_BLOCK = [
52
+ '# Neurcode runtime vs source separation',
53
+ '# Ignore all top-level runtime state by default.',
54
+ '.neurcode/*',
55
+ '# Allow source-controlled policy + template directories.',
56
+ '!.neurcode/policies/',
57
+ '!.neurcode/templates/',
58
+ '# Keep only canonical policy source JSON files.',
59
+ '.neurcode/policies/*',
60
+ '!.neurcode/policies/*.json',
61
+ '# Runtime-only policy activation snapshots are never committed.',
62
+ '.neurcode/policies/*.active.json',
63
+ '# Allow template sources.',
64
+ '.neurcode/templates/*',
65
+ '!.neurcode/templates/**',
66
+ '# Runtime-only files/directories are never committed.',
67
+ '.neurcode/intent-state.json',
68
+ '.neurcode/session.json',
69
+ '.neurcode/cache/',
70
+ '.neurcode/cache/**',
71
+ ];
72
+ function stripNeurcodeGitignoreHygieneBlock(text) {
73
+ const lines = text.replace(/\r\n/g, '\n').split('\n');
74
+ for (let i = 0; i <= lines.length - NEURCODE_GITIGNORE_HYGIENE_BLOCK.length; i++) {
75
+ const matches = NEURCODE_GITIGNORE_HYGIENE_BLOCK.every((line, offset) => lines[i + offset]?.trim() === line);
76
+ if (!matches)
77
+ continue;
78
+ const next = lines[i + NEURCODE_GITIGNORE_HYGIENE_BLOCK.length];
79
+ const removeCount = next?.trim() === ''
80
+ ? NEURCODE_GITIGNORE_HYGIENE_BLOCK.length + 1
81
+ : NEURCODE_GITIGNORE_HYGIENE_BLOCK.length;
82
+ lines.splice(i, removeCount);
83
+ break;
84
+ }
85
+ return lines.join('\n').trim();
86
+ }
87
+ function isNeurcodeOnlyGitignoreHygieneChange(repoRoot, relPath, baseRef) {
88
+ if (relPath !== '.gitignore')
89
+ return false;
90
+ let currentText = '';
91
+ try {
92
+ currentText = (0, fs_1.readFileSync)((0, path_1.join)(repoRoot, relPath), 'utf8');
93
+ }
94
+ catch {
95
+ return false;
96
+ }
97
+ const baseText = baseRef ? gitTry(repoRoot, ['show', `${baseRef}:${relPath}`]) ?? '' : '';
98
+ return stripNeurcodeGitignoreHygieneBlock(currentText) === stripNeurcodeGitignoreHygieneBlock(baseText);
99
+ }
100
+ function gitText(repoRoot, args, input) {
101
+ return (0, child_process_1.execFileSync)('git', args, {
102
+ cwd: repoRoot,
103
+ encoding: 'utf8',
104
+ stdio: ['pipe', 'pipe', 'ignore'],
105
+ ...(input !== undefined ? { input } : {}),
106
+ maxBuffer: 64 * 1024 * 1024,
107
+ });
108
+ }
109
+ function gitTry(repoRoot, args, input) {
110
+ try {
111
+ return gitText(repoRoot, args, input);
112
+ }
113
+ catch {
114
+ return null;
115
+ }
116
+ }
117
+ function detectGitObjectFormat(repoRoot) {
118
+ const value = gitTry(repoRoot, ['rev-parse', '--show-object-format']);
119
+ return value && value.trim() === 'sha256' ? 'sha256' : 'sha1';
120
+ }
121
+ function headExists(repoRoot) {
122
+ return gitTry(repoRoot, ['rev-parse', '--verify', '--quiet', 'HEAD']) !== null;
123
+ }
124
+ /**
125
+ * Split `git ... -z` NUL-delimited output into tokens. Trailing empty token from
126
+ * the final NUL is dropped.
127
+ */
128
+ function splitZ(output) {
129
+ if (!output)
130
+ return [];
131
+ const parts = output.split('\0');
132
+ if (parts.length && parts[parts.length - 1] === '')
133
+ parts.pop();
134
+ return parts;
135
+ }
136
+ /**
137
+ * Parse `git diff --raw -z` records. With --no-renames there is exactly one path
138
+ * per record; R/C are still parsed defensively (src + dst).
139
+ */
140
+ function parseRawDiff(tokens) {
141
+ const records = [];
142
+ let i = 0;
143
+ while (i < tokens.length) {
144
+ const meta = tokens[i];
145
+ if (!meta.startsWith(':')) {
146
+ i += 1;
147
+ continue;
148
+ }
149
+ // ":<oldmode> <newmode> <oldsha> <newsha> <status>"
150
+ const fields = meta.slice(1).split(' ').filter(Boolean);
151
+ const [oldMode, newMode, oldObjectId, newObjectId, status] = fields;
152
+ const statusLetter = (status || '').charAt(0).toUpperCase();
153
+ if (statusLetter === 'R' || statusLetter === 'C') {
154
+ const oldPath = tokens[i + 1];
155
+ const path = tokens[i + 2];
156
+ records.push({ oldMode, newMode, oldObjectId, newObjectId, status, path, oldPath });
157
+ i += 3;
158
+ }
159
+ else {
160
+ const path = tokens[i + 1];
161
+ records.push({ oldMode, newMode, oldObjectId, newObjectId, status, path });
162
+ i += 2;
163
+ }
164
+ }
165
+ return records;
166
+ }
167
+ /**
168
+ * Compute the would-be-committed object id + git mode for a worktree path.
169
+ * Returns null if the path no longer exists (handled as a delete elsewhere).
170
+ */
171
+ function computeWorktreeObject(repoRoot, relPath) {
172
+ const abs = (0, path_1.join)(repoRoot, relPath);
173
+ let stat;
174
+ try {
175
+ stat = (0, fs_1.lstatSync)(abs);
176
+ }
177
+ catch {
178
+ return null;
179
+ }
180
+ if (stat.isSymbolicLink()) {
181
+ const target = (0, fs_1.readlinkSync)(abs);
182
+ // Git stores a symlink as a blob whose content is the target string (no newline).
183
+ const objectId = gitTry(repoRoot, ['hash-object', '--stdin', '--no-filters'], target);
184
+ if (!objectId)
185
+ return null;
186
+ return { mode: '120000', objectId: objectId.trim() };
187
+ }
188
+ if (stat.isDirectory()) {
189
+ // A directory is only relevant as a submodule (gitlink): it has its own .git.
190
+ if ((0, fs_1.existsSync)((0, path_1.join)(abs, '.git'))) {
191
+ const commit = gitTry(repoRoot, ['-C', relPath, 'rev-parse', 'HEAD']);
192
+ if (!commit)
193
+ return null;
194
+ return { mode: '160000', objectId: commit.trim() };
195
+ }
196
+ return null;
197
+ }
198
+ // Regular file. `git hash-object` applies .gitattributes clean filters, so the
199
+ // id matches what will be committed.
200
+ const objectId = gitTry(repoRoot, ['hash-object', '--', relPath]);
201
+ if (!objectId)
202
+ return null;
203
+ const executable = (stat.mode & 0o111) !== 0;
204
+ return { mode: executable ? '100755' : '100644', objectId: objectId.trim() };
205
+ }
206
+ /**
207
+ * Capture the worktree effect set at session finish. Old-side ids come from the
208
+ * committed base (reliable); new-side ids are recomputed with git hash-object.
209
+ */
210
+ function captureWorktreeCoverage(repoRoot, options = {}) {
211
+ const objectFormat = detectGitObjectFormat(repoRoot);
212
+ const headRef = gitTry(repoRoot, ['rev-parse', '--short=12', 'HEAD'])?.trim() ?? null;
213
+ const raw = [];
214
+ const seen = new Set();
215
+ const hasHead = headExists(repoRoot);
216
+ const baseRef = hasHead ? options.baseRef || 'HEAD' : null;
217
+ if (baseRef) {
218
+ // --abbrev=64 prints full object ids (40 for sha1, 64 for sha256); --raw
219
+ // abbreviates by default and --full-index does not affect --raw output.
220
+ const tokens = splitZ(gitTry(repoRoot, ['diff', '--no-renames', '--raw', '--abbrev=64', '-z', baseRef]));
221
+ for (const rec of parseRawDiff(tokens)) {
222
+ if (isAdmissionSupportArtifactPath(rec.path))
223
+ continue;
224
+ if (isNeurcodeOnlyGitignoreHygieneChange(repoRoot, rec.path, baseRef))
225
+ continue;
226
+ seen.add(rec.path);
227
+ const deleted = rec.status.charAt(0).toUpperCase() === 'D';
228
+ if (deleted) {
229
+ raw.push({
230
+ path: rec.path,
231
+ oldMode: rec.oldMode,
232
+ oldObjectId: rec.oldObjectId,
233
+ newMode: '000000',
234
+ newObjectId: null,
235
+ });
236
+ continue;
237
+ }
238
+ const worktreeObject = computeWorktreeObject(repoRoot, rec.path);
239
+ if (!worktreeObject) {
240
+ // Vanished between diff and stat — treat as a delete against base.
241
+ raw.push({ path: rec.path, oldMode: rec.oldMode, oldObjectId: rec.oldObjectId, newMode: '000000', newObjectId: null });
242
+ continue;
243
+ }
244
+ const oldPresent = rec.oldMode && rec.oldMode !== '000000' && !/^0+$/.test(rec.oldObjectId);
245
+ raw.push({
246
+ path: rec.path,
247
+ oldMode: oldPresent ? rec.oldMode : '000000',
248
+ oldObjectId: oldPresent ? rec.oldObjectId : null,
249
+ newMode: worktreeObject.mode,
250
+ newObjectId: worktreeObject.objectId,
251
+ });
252
+ }
253
+ }
254
+ // Untracked (new) files — added.
255
+ for (const path of splitZ(gitTry(repoRoot, ['ls-files', '--others', '--exclude-standard', '-z']))) {
256
+ if (isAdmissionSupportArtifactPath(path))
257
+ continue;
258
+ if (isNeurcodeOnlyGitignoreHygieneChange(repoRoot, path, baseRef))
259
+ continue;
260
+ if (seen.has(path))
261
+ continue;
262
+ seen.add(path);
263
+ const worktreeObject = computeWorktreeObject(repoRoot, path);
264
+ if (!worktreeObject)
265
+ continue;
266
+ raw.push({
267
+ path,
268
+ oldMode: '000000',
269
+ oldObjectId: null,
270
+ newMode: worktreeObject.mode,
271
+ newObjectId: worktreeObject.objectId,
272
+ });
273
+ }
274
+ return { objectFormat, raw, baseRef, headRef };
275
+ }
276
+ /**
277
+ * Capture a committed tree delta (base..head). Both old and new object ids are
278
+ * read directly from git (reliable for committed trees). --no-renames so renames
279
+ * arrive as delete + add (the pure core also normalizes any R/C defensively).
280
+ */
281
+ function captureCommittedDelta(repoRoot, baseRef, headRef) {
282
+ const objectFormat = detectGitObjectFormat(repoRoot);
283
+ const tokens = splitZ(gitTry(repoRoot, ['diff', '--no-renames', '--raw', '--abbrev=64', '-z', baseRef, headRef]));
284
+ const raw = parseRawDiff(tokens)
285
+ .filter((rec) => !isAdmissionSupportArtifactPath(rec.path))
286
+ .map((rec) => ({
287
+ path: rec.path,
288
+ oldMode: rec.oldMode,
289
+ oldObjectId: rec.oldObjectId,
290
+ newMode: rec.newMode,
291
+ newObjectId: rec.newObjectId,
292
+ status: rec.status,
293
+ oldPath: rec.oldPath,
294
+ }));
295
+ return {
296
+ objectFormat,
297
+ raw,
298
+ baseRef,
299
+ headRef: gitTry(repoRoot, ['rev-parse', '--short=12', headRef])?.trim() ?? headRef,
300
+ };
301
+ }
302
+ //# sourceMappingURL=git-coverage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-coverage.js","sourceRoot":"","sources":["../../src/utils/git-coverage.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"gitignore.d.ts","sourceRoot":"","sources":["../../src/utils/gitignore.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA4BH;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,GAAE,MAAsB,GAAG,IAAI,CAsB3E"}
1
+ {"version":3,"file":"gitignore.d.ts","sourceRoot":"","sources":["../../src/utils/gitignore.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA4BH;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,GAAE,MAAsB,GAAG,IAAI,CAuB3E"}
@@ -49,7 +49,8 @@ function ensureNeurcodeInGitignore(cwd = process.cwd()) {
49
49
  return;
50
50
  }
51
51
  const block = NEURCODE_HYGIENE_BLOCK.join('\n');
52
- const newContent = content.trimEnd() + (content.endsWith('\n') ? '' : '\n') + block + '\n';
52
+ const existing = content.trimEnd();
53
+ const newContent = `${existing}${existing.length > 0 ? '\n\n' : ''}${block}\n`;
53
54
  (0, fs_1.writeFileSync)(gitignorePath, newContent, 'utf-8');
54
55
  }
55
56
  //# sourceMappingURL=gitignore.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"gitignore.js","sourceRoot":"","sources":["../../src/utils/gitignore.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;AA+BH,8DAsBC;AAnDD,2BAA6D;AAC7D,+BAA4B;AAE5B,MAAM,cAAc,GAAG,YAAY,CAAC;AACpC,MAAM,sBAAsB,GAAG;IAC7B,yCAAyC;IACzC,kDAAkD;IAClD,aAAa;IACb,0DAA0D;IAC1D,sBAAsB;IACtB,uBAAuB;IACvB,iDAAiD;IACjD,sBAAsB;IACtB,4BAA4B;IAC5B,iEAAiE;IACjE,kCAAkC;IAClC,2BAA2B;IAC3B,uBAAuB;IACvB,yBAAyB;IACzB,uDAAuD;IACvD,6BAA6B;IAC7B,wBAAwB;IACxB,kBAAkB;IAClB,oBAAoB;CACrB,CAAC;AAEF;;GAEG;AACH,SAAgB,yBAAyB,CAAC,MAAc,OAAO,CAAC,GAAG,EAAE;IACnE,MAAM,aAAa,GAAG,IAAA,WAAI,EAAC,GAAG,EAAE,cAAc,CAAC,CAAC;IAEhD,yCAAyC;IACzC,IAAI,CAAC,IAAA,eAAU,EAAC,aAAa,CAAC,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,CAAC,GAAG,sBAAsB,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzD,IAAA,kBAAa,EAAC,aAAa,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QAC7C,OAAO;IACT,CAAC;IAED,2BAA2B;IAC3B,MAAM,OAAO,GAAG,IAAA,iBAAY,EAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IACrD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IAE3D,MAAM,eAAe,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC;IAC5G,IAAI,eAAe,EAAE,CAAC;QACpB,OAAO;IACT,CAAC;IAED,MAAM,KAAK,GAAG,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChD,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC;IAC3F,IAAA,kBAAa,EAAC,aAAa,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;AACpD,CAAC"}
1
+ {"version":3,"file":"gitignore.js","sourceRoot":"","sources":["../../src/utils/gitignore.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;AA+BH,8DAuBC;AApDD,2BAA6D;AAC7D,+BAA4B;AAE5B,MAAM,cAAc,GAAG,YAAY,CAAC;AACpC,MAAM,sBAAsB,GAAG;IAC7B,yCAAyC;IACzC,kDAAkD;IAClD,aAAa;IACb,0DAA0D;IAC1D,sBAAsB;IACtB,uBAAuB;IACvB,iDAAiD;IACjD,sBAAsB;IACtB,4BAA4B;IAC5B,iEAAiE;IACjE,kCAAkC;IAClC,2BAA2B;IAC3B,uBAAuB;IACvB,yBAAyB;IACzB,uDAAuD;IACvD,6BAA6B;IAC7B,wBAAwB;IACxB,kBAAkB;IAClB,oBAAoB;CACrB,CAAC;AAEF;;GAEG;AACH,SAAgB,yBAAyB,CAAC,MAAc,OAAO,CAAC,GAAG,EAAE;IACnE,MAAM,aAAa,GAAG,IAAA,WAAI,EAAC,GAAG,EAAE,cAAc,CAAC,CAAC;IAEhD,yCAAyC;IACzC,IAAI,CAAC,IAAA,eAAU,EAAC,aAAa,CAAC,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,CAAC,GAAG,sBAAsB,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzD,IAAA,kBAAa,EAAC,aAAa,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QAC7C,OAAO;IACT,CAAC;IAED,2BAA2B;IAC3B,MAAM,OAAO,GAAG,IAAA,iBAAY,EAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IACrD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IAE3D,MAAM,eAAe,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC;IAC5G,IAAI,eAAe,EAAE,CAAC;QACpB,OAAO;IACT,CAAC;IAED,MAAM,KAAK,GAAG,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IACnC,MAAM,UAAU,GAAG,GAAG,QAAQ,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;IAC/E,IAAA,kBAAa,EAAC,aAAa,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;AACpD,CAAC"}
@@ -0,0 +1,10 @@
1
+ export type GovernedIntentSource = 'prompt' | 'labeled_goal';
2
+ export interface GovernedIntentSelection {
3
+ goal: string;
4
+ source: GovernedIntentSource;
5
+ operatorPrompt: boolean;
6
+ warnings: string[];
7
+ }
8
+ export declare function selectGovernedIntent(prompt: string): GovernedIntentSelection;
9
+ export declare function shouldStartGovernedSession(selection: GovernedIntentSelection): boolean;
10
+ //# sourceMappingURL=governed-intent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"governed-intent.d.ts","sourceRoot":"","sources":["../../src/utils/governed-intent.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,oBAAoB,GAAG,QAAQ,GAAG,cAAc,CAAC;AAE7D,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,oBAAoB,CAAC;IAC7B,cAAc,EAAE,OAAO,CAAC;IACxB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AA4ED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,uBAAuB,CA8B5E;AAED,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,uBAAuB,GAAG,OAAO,CAEtF"}
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.selectGovernedIntent = selectGovernedIntent;
4
+ exports.shouldStartGovernedSession = shouldStartGovernedSession;
5
+ const GOAL_LABEL = /^\s*(?:(?:new|fresh|next)\s+)?(?:governed|implementation|demo|task)\s+(?:goal|intent)\s*:\s*(.*)$/i;
6
+ const OPERATOR_PROMPT_MARKERS = [
7
+ /\bfounder-demo rehearsal\b/i,
8
+ /\bdo not (?:refactor|implement|push|change product code)\b/i,
9
+ /^\s*steps\s*:/im,
10
+ /^\s*deliver\s*:/im,
11
+ /^\s*deliverables?\s*:/im,
12
+ /\buse the real claude code\b/i,
13
+ /\bonly rehearse\b/i,
14
+ /\bi (?:can'?t|cannot) approve\b/i,
15
+ /\bno approval request\b/i,
16
+ /\bapproval request (?:is )?(?:not )?(?:visible|available)\b/i,
17
+ /\bdashboard approval\b/i,
18
+ /\bapprove via dashboard\b/i,
19
+ /\bfinish (?:the )?(?:report|session)\b/i,
20
+ /\bmark .* as (?:blocked|blocker)\b/i,
21
+ ];
22
+ function cleanGoal(value) {
23
+ return value
24
+ .replace(/^```(?:text|md|markdown)?\s*/i, '')
25
+ .replace(/```\s*$/i, '')
26
+ .trim();
27
+ }
28
+ function readFencedBlock(lines, startIndex) {
29
+ const opener = lines[startIndex]?.trim();
30
+ if (!opener || !/^```/.test(opener))
31
+ return null;
32
+ const out = [];
33
+ for (let i = startIndex + 1; i < lines.length; i++) {
34
+ if (/^```/.test(lines[i].trim()))
35
+ break;
36
+ out.push(lines[i]);
37
+ }
38
+ return cleanGoal(out.join('\n'));
39
+ }
40
+ function readNextGoalBlock(lines, startIndex) {
41
+ for (let i = startIndex; i < lines.length; i++) {
42
+ const line = lines[i];
43
+ if (!line.trim())
44
+ continue;
45
+ const fenced = readFencedBlock(lines, i);
46
+ if (fenced)
47
+ return fenced;
48
+ if (/^\s*(?:\d+[.)]|[-*+]|\w[\w -]{0,32}:)\s/.test(line))
49
+ return null;
50
+ return cleanGoal(line);
51
+ }
52
+ return null;
53
+ }
54
+ function extractLabeledGoal(prompt) {
55
+ const lines = prompt.split(/\r?\n/);
56
+ for (let i = 0; i < lines.length; i++) {
57
+ const match = lines[i].match(GOAL_LABEL);
58
+ if (!match)
59
+ continue;
60
+ const inline = cleanGoal(match[1] || '');
61
+ if (inline && !/^```/.test(inline))
62
+ return inline;
63
+ const fencedSameLine = inline ? cleanGoal(inline) : null;
64
+ if (fencedSameLine && !/^```/.test(fencedSameLine))
65
+ return fencedSameLine;
66
+ const next = readNextGoalBlock(lines, i + 1);
67
+ if (next)
68
+ return next;
69
+ }
70
+ return null;
71
+ }
72
+ function isOperatorPrompt(prompt) {
73
+ if (prompt.length > 900)
74
+ return true;
75
+ if (prompt.split(/\r?\n/).length > 12)
76
+ return true;
77
+ return OPERATOR_PROMPT_MARKERS.some((marker) => marker.test(prompt));
78
+ }
79
+ function selectGovernedIntent(prompt) {
80
+ const trimmed = prompt.trim();
81
+ const operatorPrompt = isOperatorPrompt(trimmed);
82
+ const labeled = extractLabeledGoal(trimmed);
83
+ const warnings = [];
84
+ if (labeled) {
85
+ if (operatorPrompt) {
86
+ warnings.push('operator prompt detected; using labeled governed goal for session scope');
87
+ }
88
+ return {
89
+ goal: labeled,
90
+ source: 'labeled_goal',
91
+ operatorPrompt,
92
+ warnings,
93
+ };
94
+ }
95
+ if (operatorPrompt) {
96
+ warnings.push('prompt looks like operator instructions, not a crisp implementation intent; add `Governed goal:` or `Demo goal:` to avoid noisy scope');
97
+ }
98
+ return {
99
+ goal: trimmed,
100
+ source: 'prompt',
101
+ operatorPrompt,
102
+ warnings,
103
+ };
104
+ }
105
+ function shouldStartGovernedSession(selection) {
106
+ return selection.source === 'labeled_goal' || !selection.operatorPrompt;
107
+ }
108
+ //# sourceMappingURL=governed-intent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"governed-intent.js","sourceRoot":"","sources":["../../src/utils/governed-intent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Hook heartbeat — source-free liveness evidence for Claude Code governance hooks.
3
+ *
4
+ * Every time a `session-hook start|check|finish` runs, the *currently loaded* hook
5
+ * records a small, source-free heartbeat under `.neurcode/runtime/`. doctor uses it to
6
+ * tell whether the running Claude Code session is executing the hooks that are
7
+ * installed on disk right now — the only reliable signal that activation actually
8
+ * reached the live agent (hooks load at Claude Code startup and do not hot-reload).
9
+ *
10
+ * SOURCE-FREE CONTRACT: the heartbeat contains only the hook entrypoint path, CLI
11
+ * version, repo root, event type, timestamp, and the (opaque) session id. It never
12
+ * contains source code, diffs, or prompt/goal text.
13
+ */
14
+ export declare const HOOK_HEARTBEAT_SCHEMA_VERSION = "neurcode.hook-heartbeat.v1";
15
+ export type HookEventType = 'start' | 'check' | 'finish';
16
+ export interface HookHeartbeatEvent {
17
+ type: HookEventType;
18
+ ts: string;
19
+ /** Source-free session id (opaque hex), when a session is active. */
20
+ sessionId?: string;
21
+ }
22
+ export interface HookHeartbeat {
23
+ schemaVersion: typeof HOOK_HEARTBEAT_SCHEMA_VERSION;
24
+ /** CLI version of the hook that is actually running in the live Claude session. */
25
+ cliVersion: string;
26
+ /** Realpath of the entrypoint the live hook is executing (process.argv[1]). */
27
+ entrypoint: string;
28
+ /** Short fingerprint of the running entrypoint (source-free). */
29
+ entrypointFingerprint: string;
30
+ repoRoot: string;
31
+ /** Most recent hook event. */
32
+ lastEvent: HookHeartbeatEvent;
33
+ /** Last-seen timestamp per event type. */
34
+ events: Partial<Record<HookEventType, string>>;
35
+ }
36
+ export declare function runtimeDir(repoRoot: string): string;
37
+ export declare function hookHeartbeatPath(repoRoot: string): string;
38
+ /** Short, stable, source-free fingerprint of an entrypoint path. */
39
+ export declare function fingerprintEntrypoint(entrypoint: string): string;
40
+ /** Read the CLI version from the package.json shipped alongside dist/. Best-effort. */
41
+ export declare function readCliVersion(): string;
42
+ /** Realpath of the entrypoint the current process is executing. */
43
+ export declare function runningEntrypoint(): string;
44
+ /**
45
+ * Record a source-free heartbeat for the hook that is currently running.
46
+ * Best-effort: any failure is swallowed so the governance hook is never broken.
47
+ */
48
+ export declare function recordHookHeartbeat(input: {
49
+ repoRoot: string;
50
+ eventType: HookEventType;
51
+ sessionId?: string;
52
+ }): void;
53
+ /** Read the heartbeat, or null when absent/unreadable/invalid. */
54
+ export declare function readHookHeartbeat(repoRoot: string): HookHeartbeat | null;
55
+ //# sourceMappingURL=hook-heartbeat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook-heartbeat.d.ts","sourceRoot":"","sources":["../../src/utils/hook-heartbeat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH,eAAO,MAAM,6BAA6B,+BAA+B,CAAC;AAE1E,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEzD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,aAAa,CAAC;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,aAAa,EAAE,OAAO,6BAA6B,CAAC;IACpD,mFAAmF;IACnF,UAAU,EAAE,MAAM,CAAC;IACnB,+EAA+E;IAC/E,UAAU,EAAE,MAAM,CAAC;IACnB,iEAAiE;IACjE,qBAAqB,EAAE,MAAM,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,8BAA8B;IAC9B,SAAS,EAAE,kBAAkB,CAAC;IAC9B,0CAA0C;IAC1C,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC;CAChD;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,oEAAoE;AACpE,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED,uFAAuF;AACvF,wBAAgB,cAAc,IAAI,MAAM,CAcvC;AAED,mEAAmE;AACnE,wBAAgB,iBAAiB,IAAI,MAAM,CAO1C;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,aAAa,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,IAAI,CA4BP;AAED,kEAAkE;AAClE,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAaxE"}
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ /**
3
+ * Hook heartbeat — source-free liveness evidence for Claude Code governance hooks.
4
+ *
5
+ * Every time a `session-hook start|check|finish` runs, the *currently loaded* hook
6
+ * records a small, source-free heartbeat under `.neurcode/runtime/`. doctor uses it to
7
+ * tell whether the running Claude Code session is executing the hooks that are
8
+ * installed on disk right now — the only reliable signal that activation actually
9
+ * reached the live agent (hooks load at Claude Code startup and do not hot-reload).
10
+ *
11
+ * SOURCE-FREE CONTRACT: the heartbeat contains only the hook entrypoint path, CLI
12
+ * version, repo root, event type, timestamp, and the (opaque) session id. It never
13
+ * contains source code, diffs, or prompt/goal text.
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.HOOK_HEARTBEAT_SCHEMA_VERSION = void 0;
17
+ exports.runtimeDir = runtimeDir;
18
+ exports.hookHeartbeatPath = hookHeartbeatPath;
19
+ exports.fingerprintEntrypoint = fingerprintEntrypoint;
20
+ exports.readCliVersion = readCliVersion;
21
+ exports.runningEntrypoint = runningEntrypoint;
22
+ exports.recordHookHeartbeat = recordHookHeartbeat;
23
+ exports.readHookHeartbeat = readHookHeartbeat;
24
+ const crypto_1 = require("crypto");
25
+ const fs_1 = require("fs");
26
+ const path_1 = require("path");
27
+ exports.HOOK_HEARTBEAT_SCHEMA_VERSION = 'neurcode.hook-heartbeat.v1';
28
+ function runtimeDir(repoRoot) {
29
+ return (0, path_1.join)(repoRoot, '.neurcode', 'runtime');
30
+ }
31
+ function hookHeartbeatPath(repoRoot) {
32
+ return (0, path_1.join)(runtimeDir(repoRoot), 'hook-heartbeat.json');
33
+ }
34
+ /** Short, stable, source-free fingerprint of an entrypoint path. */
35
+ function fingerprintEntrypoint(entrypoint) {
36
+ return (0, crypto_1.createHash)('sha256').update(entrypoint).digest('hex').slice(0, 16);
37
+ }
38
+ /** Read the CLI version from the package.json shipped alongside dist/. Best-effort. */
39
+ function readCliVersion() {
40
+ const candidates = [
41
+ (0, path_1.resolve)(__dirname, '..', '..', 'package.json'),
42
+ (0, path_1.resolve)(__dirname, '..', 'package.json'),
43
+ ];
44
+ for (const candidate of candidates) {
45
+ try {
46
+ const pkg = JSON.parse((0, fs_1.readFileSync)(candidate, 'utf8'));
47
+ if (pkg.version)
48
+ return pkg.version;
49
+ }
50
+ catch {
51
+ // try next candidate
52
+ }
53
+ }
54
+ return 'unknown';
55
+ }
56
+ /** Realpath of the entrypoint the current process is executing. */
57
+ function runningEntrypoint() {
58
+ const raw = process.argv[1] ?? '';
59
+ try {
60
+ return (0, fs_1.realpathSync)(raw);
61
+ }
62
+ catch {
63
+ return raw;
64
+ }
65
+ }
66
+ /**
67
+ * Record a source-free heartbeat for the hook that is currently running.
68
+ * Best-effort: any failure is swallowed so the governance hook is never broken.
69
+ */
70
+ function recordHookHeartbeat(input) {
71
+ try {
72
+ const entrypoint = runningEntrypoint();
73
+ const now = new Date().toISOString();
74
+ const previous = readHookHeartbeat(input.repoRoot);
75
+ const events = { ...(previous?.events ?? {}) };
76
+ events[input.eventType] = now;
77
+ const heartbeat = {
78
+ schemaVersion: exports.HOOK_HEARTBEAT_SCHEMA_VERSION,
79
+ cliVersion: readCliVersion(),
80
+ entrypoint,
81
+ entrypointFingerprint: fingerprintEntrypoint(entrypoint),
82
+ repoRoot: input.repoRoot,
83
+ lastEvent: {
84
+ type: input.eventType,
85
+ ts: now,
86
+ ...(input.sessionId ? { sessionId: input.sessionId } : {}),
87
+ },
88
+ events,
89
+ };
90
+ const path = hookHeartbeatPath(input.repoRoot);
91
+ (0, fs_1.mkdirSync)((0, path_1.dirname)(path), { recursive: true });
92
+ (0, fs_1.writeFileSync)(path, JSON.stringify(heartbeat, null, 2) + '\n', 'utf8');
93
+ }
94
+ catch {
95
+ // Heartbeat is best-effort liveness evidence; never break the hook.
96
+ }
97
+ }
98
+ /** Read the heartbeat, or null when absent/unreadable/invalid. */
99
+ function readHookHeartbeat(repoRoot) {
100
+ const path = hookHeartbeatPath(repoRoot);
101
+ if (!(0, fs_1.existsSync)(path))
102
+ return null;
103
+ try {
104
+ const data = JSON.parse((0, fs_1.readFileSync)(path, 'utf8'));
105
+ if (!data || data.schemaVersion !== exports.HOOK_HEARTBEAT_SCHEMA_VERSION)
106
+ return null;
107
+ if (typeof data.entrypoint !== 'string' || !data.lastEvent || typeof data.lastEvent.ts !== 'string') {
108
+ return null;
109
+ }
110
+ return data;
111
+ }
112
+ catch {
113
+ return null;
114
+ }
115
+ }
116
+ //# sourceMappingURL=hook-heartbeat.js.map