@neurcode-ai/cli 0.14.0 → 0.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +60 -8
- package/dist/api-client.d.ts +284 -0
- package/dist/api-client.d.ts.map +1 -1
- package/dist/api-client.js +111 -0
- package/dist/api-client.js.map +1 -1
- package/dist/commands/activate.d.ts +82 -0
- package/dist/commands/activate.d.ts.map +1 -0
- package/dist/commands/activate.js +551 -0
- package/dist/commands/activate.js.map +1 -0
- package/dist/commands/admission.d.ts +67 -0
- package/dist/commands/admission.d.ts.map +1 -0
- package/dist/commands/admission.js +350 -0
- package/dist/commands/admission.js.map +1 -0
- package/dist/commands/agent.d.ts +3 -0
- package/dist/commands/agent.d.ts.map +1 -0
- package/dist/commands/agent.js +2045 -0
- package/dist/commands/agent.js.map +1 -0
- package/dist/commands/demo.d.ts +3 -0
- package/dist/commands/demo.d.ts.map +1 -0
- package/dist/commands/demo.js +102 -0
- package/dist/commands/demo.js.map +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +58 -44
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/login.d.ts +1 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +44 -22
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/profile.d.ts +14 -0
- package/dist/commands/profile.d.ts.map +1 -0
- package/dist/commands/profile.js +118 -0
- package/dist/commands/profile.js.map +1 -0
- package/dist/commands/quickstart.d.ts +2 -2
- package/dist/commands/quickstart.d.ts.map +1 -1
- package/dist/commands/quickstart.js +31 -30
- package/dist/commands/quickstart.js.map +1 -1
- package/dist/commands/remediate-export.d.ts +6 -1
- package/dist/commands/remediate-export.d.ts.map +1 -1
- package/dist/commands/remediate-export.js +359 -7
- package/dist/commands/remediate-export.js.map +1 -1
- package/dist/commands/replay.d.ts.map +1 -1
- package/dist/commands/replay.js +84 -0
- package/dist/commands/replay.js.map +1 -1
- package/dist/commands/run.d.ts +3 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +98 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/runtime-adapter.d.ts +8 -0
- package/dist/commands/runtime-adapter.d.ts.map +1 -0
- package/dist/commands/runtime-adapter.js +375 -0
- package/dist/commands/runtime-adapter.js.map +1 -0
- package/dist/commands/runtime-doctor.d.ts +6 -0
- package/dist/commands/runtime-doctor.d.ts.map +1 -0
- package/dist/commands/runtime-doctor.js +478 -0
- package/dist/commands/runtime-doctor.js.map +1 -0
- package/dist/commands/runtime-report.d.ts +13 -0
- package/dist/commands/runtime-report.d.ts.map +1 -0
- package/dist/commands/runtime-report.js +81 -0
- package/dist/commands/runtime-report.js.map +1 -0
- package/dist/commands/runtime-sync.d.ts +17 -0
- package/dist/commands/runtime-sync.d.ts.map +1 -0
- package/dist/commands/runtime-sync.js +656 -0
- package/dist/commands/runtime-sync.js.map +1 -0
- package/dist/commands/runtime.d.ts +16 -0
- package/dist/commands/runtime.d.ts.map +1 -0
- package/dist/commands/runtime.js +380 -0
- package/dist/commands/runtime.js.map +1 -0
- package/dist/commands/session-hook.d.ts +35 -0
- package/dist/commands/session-hook.d.ts.map +1 -0
- package/dist/commands/session-hook.js +1297 -0
- package/dist/commands/session-hook.js.map +1 -0
- package/dist/commands/session.d.ts +91 -0
- package/dist/commands/session.d.ts.map +1 -1
- package/dist/commands/session.js +1226 -0
- package/dist/commands/session.js.map +1 -1
- package/dist/commands/whoami.d.ts +7 -4
- package/dist/commands/whoami.d.ts.map +1 -1
- package/dist/commands/whoami.js +59 -34
- package/dist/commands/whoami.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +24 -5
- package/dist/config.js.map +1 -1
- package/dist/daemon/routes.d.ts.map +1 -1
- package/dist/daemon/routes.js +8 -0
- package/dist/daemon/routes.js.map +1 -1
- package/dist/daemon/server.d.ts.map +1 -1
- package/dist/daemon/server.js +88 -0
- package/dist/daemon/server.js.map +1 -1
- package/dist/governance/impact-analysis.d.ts +27 -0
- package/dist/governance/impact-analysis.d.ts.map +1 -0
- package/dist/governance/impact-analysis.js +274 -0
- package/dist/governance/impact-analysis.js.map +1 -0
- package/dist/index.js +472 -29
- package/dist/index.js.map +1 -1
- package/dist/intent-engine/matcher.d.ts.map +1 -1
- package/dist/intent-engine/matcher.js +3 -12
- package/dist/intent-engine/matcher.js.map +1 -1
- package/dist/utils/admission-artifact.d.ts +59 -0
- package/dist/utils/admission-artifact.d.ts.map +1 -0
- package/dist/utils/admission-artifact.js +410 -0
- package/dist/utils/admission-artifact.js.map +1 -0
- package/dist/utils/agent-adapter-setup.d.ts +80 -0
- package/dist/utils/agent-adapter-setup.d.ts.map +1 -0
- package/dist/utils/agent-adapter-setup.js +577 -0
- package/dist/utils/agent-adapter-setup.js.map +1 -0
- package/dist/utils/agent-guard-supervisor.d.ts +75 -0
- package/dist/utils/agent-guard-supervisor.d.ts.map +1 -0
- package/dist/utils/agent-guard-supervisor.js +388 -0
- package/dist/utils/agent-guard-supervisor.js.map +1 -0
- package/dist/utils/agent-guard.d.ts +92 -0
- package/dist/utils/agent-guard.d.ts.map +1 -0
- package/dist/utils/agent-guard.js +326 -0
- package/dist/utils/agent-guard.js.map +1 -0
- package/dist/utils/agent-session-launcher.d.ts +89 -0
- package/dist/utils/agent-session-launcher.d.ts.map +1 -0
- package/dist/utils/agent-session-launcher.js +308 -0
- package/dist/utils/agent-session-launcher.js.map +1 -0
- package/dist/utils/bash-command-analysis.d.ts +19 -0
- package/dist/utils/bash-command-analysis.d.ts.map +1 -0
- package/dist/utils/bash-command-analysis.js +295 -0
- package/dist/utils/bash-command-analysis.js.map +1 -0
- package/dist/utils/consequence-nudges.d.ts +30 -0
- package/dist/utils/consequence-nudges.d.ts.map +1 -0
- package/dist/utils/consequence-nudges.js +313 -0
- package/dist/utils/consequence-nudges.js.map +1 -0
- package/dist/utils/drift-intelligence.d.ts.map +1 -1
- package/dist/utils/drift-intelligence.js +29 -7
- package/dist/utils/drift-intelligence.js.map +1 -1
- package/dist/utils/git-coverage.d.ts +57 -0
- package/dist/utils/git-coverage.d.ts.map +1 -0
- package/dist/utils/git-coverage.js +302 -0
- package/dist/utils/git-coverage.js.map +1 -0
- package/dist/utils/gitignore.d.ts.map +1 -1
- package/dist/utils/gitignore.js +2 -1
- package/dist/utils/gitignore.js.map +1 -1
- package/dist/utils/governed-intent.d.ts +10 -0
- package/dist/utils/governed-intent.d.ts.map +1 -0
- package/dist/utils/governed-intent.js +108 -0
- package/dist/utils/governed-intent.js.map +1 -0
- package/dist/utils/hook-heartbeat.d.ts +55 -0
- package/dist/utils/hook-heartbeat.d.ts.map +1 -0
- package/dist/utils/hook-heartbeat.js +116 -0
- package/dist/utils/hook-heartbeat.js.map +1 -0
- package/dist/utils/intent-continuity.d.ts +21 -0
- package/dist/utils/intent-continuity.d.ts.map +1 -0
- package/dist/utils/intent-continuity.js +192 -0
- package/dist/utils/intent-continuity.js.map +1 -0
- package/dist/utils/messages.d.ts +1 -1
- package/dist/utils/messages.d.ts.map +1 -1
- package/dist/utils/messages.js +24 -21
- package/dist/utils/messages.js.map +1 -1
- package/dist/utils/runtime-companion.d.ts +137 -0
- package/dist/utils/runtime-companion.d.ts.map +1 -0
- package/dist/utils/runtime-companion.js +231 -0
- package/dist/utils/runtime-companion.js.map +1 -0
- package/dist/utils/runtime-connection.d.ts +46 -0
- package/dist/utils/runtime-connection.d.ts.map +1 -0
- package/dist/utils/runtime-connection.js +148 -0
- package/dist/utils/runtime-connection.js.map +1 -0
- package/dist/utils/runtime-evidence.d.ts +68 -0
- package/dist/utils/runtime-evidence.d.ts.map +1 -0
- package/dist/utils/runtime-evidence.js +248 -0
- package/dist/utils/runtime-evidence.js.map +1 -0
- package/dist/utils/runtime-live.d.ts +33 -0
- package/dist/utils/runtime-live.d.ts.map +1 -0
- package/dist/utils/runtime-live.js +361 -0
- package/dist/utils/runtime-live.js.map +1 -0
- package/dist/utils/runtime-outbox.d.ts +76 -0
- package/dist/utils/runtime-outbox.d.ts.map +1 -0
- package/dist/utils/runtime-outbox.js +410 -0
- package/dist/utils/runtime-outbox.js.map +1 -0
- package/dist/utils/runtime-receipt.d.ts +50 -0
- package/dist/utils/runtime-receipt.d.ts.map +1 -0
- package/dist/utils/runtime-receipt.js +223 -0
- package/dist/utils/runtime-receipt.js.map +1 -0
- package/dist/utils/state.d.ts +21 -0
- package/dist/utils/state.d.ts.map +1 -1
- package/dist/utils/state.js +30 -0
- package/dist/utils/state.js.map +1 -1
- package/dist/utils/structural-understanding.d.ts +334 -0
- package/dist/utils/structural-understanding.d.ts.map +1 -0
- package/dist/utils/structural-understanding.js +2316 -0
- package/dist/utils/structural-understanding.js.map +1 -0
- package/dist/utils/v0-governance.d.ts +197 -0
- package/dist/utils/v0-governance.d.ts.map +1 -0
- package/dist/utils/v0-governance.js +904 -0
- package/dist/utils/v0-governance.js.map +1 -0
- package/package.json +11 -12
|
@@ -27,11 +27,14 @@ const crypto_1 = require("crypto");
|
|
|
27
27
|
const child_process_1 = require("child_process");
|
|
28
28
|
const runtime_state_1 = require("../utils/runtime-state");
|
|
29
29
|
const cli_json_1 = require("../utils/cli-json");
|
|
30
|
+
const plan_cache_1 = require("../utils/plan-cache");
|
|
30
31
|
const chalk = (0, cli_json_1.loadChalk)();
|
|
31
32
|
// ── Trust boundary statement — fixed, never changes ──────────────────────────
|
|
32
33
|
const TRUST_BOUNDARY_STATEMENT = 'Neurcode deterministically detects and governs. ' +
|
|
33
|
-
'Your AI coding assistant (
|
|
34
|
+
'Your AI coding assistant (Claude, Codex, Cursor, Gemini, GitHub Copilot) performs remediation. ' +
|
|
34
35
|
'Neurcode never autonomously modifies production code.';
|
|
36
|
+
const REMEDIATION_HANDOFF_SCHEMA = 'neurcode.remediation-handoff.v1';
|
|
37
|
+
const PROVIDERS = ['claude', 'codex', 'cursor', 'gemini'];
|
|
35
38
|
// ── Remediation category map — deterministic, ruleId-keyed ───────────────────
|
|
36
39
|
const REMEDIATION_CATEGORY = {
|
|
37
40
|
PY003: 'exception-handling',
|
|
@@ -179,13 +182,17 @@ async function remediateExportCommand(options) {
|
|
|
179
182
|
console.log(chalk.dim(`No finding specified. Exporting finding at index 0. Use --finding-index N or --all.\n`));
|
|
180
183
|
selected = [findings[0]];
|
|
181
184
|
}
|
|
182
|
-
const format = options.format
|
|
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
|
+
}
|
|
183
192
|
const replayChecksum = resolveReplayChecksum(verifyOutput);
|
|
184
193
|
const replayMode = resolveReplayMode(verifyOutput);
|
|
185
194
|
const payloads = selected.map((finding) => buildPayload(finding, verifyOutput, projectRoot, replayChecksum, replayMode, format));
|
|
186
|
-
const output = payloads
|
|
187
|
-
? JSON.stringify(format === 'mcp' ? payloads[0].mcpEnvelope : payloads[0], null, 2)
|
|
188
|
-
: JSON.stringify(format === 'mcp' ? payloads.map(p => p.mcpEnvelope) : payloads, null, 2);
|
|
195
|
+
const output = renderRemediationOutput(payloads, format, provider);
|
|
189
196
|
// Write to file or stdout
|
|
190
197
|
if (options.out) {
|
|
191
198
|
const outPath = (0, path_1.resolve)(projectRoot, options.out);
|
|
@@ -205,8 +212,16 @@ async function remediateExportCommand(options) {
|
|
|
205
212
|
console.error(chalk.yellow('\n⚠ --copy failed (pbcopy not available on this system).'));
|
|
206
213
|
}
|
|
207
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
|
+
}
|
|
208
223
|
// Print trust boundary reminder
|
|
209
|
-
if (!options.json) {
|
|
224
|
+
if (!options.json && format === 'json') {
|
|
210
225
|
console.error(chalk.dim('\n─────────────────────────────────────────────────────────'));
|
|
211
226
|
console.error(chalk.cyan(' Trust Boundary'));
|
|
212
227
|
console.error(chalk.dim(' Neurcode detects. Your AI assistant remediates.'));
|
|
@@ -298,7 +313,7 @@ function buildPayload(finding, verifyOutput, projectRoot, replayChecksum, replay
|
|
|
298
313
|
const payload = {
|
|
299
314
|
exportId,
|
|
300
315
|
exportedAt: new Date().toISOString(),
|
|
301
|
-
neurcodeVersion:
|
|
316
|
+
neurcodeVersion: (0, plan_cache_1.getNeurcodeVersion)(),
|
|
302
317
|
schemaVersion: '2026-05-14',
|
|
303
318
|
findingId,
|
|
304
319
|
ruleId,
|
|
@@ -338,7 +353,9 @@ function buildPayload(finding, verifyOutput, projectRoot, replayChecksum, replay
|
|
|
338
353
|
graphImpact,
|
|
339
354
|
relevantNarratives,
|
|
340
355
|
suggestedPromptHint,
|
|
356
|
+
agentHandoff: undefined,
|
|
341
357
|
};
|
|
358
|
+
payload.agentHandoff = buildAgentHandoff(payload, projectRoot);
|
|
342
359
|
if (format === 'mcp') {
|
|
343
360
|
payload.mcpEnvelope = {
|
|
344
361
|
type: 'neurcode/remediation-request',
|
|
@@ -388,6 +405,341 @@ function asStringArray(value, limit = 12) {
|
|
|
388
405
|
.filter((entry) => typeof entry === 'string' && entry.trim().length > 0)
|
|
389
406
|
.slice(0, limit);
|
|
390
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
|
+
}
|
|
391
743
|
function extractGovernanceDecisionLineage(value) {
|
|
392
744
|
const record = asRecord(value);
|
|
393
745
|
if (!record)
|