deadbyte-mcp 0.15.61 → 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 (78) hide show
  1. package/MANIFEST.SHA256 +76 -31
  2. package/PROVENANCE.json +27 -8
  3. package/README.txt +18 -18
  4. package/RELEASE.json +44 -15
  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/gate-windows-r160.ps1 +57 -0
  37. package/scripts/npm-release-r48.mjs +5 -0
  38. package/scripts/npm-release-readiness-r163.mjs +67 -0
  39. package/src/autonomous-supervisor.mjs +21 -4
  40. package/src/deadbyte-cli.mjs +70 -50
  41. package/src/legacy-marker-evidence-r159.mjs +128 -0
  42. package/src/package-identity-r160.mjs +61 -0
  43. package/src/release-generation.mjs +13 -0
  44. package/src/release-slot.mjs +2 -1
  45. package/src/remote-live-log.mjs +30 -2
  46. package/src/runtime-update.mjs +18 -6
  47. package/src/trusted-epoch-bootstrap-r158.mjs +42 -0
  48. package/src/version.mjs +1 -1
  49. package/src/windows-powershell-environment.mjs +5 -2
  50. package/test/r106-trusted-powershell-spawn.test.mjs +1 -0
  51. package/test/r130-release-security-contract.test.mjs +9 -9
  52. package/test/r132-release-identity.test.mjs +8 -10
  53. package/test/r153-prepublish-identity.test.mjs +25 -4
  54. package/test/r153-staging-leaf-acl.test.mjs +5 -2
  55. package/test/r155-commander-live-log.test.mjs +44 -0
  56. package/test/r155-default-live-log.test.mjs +89 -0
  57. package/test/r156-epoch-route-smoke.ps1 +48 -0
  58. package/test/r156-supervisor-pacing.test.mjs +59 -0
  59. package/test/r157-architecture-map.mjs +61 -0
  60. package/test/r157-reference-survey.mjs +91 -0
  61. package/test/r157-supervisor-singleflight.test.mjs +32 -0
  62. package/test/r158-epoch-bootstrap.test.mjs +34 -0
  63. package/test/r159-legacy-marker-evidence.test.mjs +100 -0
  64. package/test/r159-legacy-marker-evidence.test.mjs.before-assertion-fix-20261025-120246.bak +100 -0
  65. package/test/r160-marker-proof.test.mjs +87 -0
  66. package/test/r160-package-decision-manifest.test.mjs +67 -0
  67. package/test/r160-release-contract.test.mjs +30 -0
  68. package/test/r160-stable-launcher.test.mjs +10 -0
  69. package/test/r163-isolated-slot-rollback-restore.test.mjs +58 -0
  70. package/test/r163-publish-fence.test.mjs +13 -0
  71. package/test/r48-release-contract.test.mjs +7 -1
  72. package/test/r58-launcher-shell.test.mjs +4 -1
  73. package/test/r59-tool-surface-compat.test.mjs +1 -1
  74. package/test/release-generation.test.mjs +16 -0
  75. package/test/remote-live-log-r37.test.mjs +5 -3
  76. package/test/remote-session-cli.test.mjs +11 -11
  77. package/test/stabilization-state-root.test.mjs +2 -1
  78. package/node_modules/which/CHANGELOG.md +0 -166
