@neurcode-ai/cli 0.12.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 (212) 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/governance.d.ts.map +1 -1
  23. package/dist/commands/governance.js +12 -0
  24. package/dist/commands/governance.js.map +1 -1
  25. package/dist/commands/home.d.ts +21 -0
  26. package/dist/commands/home.d.ts.map +1 -0
  27. package/dist/commands/home.js +253 -0
  28. package/dist/commands/home.js.map +1 -0
  29. package/dist/commands/init.d.ts.map +1 -1
  30. package/dist/commands/init.js +58 -44
  31. package/dist/commands/init.js.map +1 -1
  32. package/dist/commands/login.d.ts +1 -1
  33. package/dist/commands/login.d.ts.map +1 -1
  34. package/dist/commands/login.js +44 -22
  35. package/dist/commands/login.js.map +1 -1
  36. package/dist/commands/profile.d.ts +14 -0
  37. package/dist/commands/profile.d.ts.map +1 -0
  38. package/dist/commands/profile.js +118 -0
  39. package/dist/commands/profile.js.map +1 -0
  40. package/dist/commands/quickstart.d.ts +2 -2
  41. package/dist/commands/quickstart.d.ts.map +1 -1
  42. package/dist/commands/quickstart.js +33 -30
  43. package/dist/commands/quickstart.js.map +1 -1
  44. package/dist/commands/remediate-export.d.ts +6 -1
  45. package/dist/commands/remediate-export.d.ts.map +1 -1
  46. package/dist/commands/remediate-export.js +375 -8
  47. package/dist/commands/remediate-export.js.map +1 -1
  48. package/dist/commands/replay.d.ts.map +1 -1
  49. package/dist/commands/replay.js +84 -0
  50. package/dist/commands/replay.js.map +1 -1
  51. package/dist/commands/run.d.ts +3 -0
  52. package/dist/commands/run.d.ts.map +1 -0
  53. package/dist/commands/run.js +98 -0
  54. package/dist/commands/run.js.map +1 -0
  55. package/dist/commands/runtime-adapter.d.ts +8 -0
  56. package/dist/commands/runtime-adapter.d.ts.map +1 -0
  57. package/dist/commands/runtime-adapter.js +375 -0
  58. package/dist/commands/runtime-adapter.js.map +1 -0
  59. package/dist/commands/runtime-doctor.d.ts +6 -0
  60. package/dist/commands/runtime-doctor.d.ts.map +1 -0
  61. package/dist/commands/runtime-doctor.js +478 -0
  62. package/dist/commands/runtime-doctor.js.map +1 -0
  63. package/dist/commands/runtime-report.d.ts +13 -0
  64. package/dist/commands/runtime-report.d.ts.map +1 -0
  65. package/dist/commands/runtime-report.js +81 -0
  66. package/dist/commands/runtime-report.js.map +1 -0
  67. package/dist/commands/runtime-sync.d.ts +17 -0
  68. package/dist/commands/runtime-sync.d.ts.map +1 -0
  69. package/dist/commands/runtime-sync.js +656 -0
  70. package/dist/commands/runtime-sync.js.map +1 -0
  71. package/dist/commands/runtime.d.ts +16 -0
  72. package/dist/commands/runtime.d.ts.map +1 -0
  73. package/dist/commands/runtime.js +380 -0
  74. package/dist/commands/runtime.js.map +1 -0
  75. package/dist/commands/session-hook.d.ts +35 -0
  76. package/dist/commands/session-hook.d.ts.map +1 -0
  77. package/dist/commands/session-hook.js +1297 -0
  78. package/dist/commands/session-hook.js.map +1 -0
  79. package/dist/commands/session.d.ts +91 -0
  80. package/dist/commands/session.d.ts.map +1 -1
  81. package/dist/commands/session.js +1226 -0
  82. package/dist/commands/session.js.map +1 -1
  83. package/dist/commands/verify-output.d.ts.map +1 -1
  84. package/dist/commands/verify-output.js +22 -0
  85. package/dist/commands/verify-output.js.map +1 -1
  86. package/dist/commands/verify.d.ts.map +1 -1
  87. package/dist/commands/verify.js +21 -3
  88. package/dist/commands/verify.js.map +1 -1
  89. package/dist/commands/whoami.d.ts +7 -4
  90. package/dist/commands/whoami.d.ts.map +1 -1
  91. package/dist/commands/whoami.js +59 -34
  92. package/dist/commands/whoami.js.map +1 -1
  93. package/dist/config.d.ts.map +1 -1
  94. package/dist/config.js +24 -5
  95. package/dist/config.js.map +1 -1
  96. package/dist/daemon/routes.d.ts.map +1 -1
  97. package/dist/daemon/routes.js +8 -0
  98. package/dist/daemon/routes.js.map +1 -1
  99. package/dist/daemon/server.d.ts.map +1 -1
  100. package/dist/daemon/server.js +88 -0
  101. package/dist/daemon/server.js.map +1 -1
  102. package/dist/governance/canonical-pipeline.d.ts.map +1 -1
  103. package/dist/governance/canonical-pipeline.js +29 -3
  104. package/dist/governance/canonical-pipeline.js.map +1 -1
  105. package/dist/governance/impact-analysis.d.ts +27 -0
  106. package/dist/governance/impact-analysis.d.ts.map +1 -0
  107. package/dist/governance/impact-analysis.js +274 -0
  108. package/dist/governance/impact-analysis.js.map +1 -0
  109. package/dist/index.js +484 -29
  110. package/dist/index.js.map +1 -1
  111. package/dist/intent-engine/matcher.d.ts.map +1 -1
  112. package/dist/intent-engine/matcher.js +3 -12
  113. package/dist/intent-engine/matcher.js.map +1 -1
  114. package/dist/utils/admission-artifact.d.ts +59 -0
  115. package/dist/utils/admission-artifact.d.ts.map +1 -0
  116. package/dist/utils/admission-artifact.js +410 -0
  117. package/dist/utils/admission-artifact.js.map +1 -0
  118. package/dist/utils/agent-adapter-setup.d.ts +80 -0
  119. package/dist/utils/agent-adapter-setup.d.ts.map +1 -0
  120. package/dist/utils/agent-adapter-setup.js +577 -0
  121. package/dist/utils/agent-adapter-setup.js.map +1 -0
  122. package/dist/utils/agent-guard-supervisor.d.ts +75 -0
  123. package/dist/utils/agent-guard-supervisor.d.ts.map +1 -0
  124. package/dist/utils/agent-guard-supervisor.js +388 -0
  125. package/dist/utils/agent-guard-supervisor.js.map +1 -0
  126. package/dist/utils/agent-guard.d.ts +92 -0
  127. package/dist/utils/agent-guard.d.ts.map +1 -0
  128. package/dist/utils/agent-guard.js +326 -0
  129. package/dist/utils/agent-guard.js.map +1 -0
  130. package/dist/utils/agent-session-launcher.d.ts +89 -0
  131. package/dist/utils/agent-session-launcher.d.ts.map +1 -0
  132. package/dist/utils/agent-session-launcher.js +308 -0
  133. package/dist/utils/agent-session-launcher.js.map +1 -0
  134. package/dist/utils/bash-command-analysis.d.ts +19 -0
  135. package/dist/utils/bash-command-analysis.d.ts.map +1 -0
  136. package/dist/utils/bash-command-analysis.js +295 -0
  137. package/dist/utils/bash-command-analysis.js.map +1 -0
  138. package/dist/utils/consequence-nudges.d.ts +30 -0
  139. package/dist/utils/consequence-nudges.d.ts.map +1 -0
  140. package/dist/utils/consequence-nudges.js +313 -0
  141. package/dist/utils/consequence-nudges.js.map +1 -0
  142. package/dist/utils/drift-intelligence.d.ts.map +1 -1
  143. package/dist/utils/drift-intelligence.js +29 -7
  144. package/dist/utils/drift-intelligence.js.map +1 -1
  145. package/dist/utils/git-coverage.d.ts +57 -0
  146. package/dist/utils/git-coverage.d.ts.map +1 -0
  147. package/dist/utils/git-coverage.js +302 -0
  148. package/dist/utils/git-coverage.js.map +1 -0
  149. package/dist/utils/gitignore.d.ts.map +1 -1
  150. package/dist/utils/gitignore.js +2 -1
  151. package/dist/utils/gitignore.js.map +1 -1
  152. package/dist/utils/governed-intent.d.ts +10 -0
  153. package/dist/utils/governed-intent.d.ts.map +1 -0
  154. package/dist/utils/governed-intent.js +108 -0
  155. package/dist/utils/governed-intent.js.map +1 -0
  156. package/dist/utils/hook-heartbeat.d.ts +55 -0
  157. package/dist/utils/hook-heartbeat.d.ts.map +1 -0
  158. package/dist/utils/hook-heartbeat.js +116 -0
  159. package/dist/utils/hook-heartbeat.js.map +1 -0
  160. package/dist/utils/intent-continuity.d.ts +21 -0
  161. package/dist/utils/intent-continuity.d.ts.map +1 -0
  162. package/dist/utils/intent-continuity.js +192 -0
  163. package/dist/utils/intent-continuity.js.map +1 -0
  164. package/dist/utils/messages.d.ts +1 -1
  165. package/dist/utils/messages.d.ts.map +1 -1
  166. package/dist/utils/messages.js +35 -23
  167. package/dist/utils/messages.js.map +1 -1
  168. package/dist/utils/runtime-companion.d.ts +137 -0
  169. package/dist/utils/runtime-companion.d.ts.map +1 -0
  170. package/dist/utils/runtime-companion.js +231 -0
  171. package/dist/utils/runtime-companion.js.map +1 -0
  172. package/dist/utils/runtime-connection.d.ts +46 -0
  173. package/dist/utils/runtime-connection.d.ts.map +1 -0
  174. package/dist/utils/runtime-connection.js +148 -0
  175. package/dist/utils/runtime-connection.js.map +1 -0
  176. package/dist/utils/runtime-evidence.d.ts +68 -0
  177. package/dist/utils/runtime-evidence.d.ts.map +1 -0
  178. package/dist/utils/runtime-evidence.js +248 -0
  179. package/dist/utils/runtime-evidence.js.map +1 -0
  180. package/dist/utils/runtime-live.d.ts +33 -0
  181. package/dist/utils/runtime-live.d.ts.map +1 -0
  182. package/dist/utils/runtime-live.js +361 -0
  183. package/dist/utils/runtime-live.js.map +1 -0
  184. package/dist/utils/runtime-outbox.d.ts +76 -0
  185. package/dist/utils/runtime-outbox.d.ts.map +1 -0
  186. package/dist/utils/runtime-outbox.js +410 -0
  187. package/dist/utils/runtime-outbox.js.map +1 -0
  188. package/dist/utils/runtime-receipt.d.ts +50 -0
  189. package/dist/utils/runtime-receipt.d.ts.map +1 -0
  190. package/dist/utils/runtime-receipt.js +223 -0
  191. package/dist/utils/runtime-receipt.js.map +1 -0
  192. package/dist/utils/runtime-state.d.ts +44 -0
  193. package/dist/utils/runtime-state.d.ts.map +1 -0
  194. package/dist/utils/runtime-state.js +151 -0
  195. package/dist/utils/runtime-state.js.map +1 -0
  196. package/dist/utils/state.d.ts +21 -0
  197. package/dist/utils/state.d.ts.map +1 -1
  198. package/dist/utils/state.js +30 -0
  199. package/dist/utils/state.js.map +1 -1
  200. package/dist/utils/structural-understanding.d.ts +334 -0
  201. package/dist/utils/structural-understanding.d.ts.map +1 -0
  202. package/dist/utils/structural-understanding.js +2316 -0
  203. package/dist/utils/structural-understanding.js.map +1 -0
  204. package/dist/utils/v0-governance.d.ts +197 -0
  205. package/dist/utils/v0-governance.d.ts.map +1 -0
  206. package/dist/utils/v0-governance.js +904 -0
  207. package/dist/utils/v0-governance.js.map +1 -0
  208. package/package.json +6 -6
  209. package/dist/utils/box.d.ts +0 -16
  210. package/dist/utils/box.d.ts.map +0 -1
  211. package/dist/utils/box.js +0 -85
  212. package/dist/utils/box.js.map +0 -1
