deadbyte-mcp 0.15.60 → 0.15.62

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 (91) hide show
  1. package/MANIFEST.SHA256 +90 -42
  2. package/PROVENANCE.json +33 -14
  3. package/README.txt +18 -18
  4. package/RELEASE.json +45 -16
  5. package/SBOM.cdx.json +2 -2
  6. package/TEST-MATRIX.json +24 -2
  7. package/bridge/package.json +1 -1
  8. package/controller/deadbyte-controller.ps1 +78 -1
  9. package/controller/deadbyte-process-policy.json +4 -4
  10. package/docs/R156-LOOP-AND-EPOCH-ROUTING.md +86 -0
  11. package/docs/R157-ARCHITECTURE-DEPENDENCIES.md +58 -0
  12. package/docs/R157-ARCHITECTURE-GRAPH.json +2874 -0
  13. package/docs/R157-ENGINEERING-HANDOFF.md +71 -0
  14. package/docs/R157-FILE-DELTA.json +80 -0
  15. package/docs/R157-FOCUSED-VERIFICATION.log +0 -0
  16. package/docs/R157-REFERENCE-CAPABILITY-MATRIX.md +207 -0
  17. package/docs/R157-REFERENCE-DECISIONS.md +46 -0
  18. package/docs/R157-REFERENCE-INVENTORY.json +2849 -0
  19. package/docs/R158-COMBINED-REGRESSION.log +0 -0
  20. package/docs/R158-DELTA.json +80 -0
  21. package/docs/R158-EPOCH-BOOTSTRAP-GREEN.log +0 -0
  22. package/docs/R158-EPOCH-BOOTSTRAP-RED.log +0 -0
  23. package/docs/R158-EPOCH-IDENTITY-RED.log +0 -0
  24. package/docs/R158-FOCUSED-GREEN.log +0 -0
  25. package/docs/R158-PROTECTED-EPOCH-VERIFIED.md +43 -0
  26. package/docs/R158-PROTECTED-EXACT-SOURCE-LIVE.log +0 -0
  27. package/docs/R158-UPDATER-REGRESSION.log +0 -0
  28. package/docs/R159-COMPLETED-HISTORY-BACKUP/deadbyte-cli.mjs.before +965 -0
  29. package/docs/R159-COMPLETED-HISTORY-BACKUP/legacy-marker-evidence-r159.mjs.before +102 -0
  30. package/docs/R159-COMPLETED-HISTORY-BACKUP/r159-legacy-marker-evidence.test.mjs.before +79 -0
  31. package/docs/R159-COMPLETED-HISTORY-PATCH.json +26 -0
  32. package/docs/R159-MARKER-LOCATOR-CHECKPOINT.md +46 -0
  33. package/docs/R160-ENGINEERING-HANDOFF.md +32 -0
  34. package/docs/R160-REFERENCE-CAPABILITY-MATRIX.json +165 -0
  35. package/package.json +2 -2
  36. package/scripts/bootstrap-uac-migration-r153.ps1 +17 -5
  37. package/scripts/deploy-r48.mjs +7 -6
  38. package/scripts/gate-windows-r160.ps1 +57 -0
  39. package/scripts/issue-uac-migration-r153.mjs +12 -5
  40. package/scripts/npm-release-r48.mjs +5 -0
  41. package/scripts/npm-release-readiness-r163.mjs +67 -0
  42. package/scripts/r153-prepublish-identity.mjs +3 -3
  43. package/scripts/request-uac-migration-r153.ps1 +17 -4
  44. package/scripts/verify-protected-stage-r153.mjs +1 -0
  45. package/src/autonomous-supervisor.mjs +21 -4
  46. package/src/clean-activation-recovery-r153.mjs +1 -1
  47. package/src/deadbyte-cli.mjs +83 -60
  48. package/src/host-command-pins-r154.mjs +34 -0
  49. package/src/legacy-marker-evidence-r159.mjs +128 -0
  50. package/src/package-identity-r160.mjs +61 -0
  51. package/src/release-generation.mjs +13 -0
  52. package/src/release-slot.mjs +2 -1
  53. package/src/remote-live-log.mjs +30 -2
  54. package/src/runtime-update.mjs +18 -6
  55. package/src/trusted-epoch-bootstrap-r158.mjs +42 -0
  56. package/src/uac-approval-contract-r153.mjs +6 -3
  57. package/src/version.mjs +1 -1
  58. package/src/windows-powershell-environment.mjs +5 -2
  59. package/test/r106-trusted-powershell-spawn.test.mjs +1 -0
  60. package/test/r130-release-security-contract.test.mjs +9 -9
  61. package/test/r132-release-identity.test.mjs +8 -10
  62. package/test/r153-clean-activation-recovery.test.mjs +2 -2
  63. package/test/r153-prepublish-identity.test.mjs +26 -5
  64. package/test/r153-r65-signed-precondition-recovery.test.mjs +2 -2
  65. package/test/r153-staging-leaf-acl.test.mjs +24 -10
  66. package/test/r153-uac-approval-contract.test.mjs +5 -3
  67. package/test/r153-uac-launch-parameter-contract.test.mjs +1 -1
  68. package/test/r154-multipin-recovery.test.mjs +45 -0
  69. package/test/r155-commander-live-log.test.mjs +44 -0
  70. package/test/r155-default-live-log.test.mjs +89 -0
  71. package/test/r156-epoch-route-smoke.ps1 +48 -0
  72. package/test/r156-supervisor-pacing.test.mjs +59 -0
  73. package/test/r157-architecture-map.mjs +61 -0
  74. package/test/r157-reference-survey.mjs +91 -0
  75. package/test/r157-supervisor-singleflight.test.mjs +32 -0
  76. package/test/r158-epoch-bootstrap.test.mjs +34 -0
  77. package/test/r159-legacy-marker-evidence.test.mjs +100 -0
  78. package/test/r159-legacy-marker-evidence.test.mjs.before-assertion-fix-20261025-120246.bak +100 -0
  79. package/test/r160-marker-proof.test.mjs +87 -0
  80. package/test/r160-package-decision-manifest.test.mjs +67 -0
  81. package/test/r160-release-contract.test.mjs +30 -0
  82. package/test/r160-stable-launcher.test.mjs +10 -0
  83. package/test/r163-isolated-slot-rollback-restore.test.mjs +58 -0
  84. package/test/r163-publish-fence.test.mjs +13 -0
  85. package/test/r48-release-contract.test.mjs +7 -1
  86. package/test/r58-launcher-shell.test.mjs +4 -1
  87. package/test/r59-tool-surface-compat.test.mjs +1 -1
  88. package/test/release-generation.test.mjs +16 -0
  89. package/test/remote-live-log-r37.test.mjs +5 -3
  90. package/test/remote-session-cli.test.mjs +11 -11
  91. package/test/stabilization-state-root.test.mjs +2 -1
@@ -16,7 +16,7 @@ import { exportOfflineDiagnostics } from './r67-diagnostic-export.mjs';
16
16
  import { verifyOfflineDiagnosticsZip } from './r67-diagnostics-verify.mjs';