@@ -0,0 +1,67 @@
1
+ /** R163 0.15.62 publication fence. No evidence generation or authority mutation. */
2
+ import {createHash} from 'node:crypto';
3
+ import {readFile,lstat} from 'node:fs/promises';
4
+ import path from 'node:path';
5
+
6
+ const sha=b=>createHash('sha256').update(b).digest('hex');
7
+ const parent='v0.15.61-055d1ff0aa99e60b';
8
+ const parentManifest='055d1ff0aa99e60bbf9e9f136b02ebd4fffb8391712560f7607cff30af94dcdf';
9
+ const parentGen='f940e794daac2dda097a66301c4b85c4b29a2df7c669e549503c05a2a55ff6c4';
10
+ const reject=(m)=>{throw new Error('PUBLISH_BLOCKED R163 '+m);};
11
+ const hex=x=>typeof x==='string'&&/^[0-9a-f]{64}$/.test(x);
12
+ const readJson=async f=>JSON.parse(await readFile(f,'utf8'));
13
+ async function checkedEvidenceFile(file,digest,{allowEmpty=false}={}){
14
+ if(!hex(digest))reject('missing exact evidence digest');
15
+ const info=await lstat(file).catch(()=>reject('evidence file missing '+file));
16
+ if(!info.isFile()||info.isSymbolicLink()||(!allowEmpty&&info.size<1)||info.size>16*1024*1024)reject('invalid evidence file');
17
+ const bytes=await readFile(file);
18
+ if(sha(bytes)!==digest)reject('evidence SHA-256 mismatch '+file);
19
+ return bytes;
20
+ }
21
+ function boundedEvidence(root,relative){
22
+ if(typeof relative!=='string'||!relative||relative.includes('\\'))reject('invalid evidence relative path');
23
+ const p=path.resolve(root,relative),r=path.relative(root,p);
24
+ if(!r||r.startsWith('..')||path.isAbsolute(r))reject('evidence path escape');
25
+ return p;
26
+ }
27
+ export async function assertR163NpmPublishReady(release,{root,evidenceRoot=process.env.DEADBYTE_R163_CLOSURE_ROOT}={}){
28
+ if(release?.name!=='deadbyte-mcp'||release?.version!=='0.15.62'||release?.train!=='R160'||release?.r163?.publication_mode!=='PUBLISH_ONLY')reject('release metadata not R163-closed');
29
+ if(release?.parent?.release_id!==parent||release?.parent?.manifest_sha256!==parentManifest||release?.parent?.generation_manifest_sha256!==parentGen||release?.runtime_predecessor?.release_id!==parent)reject('active predecessor lineage mismatch');
30
+ if(!root||!path.isAbsolute(root))reject('candidate root missing');
31
+ if(!evidenceRoot||!path.isAbsolute(evidenceRoot))reject('closure evidence path missing');
32
+ const testRoot=path.resolve(root,'..','..','testing','r163-release-closure');
33
+ const evidence=path.resolve(evidenceRoot);
34
+ const relative=path.relative(testRoot,evidence);
35
+ if(!relative||relative.startsWith('..')||path.isAbsolute(relative))reject('evidence outside bounded R163 testing root');
36
+ for(const p of [testRoot,evidence]){const st=await lstat(p).catch(()=>reject('evidence directory absent'));if(!st.isDirectory()||st.isSymbolicLink())reject('evidence directory is reparse/symlink');}
37
+ const closurePath=path.join(evidence,'closure.json');
38
+ const closureInfo=await lstat(closurePath).catch(()=>reject('closure missing'));
39
+ if(!closureInfo.isFile()||closureInfo.isSymbolicLink()||closureInfo.size<1||closureInfo.size>1024*1024)reject('closure file not regular/bounded');
40
+ const closure=await readJson(closurePath).catch(()=>reject('closure missing/invalid'));
41
+ if(closure?.schema!=='deadbyte.r163-release-closure.v1'||closure?.version!=='0.15.62'||closure?.status!=='PASS'||closure?.production_release_id!==parent)reject('closure subject/status mismatch');
42
+ const manifestSha=sha(await readFile(path.join(root,'MANIFEST.SHA256')));
43
+ if(closure.source_manifest_sha256!==manifestSha)reject('final manifest differs from closure');
44
+ const files=closure?.files;
45
+ if(!files||!['protected_receipt','protected_stdout','protected_stderr','verify_receipt','verify_stdout','verify_stderr'].every(k=>files[k]&&typeof files[k].path==='string'&&hex(files[k].sha256)))reject('required receipts missing');
46
+ const data={};
47
+ for(const [key,info] of Object.entries(files)) data[key]=await checkedEvidenceFile(boundedEvidence(testRoot,info.path),info.sha256,{allowEmpty:key.endsWith('_stderr')});
48
+ let protectedReceipt,verifyReceipt;
49
+ try{protectedReceipt=JSON.parse(data.protected_receipt);verifyReceipt=JSON.parse(data.verify_receipt);}
50
+ catch{reject('gate receipts invalid JSON');}
51
+ if(protectedReceipt?.schema!=='deadbyte.r163-protected-windows-gate.v1'||protectedReceipt?.stage!=='full'||protectedReceipt?.exit_code!==0||protectedReceipt?.source_manifest_sha256!==manifestSha||protectedReceipt?.active_release_id!==parent)reject('protected gate missing or unbound');
52
+ if(protectedReceipt.stdout_sha256!==sha(data.protected_stdout)||protectedReceipt.stderr_sha256!==sha(data.protected_stderr))reject('protected log mismatch');
53
+ const stdout=data.protected_stdout.toString('utf8');
54
+ const counts=Object.fromEntries(['tests','pass','fail','skipped'].map(k=>[k,Number(new RegExp('^# '+k+' (\\d+)\\s*$','m').exec(stdout)?.[1]??NaN)]));
55
+ if(counts.tests<1951||counts.pass<1902||counts.fail!==0||counts.skipped!==49||counts.pass+counts.skipped!==counts.tests||/^not ok\s+\d+/m.test(stdout))reject('full regression totals mismatch');
56
+ if(!/^ok\s+\d+\s+-\s+R163 isolated immutable slot activates, rolls back, and restores 0\.15\.62/m.test(stdout))reject('R163 live rollback proof missing');
57
+ const skips=stdout.split(/\r?\n/).filter(x=>/^ok\s+\d+\s+-.*# SKIP/.test(x));
58
+ if(skips.length!==49||skips.some(x=>!/historical|R35 external semantic backend|POSIX|R100 POSIX/i.test(x)))reject('unexpected unclassified skipped test');
59
+ if(verifyReceipt?.schema!=='deadbyte.r163-release-verify.v1'||verifyReceipt?.status!=='PASS'||verifyReceipt?.version!=='0.15.62'||verifyReceipt?.source_manifest_sha256!==manifestSha||verifyReceipt?.production_release_id!==parent||verifyReceipt?.exit_code!==0)reject('verify-only receipt subject/status mismatch');
60
+ if(verifyReceipt.stdout_sha256!==sha(data.verify_stdout)||verifyReceipt.stderr_sha256!==sha(data.verify_stderr))reject('verify-only transcript hash mismatch');
61
+ const vout=data.verify_stdout.toString('utf8');
62
+ if(!vout.includes('VERIFY-ONLY PIPELINE PASS')||!vout.includes('Artifact isolation gate PASS')||!vout.includes('VERIFIED_TARBALL '))reject('npm verify-only output missing');
63
+ const tarLine=vout.split(/\r?\n/).find(x=>x.startsWith('VERIFIED_TARBALL '));
64
+ try{const p=JSON.parse(tarLine.slice('VERIFIED_TARBALL '.length));if(p.filename!=='deadbyte-mcp-0.15.62.tgz'||!hex(p.sha256)||p.bytes<1)reject('npm tarball identity invalid');}
65
+ catch{reject('npm tarball evidence invalid');}
66
+ return Object.freeze({status:'R163_RELEASE_READY_EVIDENCE_BOUND',version:'0.15.62',manifest_sha256:manifestSha,checks:6});
67
+ }
@@ -24,7 +24,7 @@ async function listGoalIds(policy) {
24
24
  export function startAutonomousSupervisor({ runtime, policy = runtime?.policy,
25
25
  idleDelayMs = 750, maxCycles = 32, logger = console, continuous = true } = {}) {
26
26
  if (!runtime || !policy) throw new Error('autonomous supervisor requires runtime + policy');
27
- const providerBacked = ['openai_compatible','openai_responses'].includes(policy.planner.backend);
27
+ const providerBacked = ['openai_compatible','openai_responses','codex_app_server'].includes(policy.planner.backend);
28
28
  if (!Number.isInteger(idleDelayMs) || idleDelayMs < 25 || idleDelayMs > 60_000) {
29
29
  throw new Error('autonomous supervisor idleDelayMs out of range');
30
30
  }
@@ -41,6 +41,10 @@ export function startAutonomousSupervisor({ runtime, policy = runtime?.policy,
41
41
  let runnable = 0;
42
42
  for (const goalId of await listGoalIds(policy)) {
43
43
  if (abort.signal.aborted) break;
44
+ // A known retry deadline is authoritative until elapsed. Avoid
45
+ // polling goal state again just to rediscover the same backoff.
46
+ const pendingRetry=failures.get(goalId);
47
+ if (pendingRetry && Date.now() < pendingRetry.retry_at) continue;
44
48
  let status;
45
49
  try { status = await runtime.status({ goalId }); }
46
50
  catch (error) { logger.warn?.(`DEADBYTE supervisor status ${goalId}: ${String(error)}`); continue; }
@@ -61,9 +65,10 @@ export function startAutonomousSupervisor({ runtime, policy = runtime?.policy,
61
65
  failures.delete(goalId); continue;
62
66
  }
63
67
  }
64
- runnable += 1;
65
68
  const failure = failures.get(goalId);
66
69
  if (failure && Date.now() < failure.retry_at) continue;
70
+ // Only an eligible dispatch is runnable. Backoff is not useful work.
71
+ runnable += 1;
67
72
  try {
68
73
  const result = await runtime.run({ goalId, maxCycles });
69
74
  if (result.status === 'paused' && result.reason === 'provider_circuit_open') {
@@ -89,10 +94,22 @@ export function startAutonomousSupervisor({ runtime, policy = runtime?.policy,
89
94
  return runnable;
90
95
  }
91
96
 
97
+ // One supervisor, one in-flight scan. A manual scan and the polling
98
+ // loop must never race to dispatch the same durable goal.
99
+ let inFlightPass=null;
100
+ function scanOnce(){
101
+ if(inFlightPass)return inFlightPass;
102
+ const task=pass();
103
+ inFlightPass=task;
104
+ const clear=()=>{if(inFlightPass===task)inFlightPass=null;};
105
+ task.then(clear,clear);
106
+ return task;
107
+ }
108
+
92
109
  const done = continuous ? (async () => {
93
110
  while (!abort.signal.aborted) {
94
111
  let runnable = 0;
95
- try { runnable = await pass(); }
112
+ try { runnable = await scanOnce(); }
96
113
  catch (error) { logger.error?.(`DEADBYTE supervisor scan failed: ${String(error)}`); }
97
114
  if (abort.signal.aborted) break;
98
115
  await delay(runnable > 0 ? 25 : idleDelayMs, abort.signal);
@@ -103,7 +120,7 @@ export function startAutonomousSupervisor({ runtime, policy = runtime?.policy,
103
120
  get running() { return !abort.signal.aborted; },
104
121
  get passes() { return passes; },
105
122
  failures,
106
- async scanNow() { return pass(); },
123
+ async scanNow() { return scanOnce(); },
107
124
  async stop() { abort.abort(); await done; }
108
125
  });
109
126
  }
@@ -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,7 +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';
30
31
  import {normalizeHostCommandPins,encodeHostCommandPins} from './host-command-pins-r154.mjs';
32
+ import {verifyPackageDecisionManifest} from './package-identity-r160.mjs';
31
33
 
32
34
  const REMOTE_COMMANDS=new Set([
33
35
  'menu','start','resume','park','stop','restart','status','url','test','fulltest','toggle','clean','machinetest',
@@ -63,6 +65,7 @@ function printHelp(){
63
65
  ` npx -y ${exact} remote --full # explicit five-plane foreground session`,
64
66
  ` npx -y ${exact} remote --resume <cursor> # replay missed results, then reconnect`,
65
67
  ` npx -y ${exact} remote --trace # show trace/span identity without payload detail`,
68
+
66
69
  ` npx -y ${exact} remote --filter <expr> # presentation filter: tool/category/status/trace`,
67
70
  ` npx -y ${exact} remote status`,
68
71
  ` npx -y ${exact} remote restart`,
@@ -396,7 +399,7 @@ function timelineFilterEvent(timeline){
396
399
  async function tailRemoteLogs(root,signal,{journal=null,offsets=null,activityTracker=null,timelineFilter=null,timelineWriter=null,verbose=false,displayMode='unicode'}={}){
397
400
  process.stdout.write(verbose
398
401
  ? '[LOG] Verbose live timeline. Full sanitized request detail enabled; Ctrl+C disconnects and revokes authority.\n'
399
- : '[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');
400
403
  const activeOffsets=offsets??await snapshotRemoteLogOffsets(root);
401
404
  const partialLines=new Map();
402
405
  let liveFiles=[...activeOffsets.keys()];
@@ -413,7 +416,7 @@ async function tailRemoteLogs(root,signal,{journal=null,offsets=null,activityTra
413
416
  activeOffsets.set(file,next.cursor);
414
417
  if(next.reset){
415
418
  partialLines.delete(file);
416
- 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');
417
420
  }
418
421
  if(!next.text)continue;
419
422
  const lines=((partialLines.get(file)??'')+next.text).split(/\r?\n/);
@@ -513,64 +516,79 @@ async function publishExclusiveJson(file,value){
513
516
  }
514
517
  return {path:file,sha256:createHash('sha256').update(bytes).digest('hex')};
515
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
+ }
516
537
  async function recoverRemoteSession(ctx,{displayMode='unicode'}={}){
517
538
  let prior=await readRemoteSessionMarker(ctx.root);
518
539
  const evidenceDir=path.join(ctx.root,'evidence','legacy-migration');
519
- const locatorPath=path.join(evidenceDir,'r153-pending-migration.json');
520
540
  if(!prior){
521
- try{
522
- const locator=JSON.parse(await readFile(locatorPath,'utf8'));
523
- if(locator?.schema!=='deadbyte.r153-pending-migration.v1'||
524
- typeof locator.receipt_path!=='string'||!path.isAbsolute(locator.receipt_path)||
525
- path.resolve(path.dirname(locator.receipt_path)).toLowerCase()!==path.resolve(evidenceDir).toLowerCase()||
526
- !/^[0-9a-f]{64}$/.test(String(locator.receipt_sha256??'')))throw new Error('pending migration locator invalid');
527
- const bytes=await readFile(locator.receipt_path);
528
- if(createHash('sha256').update(bytes).digest('hex')!==locator.receipt_sha256)
529
- throw new Error('pending migration receipt hash mismatch');
530
- return {state:'MARKER_RECONCILED',receipt_path:locator.receipt_path,
531
- receipt_sha256:locator.receipt_sha256};
532
- }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');
533
577
  // Crash recovery for the narrow window after marker CAS deletion and
534
578
  // before terminal receipt publication. Never infer completion from the
535
579
  // missing marker alone: require exactly one durable intent and re-observe
536
580
  // the full predecessor/policy/grant/runtime subject.
537
- let entries=[];
538
- try{entries=await readdir(evidenceDir,{withFileTypes:true});}
539
- catch(error){if(error?.code==='ENOENT')return null;throw error;}
540
- const candidates=[];
541
- for(const entry of entries){
542
- const match=/^marker-([0-9a-f]{64})\.intent\.json$/.exec(entry.name);
543
- if(!match||!entry.isFile())continue;
544
- const terminal=path.join(evidenceDir,`marker-${match[1]}.terminal.json`);
545
- let terminalExists=true;
546
- try{await lstat(terminal);}
547
- catch(error){if(error?.code==='ENOENT')terminalExists=false;else throw error;}
548
- candidates.push({markerSha256:match[1],intent:path.join(evidenceDir,entry.name),terminal,terminalExists});
549
- }
550
- if(candidates.length===0)return null;
551
- if(candidates.length!==1)throw new Error('multiple unlocated marker reconciliation claims; manual reconciliation required');
552
- const pending=candidates[0],intentInfo=await lstat(pending.intent);
581
+ const pending=selected.pending,intentInfo=await lstat(selected.pending.intent);
553
582
  if(!intentInfo.isFile()||intentInfo.isSymbolicLink())throw new Error('marker reconciliation intent is not a regular file');
554
583
  const intentBytes=await readFile(pending.intent),intent=JSON.parse(intentBytes.toString('utf8').replace(/^\uFEFF/,''));
555
584
  if(intent.marker_sha256!==pending.markerSha256)throw new Error('marker reconciliation intent filename identity mismatch');
556
585
  const active=await readActiveRuntimeBinding(ctx.root);
557
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');
558
590
  const observed=observedAuthority(ctx);
559
- const grantField={process:'grant_file',coding:'lease_file',autonomous:'lease_file',desktop:'grant_file',host:'arm_file'};
560
- const policySha256={},grantPresence={};
561
- for(const plane of AUTHORITY_PLANES){
562
- const policyFile=path.join(active.generation_root,`${plane}-policy.json`),info=await lstat(policyFile);
563
- if(!info.isFile()||info.isSymbolicLink()||path.resolve(path.dirname(policyFile)).toLowerCase()!==path.resolve(active.generation_root).toLowerCase())
564
- throw new Error(`marker reconciliation ${plane} policy identity invalid`);
565
- const bytes=await readFile(policyFile),policy=JSON.parse(bytes.toString('utf8').replace(/^\uFEFF/,''));
566
- policySha256[plane]=createHash('sha256').update(bytes).digest('hex');
567
- const grant=policy?.[grantField[plane]];
568
- if(typeof grant!=='string'||!path.isAbsolute(grant)||
569
- path.resolve(path.dirname(grant)).toLowerCase()!==path.resolve(ctx.root,'runtime').toLowerCase())
570
- throw new Error(`marker reconciliation ${plane} grant path invalid`);
571
- try{await lstat(grant);grantPresence[plane]=true;}
572
- catch(error){if(error?.code==='ENOENT')grantPresence[plane]=false;else throw error;}
573
- }
591
+ const {policySha256,grantPresence}=await readMarkerRecoveryAuthority(ctx,active);
574
592
  if(await readRemoteMarkerSnapshot(remoteSessionMarker(ctx.root))!==null)
575
593
  throw new Error('marker reconciliation marker reappeared');
576
594
  const intentSha256=createHash('sha256').update(intentBytes).digest('hex');
@@ -589,7 +607,7 @@ async function recoverRemoteSession(ctx,{displayMode='unicode'}={}){
589
607
  }
590
608
  const locator={schema:'deadbyte.r153-pending-migration.v1',receipt_path:pending.terminal,
591
609
  receipt_sha256:reconciled.receipt_sha256,marker_sha256:reconciled.marker_sha256};
592
- await publishExclusiveJson(locatorPath,locator);
610
+ await publishExclusiveJson(path.join(evidenceDir,'marker-'+reconciled.marker_sha256+'.locator.json'),locator);
593
611
  writeRemote(process.stdout,`${remoteTag('recovery',displayMode)} Interrupted marker reconciliation completed (${reconciled.marker_sha256.slice(0,12)}).\n`,displayMode);
594
612
  return {...reconciled,receipt_path:pending.terminal};
595
613
  }
@@ -692,7 +710,7 @@ async function recoverRemoteSession(ctx,{displayMode='unicode'}={}){
692
710
  deleteIfHash:async expected=>deletePinnedRemoteMarker(markerPath,expected)});
693
711
  const locator={schema:'deadbyte.r153-pending-migration.v1',receipt_path:terminalPath,
694
712
  receipt_sha256:reconciled.receipt_sha256,marker_sha256:reconciled.marker_sha256};
695
- await publishExclusiveJson(locatorPath,locator);
713
+ await publishExclusiveJson(path.join(evidenceDir,'marker-'+reconciled.marker_sha256+'.locator.json'),locator);
696
714
  writeRemote(process.stdout,`${remoteTag('recovery',displayMode)} Stale session evidence reconciled (${reconciled.marker_sha256.slice(0,12)}).\n`,displayMode);
697
715
  return {...reconciled,receipt_path:terminalPath};
698
716
  }
@@ -754,6 +772,8 @@ async function runRemoteSession({resumeCursor=null,verbose=false,trace=false,fil
754
772
  const startupLock=await acquireForegroundSessionLock({root:ctx.root,powershell:ctx.powershell});
755
773
  let marker;
756
774
  try{
775
+ startupLock.assertHeld();
776
+ await verifyPackageDecisionManifest({root:CURRENT_PACKAGE_ROOT,expectedVersion:DEADBYTE_VERSION});
757
777
  startupLock.assertHeld();
758
778
  const migrationContext=await recoverRemoteSession(ctx,{displayMode});
759
779
  startupLock.assertHeld();
@@ -766,7 +786,7 @@ async function runRemoteSession({resumeCursor=null,verbose=false,trace=false,fil
766
786
  filePath:remoteResultJournalPath(ctx.root,marker.result_session_id),sessionId:marker.result_session_id,maxEntries:2048
767
787
  });
768
788
  const rootPaths=await readLiveRootPaths(ctx.root);
769
- const activityTracker=createLiveTimelineTracker({verbose,displayMode,rootPaths,trace,foldHeartbeats:!verbose});
789
+ const activityTracker=createLiveTimelineTracker({verbose,displayMode,rootPaths,trace,...defaultForegroundTimelineOptions({verbose})});
770
790
  const timelineFilter=filterExpression?createLiveTimelineFilter(filterExpression):null;
771
791
  const timelineWriter=createLiveTimelineWriter({stream:process.stdout,displayMode,rewrite:false});
772
792
  const aborter=new AbortController();
@@ -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');