@neurcode-ai/cli 0.9.36 → 0.9.38

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 (49) hide show
  1. package/README.md +4 -2
  2. package/dist/api-client.d.ts +300 -1
  3. package/dist/api-client.d.ts.map +1 -1
  4. package/dist/api-client.js +225 -9
  5. package/dist/api-client.js.map +1 -1
  6. package/dist/commands/audit.d.ts +3 -0
  7. package/dist/commands/audit.d.ts.map +1 -0
  8. package/dist/commands/audit.js +133 -0
  9. package/dist/commands/audit.js.map +1 -0
  10. package/dist/commands/contract.d.ts +3 -0
  11. package/dist/commands/contract.d.ts.map +1 -0
  12. package/dist/commands/contract.js +235 -0
  13. package/dist/commands/contract.js.map +1 -0
  14. package/dist/commands/feedback.d.ts +3 -0
  15. package/dist/commands/feedback.d.ts.map +1 -0
  16. package/dist/commands/feedback.js +208 -0
  17. package/dist/commands/feedback.js.map +1 -0
  18. package/dist/commands/plan.d.ts.map +1 -1
  19. package/dist/commands/plan.js +19 -3
  20. package/dist/commands/plan.js.map +1 -1
  21. package/dist/commands/policy.d.ts.map +1 -1
  22. package/dist/commands/policy.js +329 -6
  23. package/dist/commands/policy.js.map +1 -1
  24. package/dist/commands/remediate.d.ts +17 -0
  25. package/dist/commands/remediate.d.ts.map +1 -0
  26. package/dist/commands/remediate.js +252 -0
  27. package/dist/commands/remediate.js.map +1 -0
  28. package/dist/commands/ship.d.ts.map +1 -1
  29. package/dist/commands/ship.js +67 -14
  30. package/dist/commands/ship.js.map +1 -1
  31. package/dist/commands/verify.d.ts +12 -0
  32. package/dist/commands/verify.d.ts.map +1 -1
  33. package/dist/commands/verify.js +477 -13
  34. package/dist/commands/verify.js.map +1 -1
  35. package/dist/index.js +60 -0
  36. package/dist/index.js.map +1 -1
  37. package/dist/utils/artifact-signature.d.ts +34 -0
  38. package/dist/utils/artifact-signature.d.ts.map +1 -0
  39. package/dist/utils/artifact-signature.js +229 -0
  40. package/dist/utils/artifact-signature.js.map +1 -0
  41. package/dist/utils/change-contract.d.ts +2 -0
  42. package/dist/utils/change-contract.d.ts.map +1 -1
  43. package/dist/utils/change-contract.js +21 -1
  44. package/dist/utils/change-contract.js.map +1 -1
  45. package/dist/utils/policy-compiler.d.ts +2 -0
  46. package/dist/utils/policy-compiler.d.ts.map +1 -1
  47. package/dist/utils/policy-compiler.js +15 -0
  48. package/dist/utils/policy-compiler.js.map +1 -1
  49. package/package.json +7 -7
@@ -180,7 +180,7 @@ function shellTailLines(text, limit) {
180
180
  .join('\n');
181
181
  }
182
182
  function emitShipJson(payload) {
183
- console.log(JSON.stringify(payload, null, 2));
183
+ process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
184
184
  }