17
17
  import { parseActivePointer } from './release-slot.mjs';
18
18
  import { printDoctor } from './doctor-r45.mjs';
19
- import { classifyRemoteAuditOutcome, createLiveTimelineFilter, createLiveTimelineTracker, createLiveTimelineWriter, formatCompactAuditEvent, formatRemoteLifecycle, formatRemoteToolCall, formatRuntimeDiagnosticLine, selectLiveLogNames } from './remote-live-log.mjs';
19
+ import { classifyRemoteAuditOutcome, createLiveTimelineFilter, createLiveTimelineTracker, createLiveTimelineWriter, defaultForegroundTimelineOptions, formatRemoteLogResetNotice, formatCompactAuditEvent, formatRemoteLifecycle, formatRemoteToolCall, formatRuntimeDiagnosticLine, selectLiveLogNames } from './remote-live-log.mjs';
20
20
  import { prepareRemoteConsole, remoteDisplayText } from './remote-console.mjs';
21
21
  import { ensureRuntimeCoherence } from './runtime-coherence.mjs';
22
22
  import { windowsPowerShellEnvironment } from './runtime-update.mjs';
@@ -27,6 +27,9 @@ import {acquireForegroundSessionLock} from './foreground-session-lock.mjs';
27
27
  import { AUTHORITY_PLANES, authorityVector, authorityRestorePlan, parseAuthorityObservation, assertAuthorityVector, assertRuntimeReadyObservation, authorityBanner } from './remote-authority.mjs';
28
28
  import { decodeRemoteLogBytes, boundedRemoteDiagnostic, readRemoteLogAppend } from './remote-log-decode-r60.mjs';
29
29
  import {reconcileStaleMarker,resumeMarkerReconciliation,recoverPublishedMarkerTerminal} from './clean-activation-recovery-r153.mjs';
30
+ import {selectLegacyMarkerEvidence,verifyLocatedLegacyMarkerReceipt} from './legacy-marker-evidence-r159.mjs';
31
+ import {normalizeHostCommandPins,encodeHostCommandPins} from './host-command-pins-r154.mjs';
32
+ import {verifyPackageDecisionManifest} from './package-identity-r160.mjs';
30
33
 