@@ -25,12 +25,16 @@ const fs_1 = require("fs");
25
25
  const path_1 = require("path");
26
26
  const crypto_1 = require("crypto");
27
27
  const child_process_1 = require("child_process");
28
+ const runtime_state_1 = require("../utils/runtime-state");
28
29
  const cli_json_1 = require("../utils/cli-json");
30
+ const plan_cache_1 = require("../utils/plan-cache");
29
31
  const chalk = (0, cli_json_1.loadChalk)();
30
32
  // ── Trust boundary statement — fixed, never changes ──────────────────────────
31
33
  const TRUST_BOUNDARY_STATEMENT = 'Neurcode deterministically detects and governs. ' +
32
- 'Your AI coding assistant (Cursor, Claude, Codex, GitHub Copilot) performs remediation. ' +
34
+ 'Your AI coding assistant (Claude, Codex, Cursor, Gemini, GitHub Copilot) performs remediation. ' +
33
35
  'Neurcode never autonomously modifies production code.';
36
+ const REMEDIATION_HANDOFF_SCHEMA = 'neurcode.remediation-handoff.v1';
37
+ const PROVIDERS = ['claude', 'codex', 'cursor', 'gemini'];
34
38
  // ── Remediation category map — deterministic, ruleId-keyed ───────────────────