185
185
  function inferStepStatus(run) {
186
186
  if (!run)
@@ -219,6 +219,7 @@ function runCliCommand(cwd, args, extraEnv, execution) {
219
219
  const timeoutMs = execution?.timeoutMs ?? getPlanTimeoutMs();
220
220
  const heartbeatMs = execution?.heartbeatMs ?? getHeartbeatIntervalMs();
221
221
  const commandLabel = execution?.label || `neurcode ${args.join(' ')}`;
222
+ const streamOutput = execution?.streamOutput !== false;
222
223
  const child = (0, child_process_1.spawn)(process.execPath, [getCliEntryPath(), ...args], {
223
224
  cwd,
224
225
  env: {
@@ -288,12 +289,16 @@ function runCliCommand(cwd, args, extraEnv, execution) {
288
289
  child.stdout.on('data', (chunk) => {
289
290
  const text = chunk.toString();
290
291
  stdout += text;
291
- process.stdout.write(text);
292
+ if (streamOutput) {
293
+ process.stdout.write(text);
294
+ }
292
295
  });
293
296
  child.stderr.on('data', (chunk) => {
294
297
  const text = chunk.toString();
295
298
  stderr += text;
296
- process.stderr.write(text);
299
+ if (streamOutput) {
300
+ process.stderr.write(text);
301
+ }
297
302
  });
298
303
  child.on('error', (error) => {
299
304
  stderr += `${error instanceof Error ? error.message : String(error)}\n`;
@@ -314,6 +319,7 @@ function runShellCommand(cwd, command, execution) {
314
319
  const timeoutMs = execution?.timeoutMs ?? getTestTimeoutMs();
315
320
  const heartbeatMs = execution?.heartbeatMs ?? getHeartbeatIntervalMs();
316
321
  const commandLabel = execution?.label || command;
322
+ const streamOutput = execution?.streamOutput !== false;
317
323
  const child = (0, child_process_1.spawn)(command, {
318
324
  cwd,
319
325
  env: {
@@ -382,12 +388,16 @@ function runShellCommand(cwd, command, execution) {
382
388
  child.stdout.on('data', (chunk) => {
383
389
  const text = chunk.toString();
384
390
  stdout += text;
385
- process.stdout.write(text);
391
+ if (streamOutput) {
392
+ process.stdout.write(text);
393
+ }
386
394
  });
387
395
  child.stderr.on('data', (chunk) => {
388
396
  const text = chunk.toString();
389
397
  stderr += text;
390
- process.stderr.write(text);
398
+ if (streamOutput) {
399
+ process.stderr.write(text);
400
+ }
391
401
  });
392
402
  child.on('error', (error) => {
393
403
  stderr += `${error instanceof Error ? error.message : String(error)}\n`;
@@ -413,20 +423,46 @@ function extractPlanId(output) {
413
423
  }
414
424
  function extractLastJsonObject(output) {
415
425
  const clean = stripAnsi(output).trim();
416
- const end = clean.lastIndexOf('}');
417
- if (end < 0)
426
+ if (!clean)
418
427
  return null;
419
- let start = clean.lastIndexOf('{', end);
428
+ // Fast path for strict JSON mode outputs (single payload, no human preamble).
429
+ try {
430
+ return JSON.parse(clean);
431
+ }
432
+ catch {
433
+ // Fall through to mixed-output recovery.
434
+ }
435
+ const firstBrace = clean.indexOf('{');
436
+ const end = clean.lastIndexOf('}');
437
+ if (firstBrace >= 0 && end > firstBrace) {
438
+ const envelope = clean.slice(firstBrace, end + 1).trim();
439
+ try {
440
+ return JSON.parse(envelope);
441
+ }
442
+ catch {
443
+ // Continue with fallback scanning.
444
+ }
445
+ }
446
+ // Fallback: recover the longest parseable object near the tail.
447
+ let bestMatch = null;
448
+ let bestLen = -1;
449
+ const safeEnd = end >= 0 ? end : clean.length - 1;
450
+ let start = clean.lastIndexOf('{', safeEnd);
420
451
  while (start >= 0) {
421
- const candidate = clean.slice(start, end + 1).trim();
452
+ const candidate = clean.slice(start, safeEnd + 1).trim();
422
453
  try {
423
- return JSON.parse(candidate);
454
+ const parsed = JSON.parse(candidate);
455
+ if (candidate.length > bestLen) {
456
+ bestLen = candidate.length;
457
+ bestMatch = parsed;
458
+ }
424
459
  }
425
460
  catch {
426
- start = clean.lastIndexOf('{', start - 1);
461
+ // Ignore parse failures and continue searching.
427
462
  }
463
+ start = clean.lastIndexOf('{', start - 1);
428
464
  }
429
- return null;
465
+ return bestMatch;
430
466
  }
431
467
  function parseVerifyPayload(output) {
432
468
  const parsed = extractLastJsonObject(output);
@@ -1337,6 +1373,7 @@ async function runPlanAndApply(cwd, intent, projectId, controls) {
1337
1373
  }, {
1338
1374
  timeoutMs: getPlanTimeoutMs(),
1339
1375
  label: 'ship:plan',
1376
+ streamOutput: controls?.streamOutput !== false,
1340
1377
  });
1341
1378
  const planOutput = `${planRun.stdout}\n${planRun.stderr}`;
1342
1379
  const parsedPlan = parsePlanPayload(planOutput);
@@ -1366,6 +1403,7 @@ async function runPlanAndApply(cwd, intent, projectId, controls) {
1366
1403
  const applyRun = await runCliCommand(cwd, applyArgs, undefined, {
1367
1404
  timeoutMs: getApplyTimeoutMs(),
1368
1405
  label: 'ship:apply',
1406
+ streamOutput: controls?.streamOutput !== false,
1369
1407
  });
1370
1408
  const applyOutput = `${applyRun.stdout}\n${applyRun.stderr}`;
1371
1409
  const parsedApply = parseApplyPayload(applyOutput);
@@ -1380,6 +1418,11 @@ async function runPlanAndApply(cwd, intent, projectId, controls) {
1380
1418
  return { planId, planRun, applyRun: normalizedApplyRun, writtenFiles };
1381
1419
  }
1382
1420
  async function shipCommand(goal, options) {
1421
+ if (options.json === true) {
1422
+ console.log = (() => undefined);
1423
+ console.warn = (() => undefined);
1424
+ }
1425
+ const streamStepOutput = options.json !== true;
1383
1426
  const resumedStart = options.resumeStartedAtIso ? Date.parse(options.resumeStartedAtIso) : NaN;
1384
1427
  const startedAt = Number.isFinite(resumedStart) && resumedStart > 0 ? resumedStart : Date.now();
1385
1428
  const startedAtIso = new Date(startedAt).toISOString();
@@ -1565,6 +1608,7 @@ async function shipCommand(goal, options) {
1565
1608
  let planningAttempt = 1;
1566
1609
  let initial = await runPlanAndApply(cwd, scopedGoal, options.projectId, {
1567
1610
  enforceDocumentationScope: documentationOnlyGoal,
1611
+ streamOutput: streamStepOutput,
1568
1612
  });
1569
1613
  recordRunStep(auditSteps, {
1570
1614
  stage: 'plan',
@@ -1590,6 +1634,7 @@ async function shipCommand(goal, options) {
1590
1634
  planningAttempt += 1;
1591
1635
  initial = await runPlanAndApply(cwd, strictGoal, options.projectId, {
1592
1636
  enforceDocumentationScope: true,
1637
+ streamOutput: streamStepOutput,
1593
1638
  });
1594
1639
  recordRunStep(auditSteps, {
1595
1640
  stage: 'plan',
@@ -1670,6 +1715,7 @@ async function shipCommand(goal, options) {
1670
1715
  : undefined, {
1671
1716
  timeoutMs: getVerifyTimeoutMs(),
1672
1717
  label: 'ship:verify',
1718
+ streamOutput: streamStepOutput,
1673
1719
  });
1674
1720
  verifyTotalMs += verifyRun.durationMs;
1675
1721
  verifyExitCode = verifyRun.code;
@@ -1745,7 +1791,9 @@ async function shipCommand(goal, options) {
1745
1791
  }
1746
1792
  console.log(chalk.dim(' Falling back to constrained repair plan...'));
1747
1793
  const repairIntent = buildVerifyRepairIntent(normalizedGoal, currentPlanId, verifiedPayload, remediationAttemptsUsed);
1748
- const repair = await runPlanAndApply(cwd, repairIntent, options.projectId);
1794
+ const repair = await runPlanAndApply(cwd, repairIntent, options.projectId, {
1795
+ streamOutput: streamStepOutput,
1796
+ });
1749
1797
  recordRunStep(auditSteps, {
1750
1798
  stage: 'plan',
1751
1799
  attempt: remediationAttemptsUsed + 1,
@@ -1889,6 +1937,7 @@ async function shipCommand(goal, options) {
1889
1937
  const testRun = await runShellCommand(cwd, testCommand, {
1890
1938
  timeoutMs: getTestTimeoutMs(),
1891
1939
  label: 'ship:tests',
1940
+ streamOutput: streamStepOutput,
1892
1941
  });
1893
1942
  testsTotalMs += testRun.durationMs;
1894
1943
  testsExitCode = testRun.code;
@@ -1911,7 +1960,9 @@ async function shipCommand(goal, options) {
1911
1960
  });
1912
1961
  console.log(chalk.yellow(`⚠️ Test failure auto-remediation attempt ${remediationAttemptsUsed}/${maxFixAttempts}`));
1913
1962
  const repairIntent = buildTestRepairIntent(normalizedGoal, currentPlanId, testOutput, remediationAttemptsUsed);
1914
- const repair = await runPlanAndApply(cwd, repairIntent, options.projectId);
1963
+ const repair = await runPlanAndApply(cwd, repairIntent, options.projectId, {
1964
+ streamOutput: streamStepOutput,
1965
+ });
1915
1966
  recordRunStep(auditSteps, {
1916
1967
  stage: 'plan',
1917
1968
  attempt: remediationAttemptsUsed + 1,
@@ -1956,6 +2007,7 @@ async function shipCommand(goal, options) {
1956
2007
  : undefined, {
1957
2008
  timeoutMs: getVerifyTimeoutMs(),
1958
2009
  label: 'ship:verify',
2010
+ streamOutput: streamStepOutput,
1959
2011
  });
1960
2012
  verifyTotalMs += verifyAfterTestRepair.durationMs;
1961
2013
  recordRunStep(auditSteps, {
@@ -1982,6 +2034,7 @@ async function shipCommand(goal, options) {
1982
2034
  const finalTestRun = await runShellCommand(cwd, testCommand, {
1983
2035
  timeoutMs: getTestTimeoutMs(),
1984
2036
  label: 'ship:tests',
2037
+ streamOutput: streamStepOutput,
1985
2038
  });
1986
2039
  testsTotalMs += finalTestRun.durationMs;
1987
2040
  testsExitCode = finalTestRun.code;