31
34
  const REMOTE_COMMANDS=new Set([
32
35
  'menu','start','resume','park','stop','restart','status','url','test','fulltest','toggle','clean','machinetest',
@@ -62,6 +65,7 @@ function printHelp(){
62
65
  ` npx -y ${exact} remote --full # explicit five-plane foreground session`,
63
66
  ` npx -y ${exact} remote --resume <cursor> # replay missed results, then reconnect`,
64
67
  ` npx -y ${exact} remote --trace # show trace/span identity without payload detail`,
68
+
65
69
  ` npx -y ${exact} remote --filter <expr> # presentation filter: tool/category/status/trace`,
66
70
  ` npx -y ${exact} remote status`,
67
71
  ` npx -y ${exact} remote restart`,
@@ -114,7 +118,7 @@ async function reportVersionCoherence(root,{displayMode='ascii'}={}){
114
118
  writeRemote(process.stderr,`${remoteTag('warn',displayMode)} VERSION SKEW: CLI package ${DEADBYTE_VERSION}; active runtime ${active.version} (${active.release_id})\n`,displayMode);
115
119
  return active;
116
120
  }
117
- async function synchronizeForegroundRuntime(ctx,{displayMode='unicode',migrationContext=null,hostCommandPin=null}={}){
121
+ async function synchronizeForegroundRuntime(ctx,{displayMode='unicode',migrationContext=null,hostCommandPins=[]}={}){
118
122
  const packageManifestSha256=createHash('sha256').update(await readFile(path.join(CURRENT_PACKAGE_ROOT,'MANIFEST.SHA256'))).digest('hex');
119
123
  return ensureRuntimeCoherence({
120
124
  cliVersion:DEADBYTE_VERSION,
@@ -182,7 +186,7 @@ async function synchronizeForegroundRuntime(ctx,{displayMode='unicode',migration
182
186
  '-ExpectedBootstrapSha256',bootstrapMatch[1],
183
187
  '-StdoutPath',stdoutPath,'-StderrPath',stderrPath,
184
188
  '-MarkerReceiptPath',migrationContext.receipt_path,'-MarkerReceiptSha256',migrationContext.receipt_sha256,
185
- ...(hostCommandPin?['-HostCommandPin',hostCommandPin]:[])],{
189
+ ...(hostCommandPins.length?['-HostCommandPinsJson',encodeHostCommandPins(hostCommandPins)]:[])],{
186
190
  cwd:CURRENT_PACKAGE_ROOT,env:windowsPowerShellEnvironment(process.env),encoding:'utf8',windowsHide:true,shell:false,
187
191
  timeout:REMOTE_UPDATE_TIMEOUT_MS,maxBuffer:16*1024*1024
188
192
  });
@@ -395,7 +399,7 @@ function timelineFilterEvent(timeline){
395
399
  async function tailRemoteLogs(root,signal,{journal=null,offsets=null,activityTracker=null,timelineFilter=null,timelineWriter=null,verbose=false,displayMode='unicode'}={}){
396
400
  process.stdout.write(verbose
397
401
  ? '[LOG] Verbose live timeline. Full sanitized request detail enabled; Ctrl+C disconnects and revokes authority.\n'
398
- : '[LOG] Human live timeline. Transport IN/OUT hidden; full replay/audit detail remains on disk. START/DONE retained; heartbeat bursts folded; Ctrl+C disconnects and revokes authority.\n');
402
+ : '[LOG] Live tool calls with individual START/DONE, sanitized arguments and results. Transport hidden; signed audit remains on disk. Ctrl+C disconnects and revokes authority.\n');
399
403
  const activeOffsets=offsets??await snapshotRemoteLogOffsets(root);
400
404
  const partialLines=new Map();
401
405
  let liveFiles=[...activeOffsets.keys()];
@@ -412,7 +416,7 @@ async function tailRemoteLogs(root,signal,{journal=null,offsets=null,activityTra
412
416
  activeOffsets.set(file,next.cursor);
413
417
  if(next.reset){
414
418
  partialLines.delete(file);
415
- process.stderr.write('[LIVELOG] STREAM_RESET '+path.basename(file)+' — '+next.resetReason+'; check audit continuity before trusting coverage\n');
419
+ process.stderr.write(formatRemoteLogResetNotice(file,next.resetReason)+'\n');
416
420
  }
417
421
  if(!next.text)continue;
418
422
  const lines=((partialLines.get(file)??'')+next.text).split(/\r?\n/);
@@ -512,64 +516,79 @@ async function publishExclusiveJson(file,value){
512
516
  }
513
517
  return {path:file,sha256:createHash('sha256').update(bytes).digest('hex')};
514
518
  }
519
+ async function readMarkerRecoveryAuthority(ctx,active){
520
+ const grantField={process:'grant_file',coding:'lease_file',autonomous:'lease_file',desktop:'grant_file',host:'arm_file'};
521
+ const policySha256={},grantPresence={};
522
+ for(const plane of AUTHORITY_PLANES){
523
+ const policyFile=path.join(active.generation_root,`${plane}-policy.json`),info=await lstat(policyFile);
524
+ if(!info.isFile()||info.isSymbolicLink()||path.resolve(path.dirname(policyFile)).toLowerCase()!==path.resolve(active.generation_root).toLowerCase())
525
+ throw new Error(`marker reconciliation ${plane} policy identity invalid`);
526
+ const bytes=await readFile(policyFile),policy=JSON.parse(bytes.toString('utf8').replace(/^\uFEFF/,''));
527
+ policySha256[plane]=createHash('sha256').update(bytes).digest('hex');
528
+ const grant=policy?.[grantField[plane]];
529
+ if(typeof grant!=='string'||!path.isAbsolute(grant)||
530
+ path.resolve(path.dirname(grant)).toLowerCase()!==path.resolve(ctx.root,'runtime').toLowerCase())
531
+ throw new Error(`marker reconciliation ${plane} grant path invalid`);
532
+ try{await lstat(grant);grantPresence[plane]=true;}
533
+ catch(error){if(error?.code==='ENOENT')grantPresence[plane]=false;else throw error;}
534
+ }
535
+ return {policySha256,grantPresence};
536
+ }
515
537
  async function recoverRemoteSession(ctx,{displayMode='unicode'}={}){
516
538
  let prior=await readRemoteSessionMarker(ctx.root);
517
539
  const evidenceDir=path.join(ctx.root,'evidence','legacy-migration');
518
- const locatorPath=path.join(evidenceDir,'r153-pending-migration.json');
519
540
  if(!prior){
520
- try{
521
- const locator=JSON.parse(await readFile(locatorPath,'utf8'));
522
- if(locator?.schema!=='deadbyte.r153-pending-migration.v1'||
523
- typeof locator.receipt_path!=='string'||!path.isAbsolute(locator.receipt_path)||
524
- path.resolve(path.dirname(locator.receipt_path)).toLowerCase()!==path.resolve(evidenceDir).toLowerCase()||
525
- !/^[0-9a-f]{64}$/.test(String(locator.receipt_sha256??'')))throw new Error('pending migration locator invalid');
526
- const bytes=await readFile(locator.receipt_path);
527
- if(createHash('sha256').update(bytes).digest('hex')!==locator.receipt_sha256)
528
- throw new Error('pending migration receipt hash mismatch');
529
- return {state:'MARKER_RECONCILED',receipt_path:locator.receipt_path,
530
- receipt_sha256:locator.receipt_sha256};
531
- }catch(error){if(error?.code!=='ENOENT')throw error;}
541
+ const activePointer=await readActiveRuntimeBinding(ctx.root);
542
+ // A historical terminal is not an uncompleted migration. Ignore only
543
+ // when the installed release identity matches the CLI's manifest identity;
544
+ // this path grants no authority and publishes no recovery evidence.
545
+ const currentManifestSha256=createHash('sha256').update(
546
+ await readFile(path.join(CURRENT_PACKAGE_ROOT,'MANIFEST.SHA256'))).digest('hex');
547
+ const historyAllowed=activePointer?.version===DEADBYTE_VERSION&&
548
+ activePointer?.manifest_sha256===currentManifestSha256&&
549
+ activePointer?.release_id===('v'+DEADBYTE_VERSION+'-'+currentManifestSha256.slice(0,16));
550
+ const selected=await selectLegacyMarkerEvidence({evidenceDir,activePointer,
551
+ allowCompletedHistory:historyAllowed});
552
+ if(selected.kind==='none')return null;
553
+ if(selected.kind==='completed_history_ambiguous'){
554
+ if(!historyAllowed)throw new Error('R159 completed history cannot be reused across a release change');
555
+ // Nothing is pending: do not select an arbitrary completed receipt.
556
+ // A future upgrade still requires its own exact signed migration proof.
557
+ return null;
558
+ }
559
+ if(selected.kind==='located'){
560
+ const readback=await readActiveRuntimeBinding(ctx.root);
561
+ for(const key of ['release_id','version','manifest_sha256','generation_manifest_sha256'])
562
+ if(readback?.[key]!==activePointer?.[key])
563
+ throw new Error('R159 active release changed during located marker verification');
564
+ const {policySha256}=await readMarkerRecoveryAuthority(ctx,readback);
565
+ const verified=await verifyLocatedLegacyMarkerReceipt({located:selected,pointer:readback,policySha256});
566
+ const finalPointer=await readActiveRuntimeBinding(ctx.root);
567
+ for(const key of ['release_id','version','manifest_sha256','generation_manifest_sha256'])
568
+ if(finalPointer?.[key]!==readback?.[key])
569
+ throw new Error('R160 active release changed after located marker verification');
570
+ return verified;
571
+ }
572
+ // Completed historical receipts are not a pending migration for an
573
+ // already-online current release. Keep bytes and their SHA untouched.
574
+ if(selected.kind==='completed'&&observedAuthority(ctx).state==='ONLINE')return null;
575
+ if(selected.kind==='pending'&&observedAuthority(ctx).state!=='OFFLINE')
576
+ throw new Error('R159 pending marker reconciliation requires an offline runtime');
532
577
  // Crash recovery for the narrow window after marker CAS deletion and
533
578
  // before terminal receipt publication. Never infer completion from the
534
579
  // missing marker alone: require exactly one durable intent and re-observe
535
580
  // the full predecessor/policy/grant/runtime subject.
536
- let entries=[];
537
- try{entries=await readdir(evidenceDir,{withFileTypes:true});}
538
- catch(error){if(error?.code==='ENOENT')return null;throw error;}
539
- const candidates=[];
540
- for(const entry of entries){
541
- const match=/^marker-([0-9a-f]{64})\.intent\.json$/.exec(entry.name);
542
- if(!match||!entry.isFile())continue;
543
- const terminal=path.join(evidenceDir,`marker-${match[1]}.terminal.json`);
544
- let terminalExists=true;
545
- try{await lstat(terminal);}
546
- catch(error){if(error?.code==='ENOENT')terminalExists=false;else throw error;}
547
- candidates.push({markerSha256:match[1],intent:path.join(evidenceDir,entry.name),terminal,terminalExists});
548
- }
549
- if(candidates.length===0)return null;
550
- if(candidates.length!==1)throw new Error('multiple unlocated marker reconciliation claims; manual reconciliation required');
551
- const pending=candidates[0],intentInfo=await lstat(pending.intent);
581
+ const pending=selected.pending,intentInfo=await lstat(selected.pending.intent);
552
582
  if(!intentInfo.isFile()||intentInfo.isSymbolicLink())throw new Error('marker reconciliation intent is not a regular file');
553
583
  const intentBytes=await readFile(pending.intent),intent=JSON.parse(intentBytes.toString('utf8').replace(/^\uFEFF/,''));
554
584
  if(intent.marker_sha256!==pending.markerSha256)throw new Error('marker reconciliation intent filename identity mismatch');
555
585
  const active=await readActiveRuntimeBinding(ctx.root);
556
586
  if(!active)throw new Error('marker reconciliation predecessor pointer missing');
587
+ for(const key of ['release_id','version','manifest_sha256','generation_manifest_sha256'])
588
+ if(active[key]!==activePointer?.[key])
589
+ throw new Error('R159 active release changed during marker recovery');
557
590
  const observed=observedAuthority(ctx);
558
- const grantField={process:'grant_file',coding:'lease_file',autonomous:'lease_file',desktop:'grant_file',host:'arm_file'};
559
- const policySha256={},grantPresence={};
560
- for(const plane of AUTHORITY_PLANES){
561
- const policyFile=path.join(active.generation_root,`${plane}-policy.json`),info=await lstat(policyFile);
562
- if(!info.isFile()||info.isSymbolicLink()||path.resolve(path.dirname(policyFile)).toLowerCase()!==path.resolve(active.generation_root).toLowerCase())
563
- throw new Error(`marker reconciliation ${plane} policy identity invalid`);
564
- const bytes=await readFile(policyFile),policy=JSON.parse(bytes.toString('utf8').replace(/^\uFEFF/,''));
565
- policySha256[plane]=createHash('sha256').update(bytes).digest('hex');
566
- const grant=policy?.[grantField[plane]];
567
- if(typeof grant!=='string'||!path.isAbsolute(grant)||
568
- path.resolve(path.dirname(grant)).toLowerCase()!==path.resolve(ctx.root,'runtime').toLowerCase())
569
- throw new Error(`marker reconciliation ${plane} grant path invalid`);
570
- try{await lstat(grant);grantPresence[plane]=true;}
571
- catch(error){if(error?.code==='ENOENT')grantPresence[plane]=false;else throw error;}
572
- }
591
+ const {policySha256,grantPresence}=await readMarkerRecoveryAuthority(ctx,active);
573
592
  if(await readRemoteMarkerSnapshot(remoteSessionMarker(ctx.root))!==null)
574
593
  throw new Error('marker reconciliation marker reappeared');
575
594
  const intentSha256=createHash('sha256').update(intentBytes).digest('hex');
@@ -588,7 +607,7 @@ async function recoverRemoteSession(ctx,{displayMode='unicode'}={}){
588
607
  }
589
608
  const locator={schema:'deadbyte.r153-pending-migration.v1',receipt_path:pending.terminal,
590
609
  receipt_sha256:reconciled.receipt_sha256,marker_sha256:reconciled.marker_sha256};
591
- await publishExclusiveJson(locatorPath,locator);
610
+ await publishExclusiveJson(path.join(evidenceDir,'marker-'+reconciled.marker_sha256+'.locator.json'),locator);
592
611
  writeRemote(process.stdout,`${remoteTag('recovery',displayMode)} Interrupted marker reconciliation completed (${reconciled.marker_sha256.slice(0,12)}).\n`,displayMode);
593
612
  return {...reconciled,receipt_path:pending.terminal};
594
613
  }
@@ -691,7 +710,7 @@ async function recoverRemoteSession(ctx,{displayMode='unicode'}={}){
691
710
  deleteIfHash:async expected=>deletePinnedRemoteMarker(markerPath,expected)});
692
711
  const locator={schema:'deadbyte.r153-pending-migration.v1',receipt_path:terminalPath,
693
712
  receipt_sha256:reconciled.receipt_sha256,marker_sha256:reconciled.marker_sha256};
694
- await publishExclusiveJson(locatorPath,locator);
713
+ await publishExclusiveJson(path.join(evidenceDir,'marker-'+reconciled.marker_sha256+'.locator.json'),locator);
695
714
  writeRemote(process.stdout,`${remoteTag('recovery',displayMode)} Stale session evidence reconciled (${reconciled.marker_sha256.slice(0,12)}).\n`,displayMode);
696
715
  return {...reconciled,receipt_path:terminalPath};
697
716
  }
@@ -744,7 +763,7 @@ async function releaseRemoteSession(ctx,marker,{displayMode='unicode'}={}){
744
763
  if(deletePinnedRemoteMarker(remoteSessionMarker(ctx.root),snapshot.sha256)!=='REMOVED')
745
764
  throw new Error('remote session ownership marker replaced before native deletion; marker retained');
746
765
  }
747
- async function runRemoteSession({resumeCursor=null,verbose=false,trace=false,filterExpression='',mode='default',hostCommandPin=null}={}){
766
+ async function runRemoteSession({resumeCursor=null,verbose=false,trace=false,filterExpression='',mode='default',hostCommandPins=[]}={}){
748
767
  const display=prepareRemoteConsole();
749
768
  const displayMode=display.mode;
750
769
  const ctx=await remoteContext();
@@ -753,10 +772,12 @@ async function runRemoteSession({resumeCursor=null,verbose=false,trace=false,fil
753
772
  const startupLock=await acquireForegroundSessionLock({root:ctx.root,powershell:ctx.powershell});
754
773
  let marker;
755
774
  try{
775
+ startupLock.assertHeld();
776
+ await verifyPackageDecisionManifest({root:CURRENT_PACKAGE_ROOT,expectedVersion:DEADBYTE_VERSION});
756
777
  startupLock.assertHeld();
757
778
  const migrationContext=await recoverRemoteSession(ctx,{displayMode});
758
779
  startupLock.assertHeld();
759
- await synchronizeForegroundRuntime(ctx,{displayMode,migrationContext,hostCommandPin});
780
+ await synchronizeForegroundRuntime(ctx,{displayMode,migrationContext,hostCommandPins});
760
781
  startupLock.assertHeld();
761
782
  marker=await claimRemoteSession(ctx);
762
783
  startupLock.assertHeld();
@@ -765,7 +786,7 @@ async function runRemoteSession({resumeCursor=null,verbose=false,trace=false,fil
765
786
  filePath:remoteResultJournalPath(ctx.root,marker.result_session_id),sessionId:marker.result_session_id,maxEntries:2048
766
787
  });
767
788
  const rootPaths=await readLiveRootPaths(ctx.root);
768
- const activityTracker=createLiveTimelineTracker({verbose,displayMode,rootPaths,trace,foldHeartbeats:!verbose});
789
+ const activityTracker=createLiveTimelineTracker({verbose,displayMode,rootPaths,trace,...defaultForegroundTimelineOptions({verbose})});
769
790
  const timelineFilter=filterExpression?createLiveTimelineFilter(filterExpression):null;
770
791
  const timelineWriter=createLiveTimelineWriter({stream:process.stdout,displayMode,rewrite:false});
771
792
  const aborter=new AbortController();
@@ -869,17 +890,16 @@ async function runRemoteSession({resumeCursor=null,verbose=false,trace=false,fil
869
890
  }
870
891
  }
871
892
  async function runRemote(args){
872
- let verbose=false,trace=false,filterExpression='',resumeCursor=null,mode='default',hostCommandPin=null;
893
+ let verbose=false,trace=false,filterExpression='',resumeCursor=null,mode='default';
894
+ const hostCommandPinValues=[];
873
895
  const positional=[];
874
896
  for(let index=0;index<args.length;index++){
875
897
  const arg=args[index];
876
898
  if(arg==='--verbose'||arg==='-v'){verbose=true;continue;}
877
899
  if(arg==='--trace'){trace=true;continue;}
878
900
  if(arg==='--host-command-pin'){
879
- if(hostCommandPin!==null)throw new Error('remote --host-command-pin may be specified once');
880
901
  const value=String(args[++index]??'');
881
- if(!/^powershell_script=[0-9a-f]{64}$/.test(value))throw new Error('remote --host-command-pin requires powershell_script=lowercase_sha256');
882
- hostCommandPin=value;continue;
902
+ hostCommandPinValues.push(value);continue;
883
903
  }
884
904
  if(['--operator','--desktop','--host','--full'].includes(arg)){
885
905
  if(mode!=='default') throw new Error('remote authority modes are mutually exclusive');
@@ -897,8 +917,11 @@ async function runRemote(args){
897
917
  }
898
918
  positional.push(arg);
899
919
  }
900
- const presentation=verbose||trace||Boolean(filterExpression)||resumeCursor!==null||mode!=='default'||hostCommandPin!==null;
901
- if(positional.length===0){await runRemoteSession({resumeCursor,verbose,trace,filterExpression,mode,hostCommandPin});return;}
920
+ let hostCommandPins;
921
+ try{hostCommandPins=normalizeHostCommandPins(hostCommandPinValues);}
922
+ catch(error){throw new Error(`remote --host-command-pin ${error.message}`);}
923
+ const presentation=verbose||trace||Boolean(filterExpression)||resumeCursor!==null||mode!=='default'||hostCommandPins.length>0;
924
+ if(positional.length===0){await runRemoteSession({resumeCursor,verbose,trace,filterExpression,mode,hostCommandPins});return;}
902
925
  if(presentation) throw new Error('remote presentation flags are valid only for foreground session');
903
926
  if(positional.length>1) throw new Error('remote accepts one controller command');
904
927
  const command=positional[0];if(!REMOTE_COMMANDS.has(command)) throw new Error(`unsupported remote command '${command}'`);
@@ -0,0 +1,34 @@
1
+ const PIN=/^([A-Za-z0-9._-]{1,64})=([0-9a-f]{64})$/;
2
+ const LIMIT=16;
3
+ const REPINNABLE=new Set(['powershell_script','powershell_inline','cmd_script','cmd_inline','node_script','node_inline']);
4
+
5
+ export function normalizeHostCommandPins(values=[]){
6
+ if(!Array.isArray(values)||values.length>LIMIT)throw new Error(`host command pin limit is ${LIMIT}`);
7
+ const seen=new Set(),pins=[];
8
+ for(const value of values){
9
+ const match=PIN.exec(String(value??''));
10
+ if(!match)throw new Error('host command pin contract requires command_id=lowercase_sha256');
11
+ const [,command_id,sha256]=match;
12
+ if(!REPINNABLE.has(command_id))throw new Error(`host command '${command_id}' is not repinnable`);
13
+ if(seen.has(command_id))throw new Error(`duplicate host command pin '${command_id}'`);
14
+ seen.add(command_id);pins.push(Object.freeze({command_id,sha256}));
15
+ }
16
+ pins.sort((a,b)=>a.command_id<b.command_id?-1:a.command_id>b.command_id?1:0);
17
+ return Object.freeze(pins);
18
+ }
19
+
20
+ export function encodeHostCommandPins(pins=[]){
21
+ return JSON.stringify(normalizeHostCommandPins(pins.map(pin=>`${pin.command_id}=${pin.sha256}`))
22
+ .map(pin=>`${pin.command_id}=${pin.sha256}`));
23
+ }
24
+
25
+ export function decodeHostCommandPins(encoded='[]'){
26
+ let values;
27
+ try{values=JSON.parse(String(encoded));}catch{throw new Error('host command pins JSON invalid');}
28
+ return normalizeHostCommandPins(values);
29
+ }
30
+
31
+ export function hostCommandPinArgs(pins=[]){
32
+ return normalizeHostCommandPins(pins.map(pin=>`${pin.command_id}=${pin.sha256}`))
33
+ .flatMap(pin=>['--host-command-pin',`${pin.command_id}=${pin.sha256}`]);
34
+ }
@@ -0,0 +1,128 @@
1
+ import {readdir,lstat,readFile} from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import {createHash} from 'node:crypto';
4
+ import {verifyMarkerReconciliationReceipt} from './clean-activation-recovery-r153.mjs';
5
+
6
+ const H=/^[0-9a-f]{64}$/;
7
+ const digest=b=>createHash('sha256').update(b).digest('hex');
8
+ function samePredecessor(a,b){
9
+ return !!a&&!!b&&['release_id','version','manifest_sha256','generation_manifest_sha256']
10
+ .every(k=>typeof a[k]==='string'&&a[k]===b[k]);
11
+ }
12
+ async function regular(file){
13
+ const st=await lstat(file);
14
+ if(!st.isFile()||st.isSymbolicLink())throw new Error('R159 evidence file must be regular and not a link');
15
+ }
16
+ function strictJson(bytes,label){
17
+ let result;
18
+ try{result=JSON.parse(bytes.toString('utf8').replace(/^\uFEFF/,''));}
19
+ catch{throw new Error('R159 '+label+' invalid JSON');}
20
+ if(!result||typeof result!=='object'||Array.isArray(result))
21
+ throw new Error('R159 '+label+' invalid object');
22
+ return result;
23
+ }
24
+ // Examine ONLY local immutable receipt candidates. It must never infer a live
25
+ // process state, delete a marker, grant an authority plane, or mutate evidence.
26
+ export async function selectLegacyMarkerEvidence({evidenceDir,activePointer,allowCompletedHistory=false}){
27
+ if(typeof evidenceDir!=='string'||!path.isAbsolute(evidenceDir))
28
+ throw new Error('R159 evidence root must be absolute');
29
+ let entries;
30
+ try{entries=await readdir(evidenceDir,{withFileTypes:true});}
31
+ catch(e){if(e?.code==='ENOENT')return {kind:'none'};throw e;}
32
+ if(entries.length>4096)throw new Error('R159 evidence inventory exceeds bounded scan');
33
+ const fileSet=new Map(entries.map(e=>[e.name,e]));
34
+ const locatorPath=path.join(evidenceDir,'r153-pending-migration.json');
35
+ let located=null;
36
+ const locatorEntry=fileSet.get('r153-pending-migration.json');
37
+ if(locatorEntry){
38
+ if(!locatorEntry.isFile()||locatorEntry.isSymbolicLink())
39
+ throw new Error('R159 locator is not regular');
40
+ await regular(locatorPath);
41
+ const locator=strictJson(await readFile(locatorPath),'legacy locator');
42
+ if(locator.schema!=='deadbyte.r153-pending-migration.v1'||
43
+ !H.test(String(locator.marker_sha256??''))||
44
+ !H.test(String(locator.receipt_sha256??''))||
45
+ typeof locator.receipt_path!=='string')
46
+ throw new Error('R159 legacy locator schema invalid');
47
+ const expected=path.join(evidenceDir,'marker-'+locator.marker_sha256+'.terminal.json');
48
+ if(path.resolve(locator.receipt_path).toLowerCase()!==path.resolve(expected).toLowerCase())
49
+ throw new Error('R159 legacy locator receipt path mismatch');
50
+ await regular(expected);
51
+ const raw=await readFile(expected);
52
+ if(digest(raw)!==locator.receipt_sha256)
53
+ throw new Error('R159 legacy locator receipt hash mismatch');
54
+ const terminal=strictJson(raw,'located terminal');
55
+ if(terminal.schema!=='deadbyte.r153-marker-reconciliation.v1'||
56
+ terminal.state!=='MARKER_RECONCILED'||terminal.marker_sha256!==locator.marker_sha256)
57
+ throw new Error('R159 located terminal identity mismatch');
58
+ if(samePredecessor(terminal.predecessor,activePointer))
59
+ located={kind:'located',receiptPath:expected,receiptSha256:locator.receipt_sha256,
60
+ markerSha256:locator.marker_sha256};
61
+ }
62
+ const candidates=[];
63
+ for(const entry of entries){
64
+ const match=/^marker-([a-f0-9]{64})\.intent\.json$/.exec(entry.name);
65
+ if(!match)continue;
66
+ if(!entry.isFile()||entry.isSymbolicLink())throw new Error('R159 intent is not regular');
67
+ const intent=path.join(evidenceDir,entry.name);
68
+ await regular(intent);
69
+ const intentBytes=await readFile(intent),value=strictJson(intentBytes,'recovery intent');
70
+ if(value.schema!=='deadbyte.r153-marker-reconciliation-intent.v1'||
71
+ value.state!=='RECONCILIATION_CLAIMED'||value.marker_sha256!==match[1])
72
+ throw new Error('R159 intent filename/identity mismatch');
73
+ if(!samePredecessor(value.predecessor,activePointer))continue;
74
+ const terminal=path.join(evidenceDir,'marker-'+match[1]+'.terminal.json');
75
+ const terminalEntry=fileSet.get(path.basename(terminal));
76
+ let terminalExists=false;
77
+ if(terminalEntry){
78
+ if(!terminalEntry.isFile()||terminalEntry.isSymbolicLink())
79
+ throw new Error('R159 terminal is not regular');
80
+ await regular(terminal);
81
+ const parsed=strictJson(await readFile(terminal),'current terminal');
82
+ if(parsed.schema!=='deadbyte.r153-marker-reconciliation.v1'||
83
+ parsed.state!=='MARKER_RECONCILED'||parsed.marker_sha256!==match[1]||
84
+ parsed.intent_sha256!==digest(intentBytes)||
85
+ !samePredecessor(parsed.predecessor,activePointer))
86
+ throw new Error('R159 current terminal intent/subject mismatch');
87
+ terminalExists=true;
88
+ }
89
+ candidates.push({markerSha256:match[1],intent,terminal,terminalExists});
90
+ }
91
+ const pending=candidates.filter(c=>!c.terminalExists);
92
+ if(pending.length>1)throw new Error('R159 multiple matching pending reconciliation claims; manual reconciliation required');
93
+ if(pending.length===1)return {kind:'pending',pending:pending[0]};
94
+ if(located){
95
+ const other=candidates.filter(c=>c.markerSha256!==located.markerSha256);
96
+ if(other.length)throw new Error('R159 ambiguous multiple current reconciliation receipts');
97
+ return located;
98
+ }
99
+ const completed=candidates.filter(c=>c.terminalExists);
100
+ if(completed.length>1){
101
+ // Keep the original fail-closed default. A caller that independently
102
+ // verifies it is already running the exact installed release may choose
103
+ // not to reuse any fully completed receipts for a new startup.
104
+ if(allowCompletedHistory===true)
105
+ return {kind:'completed_history_ambiguous',count:completed.length};
106
+ throw new Error('R159 ambiguous multiple completed reconciliation receipts');
107
+ }
108
+ if(completed.length===1)return {kind:'completed',pending:completed[0]};
109
+ return {kind:'none'};
110
+ }
111
+
112
+ // Selection proves only that the locator and terminal bytes are internally
113
+ // consistent. Adoption is a separate boundary: reread the terminal and bind
114
+ // its R153 proof to the currently observed predecessor and policy generation.
115
+ export async function verifyLocatedLegacyMarkerReceipt({located,pointer,policySha256}){
116
+ if(located?.kind!=='located'||typeof located.receiptPath!=='string'||
117
+ !H.test(String(located.receiptSha256??''))||!H.test(String(located.markerSha256??'')))
118
+ throw new Error('R160 located receipt selection invalid');
119
+ await regular(located.receiptPath);
120
+ const raw=await readFile(located.receiptPath);
121
+ if(digest(raw)!==located.receiptSha256)
122
+ throw new Error('R160 located terminal changed after selection');
123
+ const terminal=strictJson(raw,'located terminal readback');
124
+ verifyMarkerReconciliationReceipt(terminal,{pointer,policySha256,
125
+ markerSha256:located.markerSha256});
126
+ return Object.freeze({...terminal,receipt_path:located.receiptPath,
127
+ receipt_sha256:located.receiptSha256});
128
+ }
@@ -0,0 +1,61 @@
1
+ import {createHash} from 'node:crypto';
2
+ import {lstat,readFile} from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import {parseManifest} from './release-slot.mjs';
5
+
6
+ const SEMVER=/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
7
+ const sha=bytes=>createHash('sha256').update(bytes).digest('hex');
8
+
9
+ export const R160_STARTUP_DECISION_FILES=Object.freeze([
10
+ 'package.json',
11
+ 'src/package-identity-r160.mjs',
12
+ 'src/deadbyte-cli.mjs',
13
+ 'src/legacy-marker-evidence-r159.mjs',
14
+ 'src/clean-activation-recovery-r153.mjs',
15
+ 'src/runtime-coherence.mjs',
16
+ 'src/runtime-update.mjs',
17
+ 'src/release-generation.mjs',
18
+ 'src/release-slot.mjs',
19
+ 'src/remote-authority.mjs',
20
+ 'src/foreground-session-lock.mjs',
21
+ 'src/foreground-marker-cas-win32.mjs',
22
+ 'src/windows-powershell-environment.mjs',
23
+ 'src/state-root.mjs'
24
+ ]);
25
+
26
+ async function regularUnder(root,rel){
27
+ const absolute=path.resolve(root,...rel.split('/'));
28
+ const boundary=path.relative(root,absolute);
29
+ if(boundary.startsWith(`..${path.sep}`)||path.isAbsolute(boundary))
30
+ throw new Error(`startup decision path escapes package: ${rel}`);
31
+ let cursor=path.resolve(root);
32
+ for(const part of rel.split('/')){
33
+ cursor=path.join(cursor,part);
34
+ const stat=await lstat(cursor);
35
+ if(stat.isSymbolicLink())throw new Error(`startup decision link forbidden: ${rel}`);
36
+ }
37
+ const stat=await lstat(absolute);
38
+ if(!stat.isFile())throw new Error(`startup decision file invalid: ${rel}`);
39
+ return absolute;
40
+ }
41
+
42
+ export async function verifyPackageDecisionManifest({root,expectedVersion}){
43
+ if(typeof root!=='string'||!path.isAbsolute(root))throw new Error('startup package root invalid');
44
+ if(!SEMVER.test(String(expectedVersion??'')))throw new Error('startup package version invalid');
45
+ const resolved=path.resolve(root),rootStat=await lstat(resolved);
46
+ if(!rootStat.isDirectory()||rootStat.isSymbolicLink())throw new Error('startup package root must be a real directory');
47
+ const manifestPath=await regularUnder(resolved,'MANIFEST.SHA256');
48
+ const manifestBytes=await readFile(manifestPath),manifest=parseManifest(manifestBytes.toString('utf8'));
49
+ for(const rel of R160_STARTUP_DECISION_FILES){
50
+ const expected=manifest.get(rel);
51
+ if(!expected)throw new Error(`startup decision manifest missing: ${rel}`);
52
+ const actual=sha(await readFile(await regularUnder(resolved,rel)));
53
+ if(actual!==expected)throw new Error(`startup decision file hash mismatch: ${rel}`);
54
+ }
55
+ const pkg=JSON.parse(await readFile(path.join(resolved,'package.json'),'utf8'));
56
+ if(pkg?.name!=='deadbyte-mcp'||pkg?.version!==expectedVersion)
57
+ throw new Error('startup package identity mismatch');
58
+ return Object.freeze({files:R160_STARTUP_DECISION_FILES.length,
59
+ manifest_sha256:sha(manifestBytes),version:expectedVersion});
60
+ }
61
+
@@ -185,6 +185,10 @@ function renderControllerConfig({currentConfig,coreRoot,workspaceRoot,processPol
185
185
  const supervisor=currentConfig.Supervisor??{},bridge=currentConfig.Bridge??{},cloud=currentConfig.Cloud??{};
186
186
  return [
187
187
  '@{'," Schema = 'deadbyte.controller.v1'",` CoreRoot = ${psQuote(coreRoot)}`,
188
+ // A pre-provisioned, OS-owned exact release copy; never auto-discover
189
+ // an unverified directory or grant authority while creating a generation.
190
+ ...(typeof currentConfig.AuthorityEpochRoot==='string'&&currentConfig.AuthorityEpochRoot.length>0
191
+ ?[` AuthorityEpochRoot = ${psQuote(currentConfig.AuthorityEpochRoot)}`]:[]),
188
192
  ` WorkspaceRoot = ${psQuote(workspaceRoot)}`,
189
193
  ` MachineRuntimeEnabled = ${psBool(currentConfig.MachineRuntimeEnabled!==false)}`,
190
194
  ` AgentRuntimeEnabled = ${psBool(currentConfig.AgentRuntimeEnabled)}`,
@@ -270,6 +274,13 @@ export async function createGenerationBundle({stateRoot,releaseRoot,developmentR
270
274
  }
271
275
  if(typeof currentConfig?.Bridge?.ScriptPath!=='string'||!path.isAbsolute(currentConfig.Bridge.ScriptPath)) throw new Error('generation Bridge ScriptPath must be absolute');
272
276
  if(typeof currentConfig?.Bridge?.ScriptSha256!=='string'||!HEX64.test(currentConfig.Bridge.ScriptSha256)) throw new Error('generation Bridge ScriptSha256 invalid');
277
+ // Legacy generations omit Epoch binding. Present values must be explicit
278
+ // Windows drive-absolute paths, never an implicit writable source.
279
+ const epochRoot=currentConfig.AuthorityEpochRoot;
280
+ if(epochRoot!==undefined&&(typeof epochRoot!=='string'||!/^[A-Za-z]:[\\/]/.test(epochRoot)||
281
+ !path.win32.isAbsolute(epochRoot)||epochRoot.includes('\0')||
282
+ path.win32.parse(epochRoot).root.toLowerCase()===path.win32.normalize(epochRoot).toLowerCase()))
283
+ throw new Error('generation AuthorityEpochRoot must be a Windows drive-absolute directory');
273
284
  const semanticSource=String(currentConfig.SemanticLspConfigFile??'');
274
285
  const semanticExpected=String(currentConfig.SemanticLspConfigSha256??'').toLowerCase();
275
286
  if(Boolean(semanticSource)!==Boolean(semanticExpected)) throw new Error('generation semantic LSP config path/SHA must be supplied together');
@@ -316,6 +327,8 @@ export async function createGenerationBundle({stateRoot,releaseRoot,developmentR
316
327
  mcp_url_file:currentConfig.McpUrlFile??'',mcp_url_file_sha256:currentConfig.McpUrlFileSha256??'',mcp_path_file:currentConfig.McpPathFile??'',
317
328
  start_timeout_seconds:Number(currentConfig.StartTimeoutSeconds??30),probe_timeout_seconds:Number(currentConfig.ProbeTimeoutSeconds??3),
318
329
  semantic_lsp_config_sha256:semanticConfigSha256,
330
+ // Changing a protected code origin changes this immutable generation.
331
+ ...(epochRoot!==undefined?{authority_epoch_root:epochRoot}:{}),
319
332
  process_policy_sha256:processBytes?sha256(processBytes):null,
320
333
  desktop_policy_sha256:desktopBytes?sha256(desktopBytes):null,
321
334
  coding_policy_sha256:sha256(codingBytes),autonomous_policy_sha256:sha256(autonomousBytes),host_policy_sha256:hostBytes?sha256(hostBytes):null
@@ -205,8 +205,9 @@ export function renderStableLauncherCmd(){
205
205
  return [
206
206
  '@echo off',
207
207
  'setlocal EnableExtensions DisableDelayedExpansion',
208
+ 'if not defined SystemRoot exit /b 1',
208
209
  'if not defined DEADBYTE_STATE_ROOT set "DEADBYTE_STATE_ROOT=%USERPROFILE%\\.deadbyte-mcp"',
209
- 'powershell.exe -NoLogo -NoProfile -ExecutionPolicy Bypass -File "%DEADBYTE_STATE_ROOT%\\bin\\DEADBYTE-MCP.ps1" %*',
210
+ '"%SystemRoot%\\System32\\WindowsPowerShell\\v1.0\\powershell.exe" -NoLogo -NoProfile -ExecutionPolicy Bypass -File "%DEADBYTE_STATE_ROOT%\\bin\\DEADBYTE-MCP.ps1" %*',
210
211
  'exit /b %ERRORLEVEL%',
211
212
  ''
212
213
  ].join('\r\n');
@@ -53,6 +53,15 @@ const TOOL_ICONS_ASCII=Object.freeze({read:'R',write:'W',edit:'E',run:'>',verify
53
53
  const START_VISIBLE_PATTERNS=[/(?:^|_)file_write$/,/text_replace$/,/symbol_replace$/,/native_diff_(?:apply|preview)$/,
54
54
  /(?:command|benchmark)_run$/,/task_run$/,/goal_run$/,/goal_submit$/,/goal_approve$/,/process_session_(?:start|action|terminate)$/,/^desktop_action$/];
55
55
 
56
+ export function formatRemoteLogResetNotice(file,reason){
57
+ const name=String(file).split(/[\\/]/).at(-1);
58
+ const rawReason=sanitizeAuditArgs(typeof reason==='string'?reason:'unknown');
59
+ const detail=typeof rawReason==='string'?clipped(rawReason,96):'[REDACTED]';
60
+ if(/^segment-\d{8}\.jsonl$/.test(name))
61
+ return '[LIVELOG] AUDIT_STREAM_RESET '+name+' — '+detail+'; verify signed audit continuity before trusting timeline coverage';
62
+ return '[LIVELOG] RUNTIME_LOG_REOPENED '+name+' — '+detail+'; console diagnostic continuity may have gaps; audit verification is separate';
63
+ }
64
+
56
65
  export function selectLiveLogNames({auditNames=[],runtimeNames=[]}={}){
57
66
  if(!Array.isArray(auditNames)||!Array.isArray(runtimeNames)) throw new Error('live log names must be arrays');
58
67
  const audit=[...new Set(auditNames.filter(name=>typeof name==='string'&&/^segment-\d{8}\.jsonl$/.test(name)))].sort().slice(-2);
@@ -388,13 +397,19 @@ export function createLiveTimelineWriter({stream=process.stdout,displayMode='uni
388
397
  retention(){return Object.freeze({congested,suppressed_since_drain:suppressedSinceDrain,total_suppressed:totalSuppressed});}});
389
398
  }
390
399
 
391
- export function createLiveTimelineTracker({clock=()=>Date.now(),verbose=false,foldHeartbeats=false,heartbeatBurstLimit=10,heartbeatWindowMs=3000,displayMode='unicode',rootPaths={},trace=false,slowCallMs=1000}={}){
400
+ export function defaultForegroundTimelineOptions({verbose=false}={}){
401
+ if(typeof verbose!=='boolean')throw new Error('default live timeline verbosity invalid');
402
+ return Object.freeze({commanderStyle:!verbose,foldHeartbeats:false});
403
+ }
404
+
405
+ export function createLiveTimelineTracker({clock=()=>Date.now(),verbose=false,foldHeartbeats=false,heartbeatBurstLimit=10,heartbeatWindowMs=3000,displayMode='unicode',rootPaths={},trace=false,slowCallMs=1000,commanderStyle=false}={}){
392
406
  if(typeof clock!=='function') throw new Error('live timeline clock must be a function');
393
407
  if(!REMOTE_DISPLAY_MODES.includes(displayMode)) throw new Error('remote display mode invalid');
394
408
  if(!Number.isInteger(heartbeatBurstLimit)||heartbeatBurstLimit<2||heartbeatBurstLimit>100) throw new Error('heartbeatBurstLimit invalid');
395
409
  if(!Number.isInteger(heartbeatWindowMs)||heartbeatWindowMs<250||heartbeatWindowMs>60000) throw new Error('heartbeatWindowMs invalid');
396
410
  if(!rootPaths||typeof rootPaths!=='object'||Array.isArray(rootPaths)) throw new Error('live timeline rootPaths invalid');
397
411
  if(typeof trace!=='boolean') throw new Error('live timeline trace invalid');
412
+ if(typeof commanderStyle!=='boolean') throw new Error('live timeline commanderStyle invalid');
398
413
  if(typeof foldHeartbeats!=='boolean') throw new Error('live timeline foldHeartbeats invalid');
399
414
  if(!Number.isInteger(slowCallMs)||slowCallMs<100||slowCallMs>600000) throw new Error('live timeline slowCallMs invalid');
400
415
  const pending=new Map();
@@ -443,6 +458,13 @@ export function createLiveTimelineTracker({clock=()=>Date.now(),verbose=false,fo
443
458
  const prefixIcon=unknown?(displayMode==='ascii'?'WARN':'⚠️'):null;
444
459
  const evidence=receipt?' '+(displayMode==='ascii'?'RECEIPT':'🧾 receipt')+(displayMode==='ascii'?'=':'=')+receipt:'';
445
460
  const reasonSep=displayMode==='ascii'?' - ':' — ';
461
+ if(commanderStyle){
462
+ const tag=unknown?'OUTCOME_UNKNOWN':pendingResult?'pending':error?'failed':'completed';
463
+ const state=rawStatus?' status='+rawStatus:'';
464
+ return remoteDisplayText('['+displayClock(eventMs(event,clock)).slice(0,8)+'] '+(unknown?'[WARN]':error?'[FAIL]':'[DONE]')+
465
+ ' Tool call '+displayTool+' '+tag+' ['+shortSpanId(event.request_id)+']'+traceSuffix(span?.trace_meta)+(duration?' '+duration:'')+state+
466
+ (reason?reasonSep+reason:'')+evidence,displayMode);
467
+ }
446
468
  return remoteDisplayText(eventPrefix(event,sequence,{displayTool,icon:prefixIcon})+traceSuffix(span?.trace_meta)+(summary?' '+summary:'')+(duration?' '+duration:'')+slow+' '+marker+statusDetail+evidence+(reason?reasonSep+reason:''),displayMode);
447
469
  }
448
470
  function burstLine(value){
@@ -497,6 +519,12 @@ export function createLiveTimelineTracker({clock=()=>Date.now(),verbose=false,fo
497
519
  }
498
520
  pending.set(requestId,{request_id:requestId,tool,display_tool:displayTool,summary,trace_meta:traceMeta,started_at_ms:clock()});
499
521
  peakInFlight=Math.max(peakInFlight,pending.size);
522
+ if(commanderStyle){
523
+ const safeArgs=sanitizeAuditArgs(args);
524
+ const visible=truncateUtf8(canonicalJson(safeArgs),768);
525
+ return remoteDisplayText('['+displayClock(eventMs(event,clock)).slice(0,8)+'] [CALL] Received tool call ['+
526
+ shortSpanId(requestId)+'] '+displayTool+traceSuffix(traceMeta)+' Arguments: '+visible,displayMode);
527
+ }
500
528
  if(verbose) return formatRemoteToolCall({...event,tool:displayTool},{clock,displayMode})+traceSuffix(traceMeta);
501
529
  if(visibleStart(displayTool)){
502
530
  const startMarker=displayMode==='ascii'?'START':'▶ START';
@@ -526,7 +554,7 @@ export function createLiveTimelineTracker({clock=()=>Date.now(),verbose=false,fo
526
554
  const snapshot=event.outcome?.snapshot_id,epoch=event.outcome?.state_epoch;
527
555
  if(/^[0-9a-f]{64}$/.test(String(snapshot??''))&&Number.isInteger(epoch)&&epoch>0){
528
556
  const identity=`${snapshot}:${epoch}`;
529
- if(identity===lastCapability){suppressedCapability++;return null;}
557
+ if(identity===lastCapability&&!commanderStyle){suppressedCapability++;return null;}
530
558
  lastCapability=identity;
531
559
  const prior=flushBurst();
532
560
  const line=resultLine(event,span,sequence)+` snapshot=${snapshot.slice(0,8)} epoch=${epoch}`;