35
39
  const REMEDIATION_CATEGORY = {
36
40
  PY003: 'exception-handling',
@@ -115,9 +119,23 @@ async function remediateExportCommand(options) {
115
119
  ? (0, path_1.resolve)(options.verifyOutputFile)
116
120
  : (0, path_1.join)(projectRoot, '.neurcode', 'last-verify-output.json');
117
121
  if (!(0, fs_1.existsSync)(verifyPath)) {
122
+ // Promote to structured operational-state guidance (lifecycle hardening
123
+ // §2.1). If the user explicitly passed --verify-output-file, the issue
124
+ // is a path mismatch, not a lifecycle gap — keep the original message.
125
+ // If they're using the default .neurcode/last-verify-output.json path
126
+ // but the file is missing, surface the structured panel.
127
+ if (!options.verifyOutputFile) {
128
+ const state = (0, runtime_state_1.detectRuntimeState)(projectRoot);
129
+ if (!state.hasNeurcodeDir) {
130
+ const code = (0, runtime_state_1.renderRuntimeStateGuidance)('no-neurcode-dir', state, {
131
+ commandLabel: 'neurcode remediate-export',
132
+ });
133
+ process.exit(code);
134
+ }
135
+ }
118
136
  console.error(chalk.red('✗ No verify output found.'));
119
137
  console.error(chalk.dim(` Expected: ${verifyPath}`));
120
- console.error(chalk.dim(' Run: neurcode verify --policy-only --json'));
138
+ console.error(chalk.dim(' Run: neurcode verify --local-only --head --json --require-intent-runtime'));
121
139
  console.error(chalk.dim(' Or pass: neurcode remediate-export --verify-output-file <path-to-verify.json>'));
122
140
  process.exit(1);
123
141
  }
@@ -164,13 +182,17 @@ async function remediateExportCommand(options) {
164
182
  console.log(chalk.dim(`No finding specified. Exporting finding at index 0. Use --finding-index N or --all.\n`));
165
183
  selected = [findings[0]];
166
184
  }
167
- const format = options.format ?? 'json';
185
+ const format = normalizeOutputFormat(options.format);
186
+ const provider = normalizeProvider(options.provider);
187
+ if ((format === 'prompt' || options.open) && !provider) {
188
+ console.error(chalk.red('✗ A provider is required for provider-specific handoff output.'));
189
+ console.error(chalk.dim(` Use: --provider ${PROVIDERS.join('|')}`));
190
+ process.exit(1);
191
+ }
168
192
  const replayChecksum = resolveReplayChecksum(verifyOutput);
169
193
  const replayMode = resolveReplayMode(verifyOutput);
170
194
  const payloads = selected.map((finding) => buildPayload(finding, verifyOutput, projectRoot, replayChecksum, replayMode, format));
171
- const output = payloads.length === 1
172
- ? JSON.stringify(format === 'mcp' ? payloads[0].mcpEnvelope : payloads[0], null, 2)
173
- : JSON.stringify(format === 'mcp' ? payloads.map(p => p.mcpEnvelope) : payloads, null, 2);
195
+ const output = renderRemediationOutput(payloads, format, provider);
174
196
  // Write to file or stdout
175
197
  if (options.out) {
176
198
  const outPath = (0, path_1.resolve)(projectRoot, options.out);
@@ -190,8 +212,16 @@ async function remediateExportCommand(options) {
190
212
  console.error(chalk.yellow('\n⚠ --copy failed (pbcopy not available on this system).'));
191
213
  }
192
214
  }
215
+ if (options.open) {
216
+ if (payloads.length !== 1) {
217
+ console.error(chalk.yellow('\n⚠ --open supports one finding at a time. Re-run without --all.'));
218
+ }
219
+ else if (provider) {
220
+ openProviderHandoff(payloads[0], provider);
221
+ }
222
+ }
193
223
  // Print trust boundary reminder
194
- if (!options.json) {
224
+ if (!options.json && format === 'json') {
195
225
  console.error(chalk.dim('\n─────────────────────────────────────────────────────────'));
196
226
  console.error(chalk.cyan(' Trust Boundary'));
197
227
  console.error(chalk.dim(' Neurcode detects. Your AI assistant remediates.'));
@@ -283,7 +313,7 @@ function buildPayload(finding, verifyOutput, projectRoot, replayChecksum, replay
283
313
  const payload = {
284
314
  exportId,
285
315
  exportedAt: new Date().toISOString(),
286
- neurcodeVersion: '0.12.0',
316
+ neurcodeVersion: (0, plan_cache_1.getNeurcodeVersion)(),
287
317
  schemaVersion: '2026-05-14',
288
318
  findingId,
289
319
  ruleId,
@@ -323,7 +353,9 @@ function buildPayload(finding, verifyOutput, projectRoot, replayChecksum, replay
323
353
  graphImpact,
324
354
  relevantNarratives,
325
355
  suggestedPromptHint,
356
+ agentHandoff: undefined,
326
357
  };
358
+ payload.agentHandoff = buildAgentHandoff(payload, projectRoot);
327
359
  if (format === 'mcp') {
328
360
  payload.mcpEnvelope = {
329
361
  type: 'neurcode/remediation-request',
@@ -373,6 +405,341 @@ function asStringArray(value, limit = 12) {
373
405
  .filter((entry) => typeof entry === 'string' && entry.trim().length > 0)
374
406
  .slice(0, limit);
375
407
  }
408
+ function normalizeProvider(value) {
409
+ if (typeof value !== 'string' || value.trim().length === 0)
410
+ return undefined;
411
+ const normalized = value.trim().toLowerCase();
412
+ return PROVIDERS.includes(normalized)
413
+ ? normalized
414
+ : undefined;
415
+ }
416
+ function normalizeOutputFormat(value) {
417
+ if (typeof value !== 'string')
418
+ return 'json';
419
+ const normalized = value.trim().toLowerCase();
420
+ return ['json', 'mcp', 'prompt', 'markdown'].includes(normalized)
421
+ ? normalized
422
+ : 'json';
423
+ }
424
+ function shellQuote(value) {
425
+ return `'${value.replace(/'/g, `'\\''`)}'`;
426
+ }
427
+ function uniqueNonEmpty(values, limit = 20) {
428
+ return [...new Set(values.map((value) => value?.trim() || '').filter(Boolean))].slice(0, limit);
429
+ }
430
+ function buildAgentHandoff(payload, projectRoot) {
431
+ const context = payload.engineeringContext;
432
+ const drift = payload.driftIntelligence;
433
+ const allowedFiles = uniqueNonEmpty([
434
+ payload.filePath,
435
+ ...(context?.approvedScope.files || []),
436
+ ...(context?.contextFiles || []),
437
+ ], 24);
438
+ const forbiddenBoundaries = uniqueNonEmpty([
439
+ ...((context?.forbiddenBoundaries || []).map((entry) => `${entry.policy}:${entry.type}:${entry.path}${entry.reason ? ` — ${entry.reason}` : ''}`)),
440
+ ...payload.scopeUnexpectedFiles.map((file) => `out-of-scope:${file}`),
441
+ ...(drift?.unexpectedFiles || []).map((file) => `unexpected-file:${file}`),
442
+ ...(payload.ownershipBoundaryCrossed || []).map((entry) => `ownership-boundary:${entry}`),
443
+ ], 24);
444
+ const currentFailure = [
445
+ `${payload.severity} ${payload.ruleId} in ${payload.filePath}${payload.line ? `:${payload.line}` : ''}`,
446
+ payload.operationalExplanation || payload.suggestedPromptHint,
447
+ ].filter(Boolean).join(' — ');
448
+ const handoffBase = {
449
+ schemaVersion: REMEDIATION_HANDOFF_SCHEMA,
450
+ purpose: 'bounded-operational-remediation',
451
+ runtimeIdentity: {
452
+ name: 'Neurcode',
453
+ role: 'Deterministic operational governance runtime for AI-assisted engineering.',
454
+ notRole: [
455
+ 'autonomous coding agent',
456
+ 'code generator',
457
+ 'scanner-only tool',
458
+ 'probabilistic reviewer',
459
+ ],
460
+ trustBoundary: payload.trustBoundaryStatement,
461
+ },
462
+ lifecycle: {
463
+ currentStage: 'verify-failed-remediation-handoff',
464
+ direction: 'deterministic verify failure -> bounded external AI remediation -> deterministic re-verify',
465
+ closureCommand: 'neurcode verify --evidence',
466
+ replayContinuity: payload.replayChecksum
467
+ ? `Preserve replay continuity from checksum ${payload.replayChecksum}.`
468
+ : 'Re-run verify after remediation so replay continuity can be reconstructed.',
469
+ },
470
+ continuity: {
471
+ exportId: payload.exportId,
472
+ findingId: payload.findingId,
473
+ findingGraphHash: payload.findingGraphHash,
474
+ replayChecksum: payload.replayChecksum,
475
+ replayMode: payload.replayMode,
476
+ provenanceRunId: payload.provenanceRunId,
477
+ planId: payload.planId,
478
+ },
479
+ objective: {
480
+ intentSummary: context?.intentSummary || payload.intentGovernance?.riskSummary || 'No authored intent summary was present in the verify payload.',
481
+ governanceObjective: 'Resolve the blocking finding while preserving the declared intent, approved scope, dependency boundary, generated-code policy, and replay expectations.',
482
+ currentFailure,
483
+ remediationCategory: payload.remediationCategory,
484
+ },
485
+ scope: {
486
+ targetFile: payload.filePath,
487
+ targetLine: payload.line,
488
+ allowedFiles,
489
+ approvedModules: context?.approvedScope.modules || [],
490
+ approvedServices: context?.approvedScope.services || [],
491
+ forbiddenBoundaries,
492
+ generatedCodePolicy: 'Do not edit generated-code surfaces directly. Regenerate from source or stop and report if the target is generated.',
493
+ },
494
+ behaviorContract: {
495
+ do: [
496
+ 'Minimally resolve the blocking governance finding.',
497
+ 'Inspect the cited code and nearby context before editing.',
498
+ 'Keep changes inside the allowed file, module, service, and intent boundary.',
499
+ 'Preserve architectural intent, ownership boundaries, and existing style.',
500
+ 'Run or recommend the deterministic verification loop after edits.',
501
+ ],
502
+ doNot: [
503
+ 'Do not broaden implementation scope.',
504
+ 'Do not perform unrelated refactors, formatting sweeps, dependency upgrades, or architecture changes.',
505
+ 'Do not touch generated-code surfaces directly.',
506
+ 'Do not widen dependency, import, infrastructure, CI, or rollout boundaries.',
507
+ 'Do not treat Neurcode findings as suggestions to debate away.',
508
+ ],
509
+ constraints: [
510
+ 'No autonomous governance decisions.',
511
+ 'No policy exception creation.',
512
+ 'No suppression unless explicitly requested by a human through governed workflow.',
513
+ 'Stop and explain if the requested remediation cannot be completed inside the boundary.',
514
+ ],
515
+ minimalityExpectations: [
516
+ 'Prefer the smallest code change that clears the finding.',
517
+ 'Avoid new abstractions unless required to satisfy the rule safely.',
518
+ 'Preserve public APIs unless the finding explicitly concerns the public API.',
519
+ 'Keep tests focused on the changed behavior when tests are needed.',
520
+ ],
521
+ },
522
+ successCriteria: [
523
+ 'The cited finding is resolved in the target file.',
524
+ 'No new blocking or advisory Neurcode findings are introduced.',
525
+ 'Approved scope, forbidden boundaries, generated-code policy, and import-edge governance remain intact.',
526
+ 'The engineer can run `neurcode verify --evidence` and get a PASS or a narrower, explainable remaining finding.',
527
+ ],
528
+ verificationLoop: {
529
+ required: true,
530
+ command: 'neurcode verify --evidence',
531
+ expectation: 'Re-run deterministic verify after the external AI edit. Do not claim closure before verify passes.',
532
+ },
533
+ outputExpectations: [
534
+ 'State the files changed and why each change was necessary.',
535
+ 'Call out any boundary uncertainty instead of guessing.',
536
+ 'Do not claim Neurcode approval; only Neurcode verify can close the loop.',
537
+ ],
538
+ };
539
+ const handoff = handoffBase;
540
+ handoff.providerHandoffs = {
541
+ claude: buildProviderHandoff('claude', handoffBase, payload, projectRoot),
542
+ codex: buildProviderHandoff('codex', handoffBase, payload, projectRoot),
543
+ cursor: buildProviderHandoff('cursor', handoffBase, payload, projectRoot),
544
+ gemini: buildProviderHandoff('gemini', handoffBase, payload, projectRoot),
545
+ };
546
+ return handoff;
547
+ }
548
+ function buildProviderHandoff(provider, handoff, payload, projectRoot) {
549
+ const prompt = buildProviderPrompt(provider, handoff, payload);
550
+ const compactPrompt = buildProviderPrompt(provider, handoff, payload, { compact: true });
551
+ const encodedPrompt = encodeURIComponent(compactPrompt);
552
+ const cwd = encodeURIComponent(projectRoot);
553
+ const label = provider === 'claude'
554
+ ? 'Claude Code'
555
+ : provider === 'codex'
556
+ ? 'Codex'
557
+ : provider === 'cursor'
558
+ ? 'Cursor'
559
+ : 'Gemini CLI';
560
+ const command = provider === 'codex'
561
+ ? `codex --cd ${shellQuote(projectRoot)} ${shellQuote(prompt)}`
562
+ : provider === 'cursor'
563
+ ? `cursor-agent ${shellQuote(prompt)}`
564
+ : provider === 'gemini'
565
+ ? `gemini -p ${shellQuote(prompt)}`
566
+ : null;
567
+ const claudeLink = provider === 'claude' && compactPrompt.length <= 5000
568
+ ? `claude-cli://open?cwd=${cwd}&q=${encodedPrompt}`
569
+ : null;
570
+ return {
571
+ provider,
572
+ label,
573
+ optimizedFor: providerOptimizations(provider),
574
+ clipboardTitle: `Remediate in ${label}`,
575
+ prompt,
576
+ launch: {
577
+ mode: provider === 'claude' ? 'deep-link' : command ? 'cli-command' : 'clipboard',
578
+ available: provider === 'claude' ? Boolean(claudeLink) : Boolean(command),
579
+ deepLink: claudeLink,
580
+ command,
581
+ limitation: provider === 'claude'
582
+ ? claudeLink
583
+ ? null
584
+ : 'Claude Code deep links accept prompts up to 5,000 characters; use the clipboard prompt for this larger handoff.'
585
+ : `${label} does not expose a documented universal prompt-prefill deep link in the audited docs; use the CLI command or clipboard prompt.`,
586
+ },
587
+ };
588
+ }
589
+ function providerOptimizations(provider) {
590
+ switch (provider) {
591
+ case 'claude':
592
+ return ['Claude Code deep-link prefill', 'explicit contract tags', 'long-context boundary retention'];
593
+ case 'codex':
594
+ return ['local workspace execution', 'reviewable patch workflow', 'approval-aware command execution'];
595
+ case 'cursor':
596
+ return ['IDE agent/composer workflow', 'file-local context anchoring', 'rule-aware editing'];
597
+ case 'gemini':
598
+ return ['CLI prompt mode', 'checklist-style boundaries', 'explicit anti-broadening constraints'];
599
+ }
600
+ }
601
+ function buildProviderPrompt(provider, handoff, payload, options = {}) {
602
+ const providerDirective = {
603
+ claude: 'Claude Code: read this as an operational contract before editing. Keep a short plan, then implement only the bounded fix.',
604
+ codex: 'Codex: operate as a local coding agent under strict governance constraints. Inspect first, edit narrowly, then summarize verification.',
605
+ cursor: 'Cursor: use Agent/Composer with this file as the anchor. Do not fan out across the codebase unless the allowed scope below requires it.',
606
+ gemini: 'Gemini CLI: follow the checklist exactly. Avoid broad rewrites; stop if the fix requires scope expansion.',
607
+ }[provider];
608
+ const allowed = handoff.scope.allowedFiles.slice(0, options.compact ? 8 : 18);
609
+ const forbidden = handoff.scope.forbiddenBoundaries.slice(0, options.compact ? 6 : 14);
610
+ const lines = [
611
+ '# Neurcode Remediation Handoff',
612
+ '',
613
+ providerDirective,
614
+ '',
615
+ '## Runtime Identity',
616
+ `${handoff.runtimeIdentity.name} is a deterministic operational governance runtime for AI-assisted engineering.`,
617
+ `It is not: ${handoff.runtimeIdentity.notRole.join(', ')}.`,
618
+ handoff.runtimeIdentity.trustBoundary,
619
+ '',
620
+ '## Governance Objective',
621
+ handoff.objective.governanceObjective,
622
+ '',
623
+ '## Current Deterministic Failure',
624
+ `Finding: ${handoff.objective.currentFailure}`,
625
+ `Category: ${handoff.objective.remediationCategory}`,
626
+ `Target: ${handoff.scope.targetFile}${handoff.scope.targetLine ? `:${handoff.scope.targetLine}` : ''}`,
627
+ payload.codeSpan ? `Code span: ${payload.codeSpan}` : '',
628
+ '',
629
+ '## Intent And Scope',
630
+ `Intent summary: ${handoff.objective.intentSummary}`,
631
+ `Allowed files: ${allowed.length ? allowed.join(', ') : handoff.scope.targetFile}`,
632
+ handoff.scope.approvedModules.length ? `Approved modules: ${handoff.scope.approvedModules.join(', ')}` : '',
633
+ handoff.scope.approvedServices.length ? `Approved services: ${handoff.scope.approvedServices.join(', ')}` : '',
634
+ forbidden.length ? `Forbidden boundaries: ${forbidden.join(' | ')}` : 'Forbidden boundaries: do not expand dependencies, imports, generated-code, infra, CI, rollout, or ownership scope.',
635
+ handoff.scope.generatedCodePolicy,
636
+ '',
637
+ '## Required Behavior',
638
+ ...handoff.behaviorContract.do.map((entry) => `DO: ${entry}`),
639
+ ...handoff.behaviorContract.doNot.map((entry) => `DO NOT: ${entry}`),
640
+ '',
641
+ '## Minimality Constraints',
642
+ ...handoff.behaviorContract.minimalityExpectations.map((entry) => `- ${entry}`),
643
+ '',
644
+ '## Success Criteria',
645
+ ...handoff.successCriteria.map((entry) => `- ${entry}`),
646
+ '',
647
+ '## Verification Loop',
648
+ `After remediation, run: ${handoff.verificationLoop.command}`,
649
+ handoff.verificationLoop.expectation,
650
+ '',
651
+ '## Continuity',
652
+ `Export ID: ${handoff.continuity.exportId}`,
653
+ `Finding graph hash: ${handoff.continuity.findingGraphHash}`,
654
+ handoff.continuity.replayChecksum ? `Replay checksum: ${handoff.continuity.replayChecksum}` : 'Replay checksum: unavailable in source verify payload',
655
+ ].filter((line) => line !== '');
656
+ if (!options.compact && payload.surroundingContext.trim().length > 0) {
657
+ lines.push('', '## Local Code Context', '```', payload.surroundingContext, '```');
658
+ }
659
+ if (!options.compact && payload.relevantNarratives.length > 0) {
660
+ lines.push('', '## Relevant Governance Narrative');
661
+ payload.relevantNarratives.slice(0, 3).forEach((entry, index) => {
662
+ lines.push(`${index + 1}. ${entry.summary}`);
663
+ lines.push(`Root cause: ${entry.rootCause}`);
664
+ lines.push(`Boundary: ${entry.remediationBoundary}`);
665
+ });
666
+ }
667
+ lines.push('', '## Output Expectations', ...handoff.outputExpectations.map((entry) => `- ${entry}`));
668
+ return lines.join('\n');
669
+ }
670
+ function renderRemediationOutput(payloads, format, provider) {
671
+ if (format === 'prompt' && provider) {
672
+ return payloads.map((payload) => payload.agentHandoff.providerHandoffs[provider].prompt).join('\n\n---\n\n');
673
+ }
674
+ if (format === 'markdown') {
675
+ return payloads.map((payload) => renderMarkdownHandoff(payload, provider)).join('\n\n---\n\n');
676
+ }
677
+ if (format === 'mcp') {
678
+ return payloads.length === 1
679
+ ? JSON.stringify(payloads[0].mcpEnvelope, null, 2)
680
+ : JSON.stringify(payloads.map((payload) => payload.mcpEnvelope), null, 2);
681
+ }
682
+ return payloads.length === 1
683
+ ? JSON.stringify(payloads[0], null, 2)
684
+ : JSON.stringify(payloads, null, 2);
685
+ }
686
+ function renderMarkdownHandoff(payload, provider) {
687
+ const selected = provider ? [payload.agentHandoff.providerHandoffs[provider]] : PROVIDERS.map((entry) => payload.agentHandoff.providerHandoffs[entry]);
688
+ const lines = [
689
+ '# Neurcode Remediation Handoff',
690
+ '',
691
+ `Export: \`${payload.exportId}\``,
692
+ `Finding: \`${payload.ruleId}\` in \`${payload.filePath}${payload.line ? `:${payload.line}` : ''}\``,
693
+ `Replay: \`${payload.replayChecksum || 'unavailable'}\``,
694
+ '',
695
+ payload.agentHandoff.objective.governanceObjective,
696
+ '',
697
+ ];
698
+ selected.forEach((handoff) => {
699
+ lines.push(`## ${handoff.clipboardTitle}`);
700
+ if (handoff.launch.deepLink)
701
+ lines.push(`[Open ${handoff.label}](${handoff.launch.deepLink})`);
702
+ if (handoff.launch.command) {
703
+ lines.push('```bash');
704
+ lines.push(handoff.launch.command);
705
+ lines.push('```');
706
+ }
707
+ if (handoff.launch.limitation)
708
+ lines.push(`Note: ${handoff.launch.limitation}`);
709
+ lines.push('');
710
+ lines.push('```text');
711
+ lines.push(handoff.prompt);
712
+ lines.push('```');
713
+ lines.push('');
714
+ });
715
+ return lines.join('\n');
716
+ }
717
+ function openProviderHandoff(payload, provider) {
718
+ const handoff = payload.agentHandoff.providerHandoffs[provider];
719
+ if (!handoff.launch.deepLink) {
720
+ console.error(chalk.yellow(`\n⚠ ${handoff.label} does not have an available documented deep-link for this payload.`));
721
+ if (handoff.launch.command) {
722
+ console.error(chalk.dim(' Use this command instead:'));
723
+ console.error(chalk.cyan(` ${handoff.launch.command}`));
724
+ }
725
+ return;
726
+ }
727
+ try {
728
+ if (process.platform === 'darwin') {
729
+ (0, child_process_1.execFileSync)('open', [handoff.launch.deepLink], { stdio: 'ignore' });
730
+ }
731
+ else if (process.platform === 'win32') {
732
+ (0, child_process_1.execFileSync)('cmd', ['/c', 'start', '', handoff.launch.deepLink], { stdio: 'ignore' });
733
+ }
734
+ else {
735
+ (0, child_process_1.execFileSync)('xdg-open', [handoff.launch.deepLink], { stdio: 'ignore' });
736
+ }
737
+ console.error(chalk.green(`\n✅ Opened ${handoff.label} handoff.`));
738
+ }
739
+ catch {
740
+ console.error(chalk.yellow(`\n⚠ Could not open ${handoff.label}. Copy the deep link or prompt from the export instead.`));
741
+ }
742
+ }
376
743
  function extractGovernanceDecisionLineage(value) {
377
744
  const record = asRecord(value);
378
745
  if (!record)