deadbyte-mcp 0.15.43 → 0.15.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MANIFEST.SHA256 +160 -161
- package/PROVENANCE.json +257 -232
- package/README.txt +18 -18
- package/RELEASE.json +348 -320
- package/SBOM.cdx.json +14 -2
- package/TEST-MATRIX.json +503 -460
- package/bin/deadbyte-native-inspect-r67.exe +0 -0
- package/bridge/package.json +1 -1
- package/controller/deadbyte-controller.ps1 +1857 -1769
- package/controller/deadbyte-desktop-policy.json +6 -6
- package/controller/deadbyte-process-policy.json +4 -4
- package/docs/R67-ALPHA-REFERENCE-DIFFERENTIAL.md +42 -0
- package/docs/R67-ALPHA-STATIC-COMPARISON.json +205 -0
- package/docs/R67-CANDIDATE-PARENT.json +10 -0
- package/docs/R67-EVIDENCE-RECONCILE-CLOSEOUT-20261011.md +64 -0
- package/docs/R67-FULL-REGRESSION-UNKNOWN.json +27 -0
- package/docs/R67-NATIVE-INSPECT-BINARY.json +11 -0
- package/docs/R67-NPM-EXDEV-PRESERVATION-20261011.md +39 -0
- package/docs/R67-OBSERVATION-TRUTH.md +82 -0
- package/docs/R67-REFERENCE-GAP-MATRIX.json +57 -0
- package/docs/R67-REGRESSION-CLOSURE-20261011.md +24 -0
- package/docs/R68-COMPAT-HOST-EXEC-CANDIDATE.md +63 -0
- package/docs/R69-LIVE-OUTCOME-R70-POLICY-TRANSFER.md +136 -0
- package/docs/R70-CODING-DIGEST-SUPERVISOR-CHECKPOINT-20261013.md +42 -0
- package/docs/R70-FINITE-GRANT-OWNER-BOUNDARY-20261013.md +80 -0
- package/docs/R70-OWNER-BOOTSTRAP-CHECKPOINT-20261013.md +60 -0
- package/docs/R70-REFERENCE-MECHANISMS.json +95 -0
- package/docs/R70-TRUST-GUARD-EXPIRY-CHECKPOINT-20261013.md +47 -0
- package/native/deadbyte-native-inspect-r67.cpp +252 -0
- package/package.json +6 -3
- package/scripts/benchmark-l0-r71.mjs +76 -0
- package/scripts/build-native-inspector-r67.ps1 +28 -0
- package/scripts/gate-windows-r67.ps1 +56 -0
- package/scripts/gate-windows-r71.ps1 +64 -0
- package/scripts/npm-preserve-artifact-r67.mjs +99 -0
- package/scripts/npm-release-r48.mjs +12 -2
- package/scripts/npm-release-readiness-r67.mjs +26 -0
- package/scripts/npm-release-readiness-r71.mjs +21 -0
- package/scripts/r67-acquire-alpha-reference.mjs +95 -0
- package/scripts/r67-audit-nonpass-source.mjs +39 -0
- package/scripts/r67-compare-desktop-alpha.mjs +48 -0
- package/scripts/r67-diagnose-failed-shard.mjs +23 -0
- package/scripts/r67-durable-batch.mjs +42 -0
- package/scripts/r67-focused-gate.mjs +58 -0
- package/scripts/r67-full-regression.mjs +28 -0
- package/scripts/r67-independent-observation-verify.mjs +36 -0
- package/scripts/r67-independent-runtime-observation-verify.mjs +63 -0
- package/scripts/r67-nonpass-adjudicate.mjs +20 -0
- package/scripts/r67-publish-boundary-audit.mjs +32 -0
- package/scripts/r67-regression-reconcile.mjs +10 -0
- package/scripts/r67-regression-shard-run.mjs +70 -0
- package/scripts/r67-run-shard-batch.mjs +18 -0
- package/scripts/r67-stage-candidate.mjs +30 -0
- package/scripts/r67-verify-parent-ping.mjs +22 -0
- package/scripts/release-manifest.mjs +1 -0
- package/scripts/verify-r70-full-regression.ps1 +72 -0
- package/src/activation-continuity-engine-r65.mjs +2 -1
- package/src/authority-continuity-r65.mjs +28 -8
- package/src/autonomous-mcp-tools.mjs +1 -1
- package/src/autonomous-output-contracts.mjs +4 -1
- package/src/autonomous-policy.mjs +54 -7
- package/src/autonomous-runtime.mjs +1 -1
- package/src/capability-ledger.mjs +1 -1
- package/src/capability-resolver.mjs +2 -1
- package/src/commander-compat-runtime.mjs +30 -2
- package/src/deadbyte-cli.mjs +41 -7
- package/src/machine-fs-smoke-client.mjs +13 -5
- package/src/machine-identity.mjs +59 -2
- package/src/machine-mcp-tools.mjs +8 -0
- package/src/mcp-server.mjs +11 -2
- package/src/native-diff-v2.mjs +18 -5
- package/src/native-diff.mjs +21 -5
- package/src/native-inspector-r67.mjs +66 -0
- package/src/r67-diagnostic-export.mjs +118 -0
- package/src/r67-diagnostics-verify.mjs +82 -0
- package/src/r67-evidence-reconcile.mjs +128 -0
- package/src/r67-native-observation-authority.mjs +45 -0
- package/src/r67-observation-receipt.mjs +43 -0
- package/src/r67-regression-shards.mjs +176 -0
- package/src/r70-owner-approval.mjs +78 -0
- package/src/remote-live-log.mjs +62 -24
- package/src/remote-result-journal.mjs +1 -1
- package/src/runtime-update.mjs +2051 -1891
- package/src/tool-audit.mjs +3 -1
- package/src/version.mjs +1 -1
- package/test/agent-runtime.test.mjs +1 -1
- package/test/autonomous-local-supervisor.test.mjs +2 -1
- package/test/autonomous-loop.test.mjs +11 -6
- package/test/autonomous-output-contract.test.mjs +17 -1
- package/test/autonomous-runtime.test.mjs +1 -1
- package/test/autonomous-supervisor-integration.test.mjs +2 -1
- package/test/capability-resolver.test.mjs +17 -0
- package/test/codex-autonomous-r44.test.mjs +1 -1
- package/test/coding-plane.test.mjs +1 -1
- package/test/commander-compat-runtime.test.mjs +42 -0
- package/test/controller-policy-preflight-r59.test.mjs +1 -0
- package/test/full-max-catalog-r46.test.mjs +1 -1
- package/test/native-diff-topology-r36.test.mjs +35 -2
- package/test/native-diff.test.mjs +83 -3
- package/test/output-schema.test.mjs +1 -1
- package/test/r51-live-log-polling.test.mjs +12 -0
- package/test/r53-release-contract.test.mjs +1 -1
- package/test/r54-release-contract.test.mjs +1 -1
- package/test/r55-release-contract.test.mjs +1 -1
- package/test/r56-release-contract.test.mjs +1 -1
- package/test/r57-release-contract.test.mjs +1 -1
- package/test/r58-bundled-bridge.test.mjs +1 -1
- package/test/r58-release-contract.test.mjs +2 -2
- package/test/r58-windows-gate.test.mjs +1 -1
- package/test/r59-tool-surface-compat.test.mjs +9 -5
- package/test/r60-release-contract.test.mjs +3 -3
- package/test/r61-release-contract.test.mjs +1 -1
- package/test/r62-release-contract.test.mjs +1 -1
- package/test/r63-release-contract.test.mjs +1 -1
- package/test/r64-release-contract.test.mjs +1 -1
- package/test/r65-authority-runtime-epoch.test.mjs +9 -1
- package/test/r65-epoch-native-activation-integration.test.mjs +4 -4
- package/test/r65-release-contract.test.mjs +1 -1
- package/test/r66-release-contract.test.mjs +2 -1
- package/test/r67-cli-integration.test.mjs +41 -0
- package/test/r67-diagnostics-cli.test.mjs +60 -0
- package/test/r67-diagnostics-verify.test.mjs +49 -0
- package/test/r67-diagnostics-zip-oracle.test.mjs +38 -0
- package/test/r67-diagnostics.test.mjs +60 -0
- package/test/r67-evidence-reconcile.test.mjs +186 -0
- package/test/r67-isolated-slot-rollback-restore.test.mjs +63 -0
- package/test/r67-live-log-secret-canary.test.mjs +44 -0
- package/test/r67-machine-fs-smoke-epoch.test.mjs +22 -0
- package/test/r67-native-inspector.test.mjs +131 -0
- package/test/r67-native-observation-authority.test.mjs +49 -0
- package/test/r67-npm-cross-volume.test.mjs +74 -0
- package/test/r67-npm-publish-gate.test.mjs +40 -0
- package/test/r67-regression-shards.test.mjs +184 -0
- package/test/r67-release-contract.test.mjs +45 -0
- package/test/r67-runtime-observation-binding.test.mjs +86 -0
- package/test/r67-server-observation-wiring.test.mjs +12 -0
- package/test/r67-signed-receipt.test.mjs +66 -0
- package/test/r67-skip-rationale.test.mjs +31 -0
- package/test/r67-tool-annotations.test.mjs +21 -0
- package/test/r67-windows-gate-argv.test.mjs +13 -0
- package/test/r69-live-outcome.test.mjs +137 -0
- package/test/r70-autonomous-grant-expiry.test.mjs +89 -0
- package/test/r70-autonomous-policy-bootstrap.test.mjs +166 -0
- package/test/r70-controller-autonomous-root.test.mjs +104 -0
- package/test/r70-controller-grant-subset.test.mjs +28 -0
- package/test/r70-controller-owner-issue-boundary.test.mjs +80 -0
- package/test/r70-controller-policy-snapshot.test.mjs +66 -0
- package/test/r70-owner-approval.test.mjs +67 -0
- package/test/r71-full-verifier-artifact.test.mjs +28 -0
- package/test/r71-isolated-slot-rollback-restore.test.mjs +62 -0
- package/test/r71-native-diff-mcp-wire.test.mjs +75 -0
- package/test/r71-publish-fence.test.mjs +38 -0
- package/test/r71-release-identity.test.mjs +31 -0
- package/test/release-version.test.mjs +1 -1
- package/test/remote-live-log-r36.test.mjs +10 -0
- package/test/remote-live-log-r37.test.mjs +29 -0
- package/test/remote-result-journal.test.mjs +12 -0
- package/test/remote-session-cli.test.mjs +2 -1
- package/test/semantic-multilang.test.mjs +1 -1
- package/test/standing-grants.test.mjs +2 -2
- package/test/tool-audit.test.mjs +14 -0
- package/bin/appcontainer-stage.obj +0 -0
- package/bin/bootstrap-advapi32.obj +0 -0
- package/bin/bootstrap-exitcode.obj +0 -0
- package/bin/bootstrap-kernel32.obj +0 -0
- package/bin/child-control-probe.obj +0 -0
- package/bin/child-control-stage.obj +0 -0
- package/bin/contained-reverse-worker.obj +0 -0
- package/bin/contained-transform-worker.obj +0 -0
- package/bin/containment-probe.obj +0 -0
- package/bin/deadbyte-contain.obj +0 -0
- package/bin/deadbyte-desktop-input-r40.obj +0 -0
- package/bin/deadbyte-desktop-observer-r40.obj +0 -0
- package/bin/deadbyte-desktop-uia-r40.obj +0 -0
- package/bin/deadbyte-exec.obj +0 -0
- package/bin/deadbyte-hardware-observer-r45.obj +0 -0
- package/bin/deadbyte-process-host.obj +0 -0
- package/bin/deadbyte-tunnel-host.obj +0 -0
- package/conpty-input-observer.obj +0 -0
- package/miniconpty.obj +0 -0
- package/proof/CONTAINMENT-BUILD.txt +0 -163
- package/proof/MCP-SMOKE-STATUS.txt +0 -9
- package/proof/NODE-SYNTAX.txt +0 -4
- package/proof/PROOF.txt +0 -6
- package/proof/R34-TASK8-SUPERVISOR-CHECKPOINT.json +0 -29
- package/proof/R34-TASK9-MCP-SURFACE-CHECKPOINT.json +0 -28
- package/proof/SECRET-SCAN.txt +0 -4
- package/proof/SOURCE-GATES.txt +0 -16
- package/proof/STATUS.txt +0 -11
- package/proof/TARGET-V0313-CONTAINMENT-PASS.sha256 +0 -1
- package/proof/TARGET-V0313-CONTAINMENT-PASS.txt +0 -215
- package/proof/TARGET-V040-CONTAINED-IPC-FAIL.sha256 +0 -1
- package/proof/TARGET-V040-CONTAINED-IPC-FAIL.txt +0 -299
- package/proof/TARGET-V041-CONTAINED-CREATEPROCESS-203.sha256 +0 -1
- package/proof/TARGET-V041-CONTAINED-CREATEPROCESS-203.txt +0 -311
- package/proof/TARGET-V042-CONTAINED-CREATEPROCESS-203.sha256 +0 -1
- package/proof/TARGET-V042-CONTAINED-CREATEPROCESS-203.txt +0 -313
- package/proof/TARGET-V043-CONTAINED-CREATEPROCESS-203.sha256 +0 -1
- package/proof/TARGET-V043-CONTAINED-CREATEPROCESS-203.txt +0 -308
- package/proof/TARGET-V044-CONTAINED-PASS.sha256 +0 -1
- package/proof/TARGET-V044-CONTAINED-PASS.txt +0 -432
- package/proof/TARGET-V045-DUAL-OPERATION-PASS.sha256 +0 -1
- package/proof/TARGET-V045-DUAL-OPERATION-PASS.txt +0 -481
- package/proof/TARGET-V046-FIXED-EXECUTABLE-REGISTRY-PASS.sha256 +0 -1
- package/proof/TARGET-V046-FIXED-EXECUTABLE-REGISTRY-PASS.txt +0 -610
- package/proof/TARGET-V047-RUNTIME-MANIFEST-PASS.sha256 +0 -1
- package/proof/TARGET-V047-RUNTIME-MANIFEST-PASS.txt +0 -642
- package/proof/TARGET-V050-BATCH-GATE-PASS.sha256 +0 -1
- package/proof/TARGET-V050-BATCH-GATE-PASS.txt +0 -713
- package/proof/TESTS.txt +0 -686
- package/proof/TRUST-EPHEMERAL.txt +0 -4
- package/proof/V03-FREEZE.txt +0 -27
- package/proof/V041-IPC-HOTFIX.txt +0 -16
- package/proof/V042-ENV-HOTFIX.txt +0 -15
- package/proof/V043-DRIVE-CWD-HOTFIX.txt +0 -14
- package/proof/V044-LOCALAPPDATA-HOTFIX.txt +0 -18
- package/proof/V045-OPERATION-REGISTRY.txt +0 -7
- package/proof/V046-WORKER-REGISTRY.txt +0 -12
- package/proof/V047-WORKER-MANIFEST.txt +0 -18
- package/proof/V050-BATCH-TRUST-CLOSURE.txt +0 -21
- package/proof/V060-ACTIVE-NETWORK-AUTHORITY.txt +0 -29
- package/proof/V070-NODE-SYNTAX.txt +0 -36
- package/proof/V070-NODE-TESTS.txt +0 -752
- package/proof/V070-PACK-DRY-RUN.txt +0 -126
- package/proof/V070-SOURCE-GATE.txt +0 -30
- package/proof/V070-STATIC-SCAN.txt +0 -4
- package/proof/V070-WINDOWS-GATE-PENDING.txt +0 -25
- package/proof/V071-NODE-SYNTAX.txt +0 -1
- package/proof/V071-NODE-TESTS.txt +0 -796
- package/proof/V071-PACK-DRY-RUN.json +0 -656
- package/proof/V071-SOURCE-GATE.txt +0 -16
- package/proof/V071-WINDOWS-GATE-PENDING.txt +0 -24
- package/proof/V073-NODE-SYNTAX.txt +0 -4
- package/proof/V073-SOURCE-GATE.txt +0 -21
- package/proof/V073-STATIC-SCAN.txt +0 -10
- package/proof/V073-WINDOWS-GATE-PENDING.txt +0 -5
- package/proof/VERIFY.txt +0 -7
- package/proof/WINDOWS-CONTAINED-STATUS.txt +0 -5
- package/proof/WINDOWS-CONTAINMENT-STATUS.txt +0 -3
- package/proof/commander-closure-20260927/CONTINUATION.json +0 -43
- package/proof/commander-closure-20260927/RESULT.json +0 -30
- package/proof/commander-closure-20260927/SEARCH-CONTINUATION.json +0 -30
- package/proof/commander-closure-20260927/XLS-REFERENCE-PROBE.json +0 -13
- package/proof/commander-closure-20260928/DIFFERENTIAL-CHECKPOINT.json +0 -122
- package/proof/r59-full-regression-current.json +0 -13
- package/proof/r59-full-regression-current.stderr.log +0 -0
- package/proof/r59-full-regression-current.stdout.log +0 -1268
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import {readdir,mkdir,open,readFile,rename} from 'node:fs/promises';
|
|
2
|
+
import {spawnSync} from 'node:child_process';
|
|
3
|
+
import {createHash} from 'node:crypto';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import {fileURLToPath} from 'node:url';
|
|
6
|
+
import {createR67ShardPlan,r67ShardTimeoutMs,r67RegressionTreeHash,parseR67TapSummary,parseR67NonpassCases,parseR67FailedCases} from '../src/r67-regression-shards.mjs';
|
|
7
|
+
|
|
8
|
+
const root=path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
9
|
+
const action=process.argv[2],operation=process.argv[3],number=process.argv[4];
|
|
10
|
+
if(!['run','status'].includes(action)||!/^[a-z0-9][a-z0-9._-]{5,63}$/.test(operation??'')||!/^(?:0|[1-9][0-9]?)$/.test(number??''))throw new Error('usage: run|status uniqueOperationId index');
|
|
11
|
+
const index=Number(number);
|
|
12
|
+
if(index>=32)throw new Error('R67 shard index must be 0..31');
|
|
13
|
+
const names=(await readdir(path.join(root,'test'))).filter(n=>n.endsWith('.test.mjs')).map(n=>'test/'+n).sort();
|
|
14
|
+
const plan=createR67ShardPlan(names,32),shard=plan.shards[index];
|
|
15
|
+
const hash=b=>createHash('sha256').update(b).digest('hex');
|
|
16
|
+
const evidenceRoot=path.resolve(root,'..','..','testing','0.15.44-r67','regression-shards');
|
|
17
|
+
const directory=path.join(evidenceRoot,operation+'-shard-'+String(index).padStart(2,'0'));
|
|
18
|
+
const intentPath=path.join(directory,'intent.json'),resultPath=path.join(directory,'result.json');
|
|
19
|
+
if(action==='status'){
|
|
20
|
+
let intent,result;
|
|
21
|
+
try{intent=JSON.parse(await readFile(intentPath,'utf8'));}catch(error){if(error.code==='ENOENT'){console.log(JSON.stringify({status:'NOT_STARTED',operation,shard_index:index}));process.exit(0);}throw error;}
|
|
22
|
+
try{result=JSON.parse(await readFile(resultPath,'utf8'));}catch(error){if(error.code==='ENOENT'){console.log(JSON.stringify({status:'RUNNING_OR_OUTCOME_UNKNOWN',operation,shard_index:index,intent}));process.exit(0);}throw error;}
|
|
23
|
+
const {receipt_sha256,...body}=result;
|
|
24
|
+
if(receipt_sha256!==hash(Buffer.from(JSON.stringify(body),'utf8')))throw new Error('durable result receipt hash mismatch');
|
|
25
|
+
console.log(JSON.stringify({status:'COMPLETED_RECORD',operation,shard_index:index,result},null,2));
|
|
26
|
+
process.exit(0);
|
|
27
|
+
}
|
|
28
|
+
await mkdir(evidenceRoot,{recursive:true});
|
|
29
|
+
await mkdir(directory,{recursive:false}); // EEXIST means NEVER rerun: reconcile existing intent/result
|
|
30
|
+
const startedAt=new Date().toISOString();
|
|
31
|
+
const fileHashes=[];
|
|
32
|
+
for(const name of names)fileHashes.push([name,hash(await readFile(path.join(root,name)))]);
|
|
33
|
+
const test_tree_sha256=hash(Buffer.from(JSON.stringify(fileHashes),'utf8'));
|
|
34
|
+
const sourceTree=await r67RegressionTreeHash(root);
|
|
35
|
+
const intent={schema:'deadbyte.r67-shard-intent.v1',operation,shard_index:index,plan_sha256:plan.plan_sha256,
|
|
36
|
+
files_sha256:shard.files_sha256,test_tree_sha256,source_tree_sha256:sourceTree.sha256,
|
|
37
|
+
source_file_count:sourceTree.file_count,started_at_utc:startedAt,files:shard.files};
|
|
38
|
+
const intentHandle=await open(intentPath,'wx',0o600);
|
|
39
|
+
try{await intentHandle.writeFile(JSON.stringify(intent,null,2)+'\n');await intentHandle.sync();}finally{await intentHandle.close();}
|
|
40
|
+
const began=Date.now();
|
|
41
|
+
const configuredTimeoutMs=r67ShardTimeoutMs(shard);
|
|
42
|
+
const child=spawnSync(process.execPath,['--test','--test-reporter=tap','--test-concurrency=2',...shard.files],{
|
|
43
|
+
cwd:root,encoding:'utf8',windowsHide:true,shell:false,timeout:configuredTimeoutMs,maxBuffer:16*1024*1024
|
|
44
|
+
});
|
|
45
|
+
const output=String(child.stdout||''),stderr=String(child.stderr||'');
|
|
46
|
+
const tap=parseR67TapSummary(output);
|
|
47
|
+
const nonpass=parseR67NonpassCases(output);
|
|
48
|
+
const failures=parseR67FailedCases(output);
|
|
49
|
+
const testCount=tap?.tests??null,passed=tap?.pass??null,failed=tap?.fail??null;
|
|
50
|
+
let status='OUTCOME_UNKNOWN';
|
|
51
|
+
if(!child.error&&Number.isInteger(child.status)&&tap!==null){
|
|
52
|
+
status=(child.status===0&&failed===0&&testCount>=shard.files.length)?'PASS':'FAILED';
|
|
53
|
+
}
|
|
54
|
+
const body={schema:'deadbyte.r67-shard-result.v2',operation_id:operation,shard_index:index,
|
|
55
|
+
plan_sha256:plan.plan_sha256,files_sha256:shard.files_sha256,test_tree_sha256,
|
|
56
|
+
source_tree_sha256:sourceTree.sha256,source_file_count:sourceTree.file_count,
|
|
57
|
+
status,exit_code:child.status,test_count:testCount,passed,failed,
|
|
58
|
+
skipped:tap?.skipped??null,cancelled:tap?.cancelled??null,todo:tap?.todo??null,
|
|
59
|
+
...(nonpass?{nonpass_cases:nonpass.cases,nonpass_fully_classified:nonpass.fully_classified}:{}),
|
|
60
|
+
failure_cases:failures.cases,failure_cases_complete:failures.complete,
|
|
61
|
+
timed_out:child.error?.code==='ETIMEDOUT',failure_reason:child.error?.code??null,
|
|
62
|
+
elapsed_ms:Date.now()-began,configured_timeout_ms:configuredTimeoutMs,finished_at_utc:new Date().toISOString(),
|
|
63
|
+
stdout_sha256:hash(Buffer.from(output,'utf8')),stderr_sha256:hash(Buffer.from(stderr,'utf8'))};
|
|
64
|
+
const receipt={...body,receipt_sha256:hash(Buffer.from(JSON.stringify(body),'utf8'))};
|
|
65
|
+
const temporary=path.join(directory,'result.tmp-'+process.pid);
|
|
66
|
+
const h=await open(temporary,'wx',0o600);
|
|
67
|
+
try{await h.writeFile(JSON.stringify(receipt,null,2)+'\n');await h.sync();}finally{await h.close();}
|
|
68
|
+
await rename(temporary,resultPath);
|
|
69
|
+
console.log(JSON.stringify({status,receipt_path:resultPath,receipt},null,2));
|
|
70
|
+
if(status!=='PASS')process.exitCode=1;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {spawnSync} from 'node:child_process';
|
|
2
|
+
import {readFile} from 'node:fs/promises';
|
|
3
|
+
import {fileURLToPath} from 'node:url';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
const root=path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
6
|
+
const op=process.argv[2],start=Number(process.argv[3]),end=Number(process.argv[4]);
|
|
7
|
+
if(!/^[a-z0-9][a-z0-9._-]{5,63}$/.test(op??'')||!Number.isInteger(start)||!Number.isInteger(end)||start<0||end>32||end<=start||end-start>8)throw Error('usage: operation id, start, end (max eight)');
|
|
8
|
+
const runner=path.join(root,'scripts','r67-regression-shard-run.mjs');
|
|
9
|
+
const results=[];
|
|
10
|
+
for(let i=start;i<end;i++){
|
|
11
|
+
const found=spawnSync(process.execPath,[runner,'run',op,String(i)],{cwd:root,encoding:'utf8',shell:false,windowsHide:true,timeout:220000,maxBuffer:256*1024});
|
|
12
|
+
const receiptPath=path.resolve(root,'..','..','testing','0.15.44-r67','regression-shards',op+'-shard-'+String(i).padStart(2,'0'),'result.json');
|
|
13
|
+
let body=null;try{body=JSON.parse(await readFile(receiptPath,'utf8'));}catch{}
|
|
14
|
+
results.push({shard_index:i,transport_exit:found.status,child_error:found.error?.code??null,recorded_status:body?.status??'MISSING',test_count:body?.test_count??null,passed:body?.passed??null,skipped:body?.skipped??null,nonpass_classified:body?.nonpass_fully_classified??null,source_tree_sha256:body?.source_tree_sha256??null,receipt_sha256:body?.receipt_sha256??null});
|
|
15
|
+
if(!body){break;}
|
|
16
|
+
}
|
|
17
|
+
console.log(JSON.stringify({schema:'deadbyte.r67-batch-progress.v1',operation_id:op,results},null,2));
|
|
18
|
+
if(results.length!==end-start||results.some(r=>r.recorded_status!=='PASS'))process.exitCode=2;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import {readFile,writeFile,stat,lstat,mkdir,copyFile} from 'node:fs/promises';
|
|
2
|
+
import {createHash} from 'node:crypto';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import {fileURLToPath} from 'node:url';
|
|
5
|
+
const candidate=path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
6
|
+
const parent=path.join(path.dirname(candidate),'deadbyte-mcp-0.15.43-r66');
|
|
7
|
+
const EXPECT='4c4a64a4c8e9f5a6e9eecce85fd0007ebcac99121b29c07f1a1fc81d1643cd33';
|
|
8
|
+
const sha=b=>createHash('sha256').update(b).digest('hex');
|
|
9
|
+
const manifest=await readFile(path.join(parent,'MANIFEST.SHA256'));
|
|
10
|
+
if(sha(manifest)!==EXPECT)throw new Error('R67 parent manifest SHA mismatch');
|
|
11
|
+
const rows=manifest.toString('utf8').trimEnd().split(/\r?\n/).map(line=>{const m=/^([a-f0-9]{64}) (.+)$/.exec(line);if(!m)throw new Error('bad manifest row');return {sha:m[1],rel:m[2]};});
|
|
12
|
+
const seen=new Set();
|
|
13
|
+
let copied=0,bytes=0;
|
|
14
|
+
for(const {sha:want,rel} of rows){
|
|
15
|
+
if(rel.startsWith('/')||rel.includes('\\')||rel.split('/').some(x=>!x||x==='.'||x==='..')||seen.has(rel))throw new Error('unsafe or duplicate parent path: '+rel);
|
|
16
|
+
seen.add(rel);
|
|
17
|
+
const src=path.join(parent,...rel.split('/'));const info=await lstat(src);
|
|
18
|
+
if(!info.isFile()||info.isSymbolicLink())throw new Error('non-file predecessor: '+rel);
|
|
19
|
+
const data=await readFile(src);if(sha(data)!==want)throw new Error('source drift: '+rel);
|
|
20
|
+
const dst=path.join(candidate,...rel.split('/'));
|
|
21
|
+
await mkdir(path.dirname(dst),{recursive:true});
|
|
22
|
+
try{const existing=await readFile(dst);if(sha(existing)!==want)throw new Error('destination differs: '+rel);}catch(e){if(e.code!=='ENOENT')throw e;await copyFile(src,dst);}
|
|
23
|
+
if(sha(await readFile(dst))!==want)throw new Error('copy differs: '+rel);
|
|
24
|
+
copied++;bytes+=data.length;
|
|
25
|
+
}
|
|
26
|
+
await writeFile(path.join(candidate,'MANIFEST.SHA256'),manifest,{flag:'wx'});
|
|
27
|
+
const proof={schema:'deadbyte.r67-candidate-parent.v1',parent_release_id:'v0.15.43-4c4a64a4c8e9f5a6',parent_manifest_sha256:EXPECT,source_directory:parent,candidate_directory:candidate,copied_files:copied,copied_bytes:bytes,mutation:false};
|
|
28
|
+
await mkdir(path.join(candidate,'docs'),{recursive:true});
|
|
29
|
+
await writeFile(path.join(candidate,'docs','R67-CANDIDATE-PARENT.json'),JSON.stringify(proof,null,2)+'\n',{flag:'wx'});
|
|
30
|
+
console.log(JSON.stringify({status:'STAGED',copied_files:copied,copied_bytes:bytes,parent_manifest_sha256:EXPECT,candidate},null,2));
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {readFile} from 'node:fs/promises';
|
|
2
|
+
import {createHash,createPublicKey,verify as edVerify} from 'node:crypto';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import {fileURLToPath} from 'node:url';
|
|
5
|
+
const root=path.resolve(fileURLToPath(new URL('../../..',import.meta.url)));
|
|
6
|
+
const receiptFile=path.join(root,'testing','0.15.44-r67','R67-PRODUCTION-BASELINE.json');
|
|
7
|
+
const receipt=JSON.parse(await readFile(receiptFile,'utf8'));
|
|
8
|
+
const ping=receipt.signed_ping;
|
|
9
|
+
const spki=Buffer.from(receipt.machine.public_key_spki_base64,'base64');
|
|
10
|
+
const keyId=createHash('sha256').update(spki).digest('hex');
|
|
11
|
+
const {attestation,...body}=ping;
|
|
12
|
+
const sorted=v=>Array.isArray(v)?v.map(sorted):v!==null&&typeof v==='object'?Object.fromEntries(Object.keys(v).sort().map(k=>[k,sorted(v[k])])):v;
|
|
13
|
+
const message=Buffer.concat([Buffer.from('DEADBYTE-MACHINE-PING-V1\0','utf8'),Buffer.from(JSON.stringify(sorted(body)),'utf8')]);
|
|
14
|
+
const digest=createHash('sha256').update(message).digest('hex');
|
|
15
|
+
const key=createPublicKey({key:spki,format:'der',type:'spki'});
|
|
16
|
+
const signature=Buffer.from(attestation.signature_base64,'base64');
|
|
17
|
+
const valid=key.asymmetricKeyType==='ed25519'&&signature.length===64&&attestation.key_id===keyId&&ping.machine_id===keyId&&receipt.machine.machine_id===keyId&&edVerify(null,message,key,signature);
|
|
18
|
+
const prior=receipt.independent_verification?.signed_message_sha256??null;
|
|
19
|
+
const ok=valid&&digest===prior;
|
|
20
|
+
const result={schema:'deadbyte.r67-independent-baseline-check.v1',status:ok?'PASS':'FAIL',ed25519_valid:valid,key_identity_matches:keyId===ping.machine_id,message_sha256:digest,claimed_message_sha256:prior,release_id:ping.release_id};
|
|
21
|
+
console.log(JSON.stringify(result,null,2));
|
|
22
|
+
if(!ok)process.exitCode=1;
|
|
@@ -59,6 +59,7 @@ function npmPackFiles() {
|
|
|
59
59
|
const raw = item?.path;
|
|
60
60
|
if (typeof raw !== 'string' || raw.length < 1) throw new Error('npm pack file path invalid');
|
|
61
61
|
const rel = raw.replaceAll('\\','/');
|
|
62
|
+
if (/\.tgz$/i.test(rel)) throw new Error(`npm archive self-inclusion forbidden: ${rel}; exclude existing tarballs from the npm package surface`);
|
|
62
63
|
if (rel === manifestName || excludedPackagePaths.has(rel) || excludedPackagePrefixes.some(prefix => rel.startsWith(prefix))) continue;
|
|
63
64
|
if (path.posix.isAbsolute(rel) || rel.split('/').includes('..') || rel.includes('\0')) {
|
|
64
65
|
throw new Error(`unsafe package path '${rel}'`);
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#requires -Version 5.1
|
|
2
|
+
# R70 verifier artifact: runs the candidate test suite without altering release manifests.
|
|
3
|
+
param([switch]$SelfTest)
|
|
4
|
+
Set-StrictMode -Version Latest
|
|
5
|
+
$ErrorActionPreference = 'Continue'
|
|
6
|
+
Set-Location -LiteralPath (Split-Path -Parent $PSScriptRoot)
|
|
7
|
+
$timer = [System.Diagnostics.Stopwatch]::StartNew()
|
|
8
|
+
if ($SelfTest) {
|
|
9
|
+
$lines = @('tests 1', 'pass 0', 'fail 1', 'skipped 0', 'hash mismatch: SYNTHETIC_TEST')
|
|
10
|
+
$exitCode = 1
|
|
11
|
+
} else {
|
|
12
|
+
$lines = @(& npm.cmd test 2>&1 | ForEach-Object { [string]$_ })
|
|
13
|
+
$exitCode = [int]$LASTEXITCODE
|
|
14
|
+
}
|
|
15
|
+
$timer.Stop()
|
|
16
|
+
$utf8 = New-Object System.Text.UTF8Encoding($false)
|
|
17
|
+
$stdoutBytes = $utf8.GetBytes(($lines -join "`n"))
|
|
18
|
+
$sha = [System.Security.Cryptography.SHA256]::Create()
|
|
19
|
+
try {
|
|
20
|
+
$hash = ([BitConverter]::ToString($sha.ComputeHash($stdoutBytes))).Replace('-', '').ToLowerInvariant()
|
|
21
|
+
} finally {
|
|
22
|
+
$sha.Dispose()
|
|
23
|
+
}
|
|
24
|
+
Write-Output 'R70_FULL_TEST_SCHEMA=deadbyte.verifier-output.r70.v1'
|
|
25
|
+
Write-Output ('R70_FULL_TEST_EXIT_CODE=' + $exitCode)
|
|
26
|
+
Write-Output ('R70_FULL_TEST_ELAPSED_MS=' + [math]::Round($timer.Elapsed.TotalMilliseconds))
|
|
27
|
+
Write-Output ('R70_FULL_TEST_STDOUT_SHA256=' + $hash)
|
|
28
|
+
Write-Output ('R70_FULL_TEST_LINE_COUNT=' + $lines.Count)
|
|
29
|
+
$selected = @($lines | Where-Object {
|
|
30
|
+
$_ -match '(?i)(?:^|\s)(?:tests|pass|fail|skipped|cancelled|duration_ms)\s+[0-9.]+' -or
|
|
31
|
+
$_ -match '^✖' -or
|
|
32
|
+
$_ -match '^ (Error|AssertionError|SyntaxError):' -or
|
|
33
|
+
$_ -match 'hash mismatch:' -or
|
|
34
|
+
$_ -match '^# (tests|pass|fail|skipped) '
|
|
35
|
+
})
|
|
36
|
+
$summary = @($selected | Select-Object -Last 140 | ForEach-Object {
|
|
37
|
+
if ($_.Length -gt 512) { $_.Substring(0, 512) } else { $_ }
|
|
38
|
+
})
|
|
39
|
+
$artifactDir = Join-Path (Get-Location).Path 'testing\r70-verifier'
|
|
40
|
+
if (-not (Test-Path -LiteralPath $artifactDir -PathType Container)) {
|
|
41
|
+
New-Item -ItemType Directory -Path $artifactDir -Force | Out-Null
|
|
42
|
+
}
|
|
43
|
+
$artifact = Join-Path $artifactDir ('result-{0}-{1}.json' -f (Get-Date -Format 'yyyyMMdd-HHmmss'), [Guid]::NewGuid().ToString('N'))
|
|
44
|
+
$stdoutPath = [System.IO.Path]::ChangeExtension($artifact, '.stdout.txt')
|
|
45
|
+
$stdoutStream = New-Object System.IO.FileStream($stdoutPath, [System.IO.FileMode]::CreateNew, [System.IO.FileAccess]::Write, [System.IO.FileShare]::None)
|
|
46
|
+
try { $stdoutStream.Write($stdoutBytes, 0, $stdoutBytes.Length); $stdoutStream.Flush($true) } finally { $stdoutStream.Dispose() }
|
|
47
|
+
$record = [ordered]@{
|
|
48
|
+
schema = 'deadbyte.r70-full-regression-result.v1'
|
|
49
|
+
mode = if ($SelfTest) { 'synthetic-selftest' } else { 'candidate-full-regression' }
|
|
50
|
+
created_at_utc = [DateTime]::UtcNow.ToString('o')
|
|
51
|
+
exit_code = $exitCode
|
|
52
|
+
elapsed_ms = [math]::Round($timer.Elapsed.TotalMilliseconds)
|
|
53
|
+
stdout_sha256 = $hash
|
|
54
|
+
stdout_path = $stdoutPath
|
|
55
|
+
total_line_count = $lines.Count
|
|
56
|
+
summary = $summary
|
|
57
|
+
}
|
|
58
|
+
$json = ($record | ConvertTo-Json -Depth 5 -Compress) + "`n"
|
|
59
|
+
$bytes = $utf8.GetBytes($json)
|
|
60
|
+
$stream = New-Object System.IO.FileStream($artifact, [System.IO.FileMode]::CreateNew, [System.IO.FileAccess]::Write, [System.IO.FileShare]::None)
|
|
61
|
+
try { $stream.Write($bytes, 0, $bytes.Length); $stream.Flush($true) } finally { $stream.Dispose() }
|
|
62
|
+
$artifactHashAlgorithm = [System.Security.Cryptography.SHA256]::Create()
|
|
63
|
+
try {
|
|
64
|
+
$artifactStream = [System.IO.File]::OpenRead($artifact)
|
|
65
|
+
try { $artifactSha = ([BitConverter]::ToString($artifactHashAlgorithm.ComputeHash($artifactStream))).Replace('-', '').ToLowerInvariant() }
|
|
66
|
+
finally { $artifactStream.Dispose() }
|
|
67
|
+
} finally { $artifactHashAlgorithm.Dispose() }
|
|
68
|
+
Write-Output ('R70_FULL_TEST_ARTIFACT=' + $artifact)
|
|
69
|
+
Write-Output ('R70_FULL_TEST_ARTIFACT_SHA256=' + $artifactSha)
|
|
70
|
+
foreach ($line in $summary) { Write-Output $line }
|
|
71
|
+
if ($SelfTest) { exit 0 }
|
|
72
|
+
exit $exitCode
|
|
@@ -2,6 +2,7 @@ import {createHash,randomBytes} from 'node:crypto';
|
|
|
2
2
|
import {open,readFile,rm} from 'node:fs/promises';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import {canonicalJson} from './canonical-json.mjs';
|
|
5
|
+
import {decodeUtf8Strict} from './text-policy.mjs';
|
|
5
6
|
import {
|
|
6
7
|
captureStandingGrant,compareSecurityEnvelopes,createAuthorityEpochStore,deriveSecurityEnvelope
|
|
7
8
|
} from './authority-continuity-r65.mjs';
|
|
@@ -17,7 +18,7 @@ const sha=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
|
17
18
|
const plain=value=>value&&typeof value==='object'&&!Array.isArray(value);
|
|
18
19
|
|
|
19
20
|
function parseJson(bytes,label){
|
|
20
|
-
try{return JSON.parse(bytes
|
|
21
|
+
try{return JSON.parse(decodeUtf8Strict(bytes));}
|
|
21
22
|
catch{throw new Error(`${label} JSON invalid`);}
|
|
22
23
|
}
|
|
23
24
|
function inside(root,target){
|
|
@@ -207,6 +207,10 @@ const DURABLE_EPOCH_ACTIONS=new Set(['grant','transaction_revoke','user_revoke',
|
|
|
207
207
|
const DURABLE_EPOCH_SCHEMA='deadbyte.authority-epoch-event.r65.v1';
|
|
208
208
|
const DURABLE_HEAD_SCHEMA='deadbyte.authority-epoch-head.r65.v1';
|
|
209
209
|
const DURABLE_EPOCH_DOMAIN=Buffer.from('DEADBYTE-AUTHORITY-DURABLE-EPOCH-R65-V1\0','utf8');
|
|
210
|
+
// Cache parsed public keys by the exact bytes read from disk, never by path.
|
|
211
|
+
// A changed trust file is re-read and yields a different entry immediately.
|
|
212
|
+
const DURABLE_PUBLIC_KEY_CACHE_LIMIT=8;
|
|
213
|
+
const durablePublicKeys=new Map();
|
|
210
214
|
const RESTORE_BINDING_FIELDS=Object.freeze(['prior_grant_sha256','prior_grant_instance_nonce','predecessor_policy_envelope_sha256','successor_policy_envelope_sha256','candidate_manifest_sha256','continuity_subject_sha256']);
|
|
211
215
|
function normalizeRestoreBinding(value,{required=false}={}){
|
|
212
216
|
if(value===undefined||value===null){if(required)throw new Error('authority epoch transaction restore binding required');return null;}
|
|
@@ -218,9 +222,19 @@ function normalizeRestoreBinding(value,{required=false}={}){
|
|
|
218
222
|
|
|
219
223
|
async function durableEpochKeys(runtimeDir,{privateRequired=false}={}){
|
|
220
224
|
const trust=path.join(path.dirname(path.resolve(runtimeDir)),'trust');
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
|
|
225
|
+
const publicBytes=await readFile(path.join(trust,'ed25519-public.pem'));
|
|
226
|
+
const publicSha=hashBytes(publicBytes);
|
|
227
|
+
let cached=durablePublicKeys.get(publicSha);
|
|
228
|
+
if(!cached){
|
|
229
|
+
const publicKey=createPublicKey(publicBytes);
|
|
230
|
+
if(publicKey.asymmetricKeyType!=='ed25519')throw new Error('authority epoch trust public key invalid');
|
|
231
|
+
const keyId=hashBytes(Buffer.from(publicKey.export({format:'der',type:'spki'})));
|
|
232
|
+
cached={publicKey,keyId};
|
|
233
|
+
if(durablePublicKeys.size>=DURABLE_PUBLIC_KEY_CACHE_LIMIT)
|
|
234
|
+
durablePublicKeys.delete(durablePublicKeys.keys().next().value);
|
|
235
|
+
durablePublicKeys.set(publicSha,cached);
|
|
236
|
+
}
|
|
237
|
+
const {publicKey,keyId}=cached;
|
|
224
238
|
if(!privateRequired)return {publicKey,keyId};
|
|
225
239
|
const privateKey=createPrivateKey(await readFile(path.join(trust,'ed25519-private.pem')));
|
|
226
240
|
if(privateKey.asymmetricKeyType!=='ed25519'||
|
|
@@ -315,7 +329,14 @@ async function readDurableHead(runtimeDir,plane){
|
|
|
315
329
|
if(head.action!=='transaction_restore'&&headRestoreBinding!==null)throw new Error('authority epoch unexpected restore binding');
|
|
316
330
|
const expectedName=durableEventName(head.seq,head.event_sha256);
|
|
317
331
|
if(head.event_file!==expectedName)throw new Error('authority epoch head event name mismatch');
|
|
318
|
-
|
|
332
|
+
// These are independent observations of one immutable event identity.
|
|
333
|
+
// Read them concurrently, then validate the complete set before trusting
|
|
334
|
+
// the head. The head remains freshly read on every authority decision.
|
|
335
|
+
const [eventNames,eventRead,keys]=await Promise.all([
|
|
336
|
+
readdir(path.join(dir,'events')),
|
|
337
|
+
readFile(path.join(dir,'events',head.event_file)).then(bytes=>({bytes}),()=>({bytes:null})),
|
|
338
|
+
durableEpochKeys(runtimeDir)
|
|
339
|
+
]);
|
|
319
340
|
if(eventNames.length>10000)throw new Error('authority epoch event budget exceeded');
|
|
320
341
|
for(const name of eventNames){
|
|
321
342
|
const match=/^(\d{16})-([0-9a-f]{64})\.json$/.exec(name);
|
|
@@ -324,13 +345,12 @@ async function readDurableHead(runtimeDir,plane){
|
|
|
324
345
|
if(!Number.isSafeInteger(seq)||seq>head.seq||(seq===head.seq&&name!==head.event_file))
|
|
325
346
|
throw new Error('authority epoch head replay or incomplete write');
|
|
326
347
|
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
catch{throw new Error('authority epoch event missing');}
|
|
348
|
+
const eventBytes=eventRead.bytes;
|
|
349
|
+
if(!eventBytes)throw new Error('authority epoch event missing');
|
|
330
350
|
if(hashBytes(eventBytes)!==head.event_sha256)throw new Error('authority epoch event hash mismatch');
|
|
331
351
|
let event;
|
|
332
352
|
try{event=JSON.parse(decodeUtf8Strict(eventBytes));}catch{throw new Error('authority epoch event invalid');}
|
|
333
|
-
const {publicKey,keyId}=
|
|
353
|
+
const {publicKey,keyId}=keys;
|
|
334
354
|
if(!verifyDurableEvent(event,publicKey,keyId))throw new Error('authority epoch event signature invalid');
|
|
335
355
|
for(const key of ['schema','plane','seq','action','update_id','grant_sha256','grant_instance_nonce','previous_event_sha256']){
|
|
336
356
|
const expected=key==='schema'?DURABLE_EPOCH_SCHEMA:head[key];
|
|
@@ -48,7 +48,7 @@ export function registerAutonomousTools(server,{ autonomousRuntime, nativeDiffRu
|
|
|
48
48
|
catch(error){ return fail(autonomousSessionStatusOutputSchema,error); } });
|
|
49
49
|
|
|
50
50
|
server.registerTool('native_diff_preview',{
|
|
51
|
-
description:'
|
|
51
|
+
description:'Validate exact file SHA-256 preconditions. With Coding read authority alone, return a read-only preview_only result that cannot be applied; a signed applicable diff additionally requires Autonomous authority. No Git metadata is used.',
|
|
52
52
|
inputSchema:z.strictObject({ root_id:id, title:z.string().max(160).default(''), operations:z.array(nativeOperation).min(1).max(32) }),
|
|
53
53
|
outputSchema:nativeDiffPreviewOutputSchema
|
|
54
54
|
},async({root_id,title,operations})=>{ try { return result(nativeDiffPreviewOutputSchema,
|
|
@@ -83,10 +83,13 @@ export const autonomousSessionStatusOutputSchema = statusContract({
|
|
|
83
83
|
});
|
|
84
84
|
|
|
85
85
|
export const nativeDiffPreviewOutputSchema = statusContract({
|
|
86
|
-
statuses:['ready','failed'], success:['ready'], required:['
|
|
86
|
+
statuses:['ready','preview_only','failed'], success:['ready','preview_only'], required:['root_id','operation_count','payload_bytes','paths','operations'],
|
|
87
87
|
shape:{ schema:z.enum(['deadbyte.native-diff.v1','deadbyte.native-diff.v2']).optional(), diff_id:hex64.optional(), root_id:z.string().min(1).max(64).optional(), operation_count:z.number().int().min(1).max(32).optional(),
|
|
88
88
|
payload_bytes:z.number().int().min(0).optional(), paths:z.array(z.string()).max(64).optional(),
|
|
89
89
|
operations:z.array(jsonObject).max(32).optional() }
|
|
90
|
+
}).superRefine((value,ctx)=>{
|
|
91
|
+
if(value.status==='ready'&&value.diff_id===undefined) ctx.addIssue({code:'custom',path:['diff_id'],message:'signed ready diff requires diff_id'});
|
|
92
|
+
if(value.status==='preview_only'&&value.diff_id!==undefined) ctx.addIssue({code:'custom',path:['diff_id'],message:'coding-only preview must not have an applicable diff_id'});
|
|
90
93
|
});
|
|
91
94
|
export const nativeDiffApplyOutputSchema = statusContract({
|
|
92
95
|
statuses:['committed','existing','failed'], success:['committed','existing'],
|
|
@@ -80,11 +80,11 @@ function normalizePlanner(raw,codingPolicy,rootIds) {
|
|
|
80
80
|
}
|
|
81
81
|
return provider;
|
|
82
82
|
}
|
|
83
|
-
function normalizeProfile(id, raw, codingPolicy) {
|
|
83
|
+
function normalizeProfile(id, raw, codingPolicy, rootIds) {
|
|
84
84
|
if (!ID_RE.test(id)) throw new Error(`invalid autonomous profile '${id}'`);
|
|
85
85
|
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) throw new Error(`autonomous profile '${id}' malformed`);
|
|
86
86
|
if (!['command','benchmark'].includes(raw.kind)) throw new Error(`autonomous profile '${id}' kind invalid`);
|
|
87
|
-
if (!ID_RE.test(raw.root_id ?? '') || !codingPolicy.roots[raw.root_id]) throw new Error(`autonomous profile '${id}' root invalid`);
|
|
87
|
+
if (!ID_RE.test(raw.root_id ?? '') || !codingPolicy.roots[raw.root_id] || !rootIds.includes(raw.root_id)) throw new Error(`autonomous profile '${id}' root invalid`);
|
|
88
88
|
if (!ID_RE.test(raw.command_id ?? '') || !codingPolicy.commands[raw.command_id]) throw new Error(`autonomous profile '${id}' command invalid`);
|
|
89
89
|
validatePortableRelativePath(raw.script_path);
|
|
90
90
|
if (!SHA256_RE.test(raw.script_sha256 ?? '')) throw new Error(`autonomous profile '${id}' script hash invalid`);
|
|
@@ -130,7 +130,7 @@ export async function loadAutonomousPolicy(policyPath, codingPolicy) {
|
|
|
130
130
|
const rootIds = Array.isArray(raw.root_ids) ? [...new Set(raw.root_ids)] : [];
|
|
131
131
|
if (rootIds.length < 1 || rootIds.some(id => !ID_RE.test(id) || !codingPolicy.roots[id])) throw new Error('autonomous root_ids invalid');
|
|
132
132
|
const profiles = {};
|
|
133
|
-
for (const [id, value] of Object.entries(raw.profiles ?? {})) profiles[id] = normalizeProfile(id, value, codingPolicy);
|
|
133
|
+
for (const [id, value] of Object.entries(raw.profiles ?? {})) profiles[id] = normalizeProfile(id, value, codingPolicy, rootIds);
|
|
134
134
|
const limits = raw.limits ?? {};
|
|
135
135
|
const policy = {
|
|
136
136
|
schema: AUTONOMOUS_POLICY_SCHEMA, enabled: true, policy_path: absolute,
|
|
@@ -154,6 +154,43 @@ export async function loadAutonomousPolicy(policyPath, codingPolicy) {
|
|
|
154
154
|
return Object.freeze(policy);
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
+
export function inspectAutonomousStandingWindow(lease,now=new Date()){
|
|
158
|
+
// v2 legacy standing grants have no expiry. New bounded grants must be
|
|
159
|
+
// checked on every authority observation, including after a runtime restart.
|
|
160
|
+
if(!lease||typeof lease!=='object'||Array.isArray(lease)){
|
|
161
|
+
return {ok:false,reason:'expiry-invalid',expires_at_utc:null,remaining_ms:null};
|
|
162
|
+
}
|
|
163
|
+
if(!Object.hasOwn(lease,'expires_at_utc')){
|
|
164
|
+
return {ok:true,reason:null,expires_at_utc:null,remaining_ms:null};
|
|
165
|
+
}
|
|
166
|
+
const canonical=value=>typeof value==='string'&&
|
|
167
|
+
/^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{3,7}Z$/.test(value);
|
|
168
|
+
const expiry=lease.expires_at_utc;
|
|
169
|
+
const issued=lease.granted_at_utc;
|
|
170
|
+
if(!canonical(expiry)||!canonical(issued)){
|
|
171
|
+
return {ok:false,reason:'expiry-invalid',expires_at_utc:null,remaining_ms:null};
|
|
172
|
+
}
|
|
173
|
+
const end=Date.parse(expiry),start=Date.parse(issued);
|
|
174
|
+
if(!Number.isFinite(end)||!Number.isFinite(start)){
|
|
175
|
+
return {ok:false,reason:'expiry-invalid',expires_at_utc:null,remaining_ms:null};
|
|
176
|
+
}
|
|
177
|
+
const duration=end-start;
|
|
178
|
+
if(duration<=0||duration>3_600_000){
|
|
179
|
+
return {ok:false,reason:'expiry-window-invalid',expires_at_utc:expiry,remaining_ms:null};
|
|
180
|
+
}
|
|
181
|
+
const observed=now instanceof Date?now.getTime():NaN;
|
|
182
|
+
if(!Number.isFinite(observed)){
|
|
183
|
+
return {ok:false,reason:'clock-invalid',expires_at_utc:expiry,remaining_ms:null};
|
|
184
|
+
}
|
|
185
|
+
if(observed<start){
|
|
186
|
+
return {ok:false,reason:'not-yet-valid',expires_at_utc:expiry,remaining_ms:null};
|
|
187
|
+
}
|
|
188
|
+
if(observed>=end){
|
|
189
|
+
return {ok:false,reason:'expired',expires_at_utc:expiry,remaining_ms:0};
|
|
190
|
+
}
|
|
191
|
+
return {ok:true,reason:null,expires_at_utc:expiry,remaining_ms:end-observed};
|
|
192
|
+
}
|
|
193
|
+
|
|
157
194
|
export async function autonomousSessionStatus(policy, now = new Date()) {
|
|
158
195
|
let lease,leaseBytes;
|
|
159
196
|
try { leaseBytes=await readFile(policy.lease_file); lease = JSON.parse(decodeUtf8Strict(leaseBytes)); }
|
|
@@ -164,15 +201,25 @@ export async function autonomousSessionStatus(policy, now = new Date()) {
|
|
|
164
201
|
return { configured:true, armed:false, reason:'lease-schema', expires_at_utc:null };
|
|
165
202
|
}
|
|
166
203
|
if (lease.policy_sha256 !== policy.policy_sha256) return { configured:true, armed:false, reason:'policy-digest', expires_at_utc:null };
|
|
204
|
+
// Controller and runtime must agree on the exact Coding authority policy
|
|
205
|
+
// for every signed v2 Autonomous grant, including after generation changes.
|
|
206
|
+
if (lease.schema === AUTONOMOUS_GRANT_SCHEMA &&
|
|
207
|
+
lease.coding_policy_sha256 !== policy.coding_policy_sha256) {
|
|
208
|
+
return { configured:true, armed:false, reason:'coding-policy-digest', expires_at_utc:null };
|
|
209
|
+
}
|
|
167
210
|
if (typeof lease.instance_nonce !== 'string' || !SHA256_RE.test(lease.instance_nonce)) return { configured:true, armed:false, reason:'nonce-invalid', expires_at_utc:null };
|
|
168
211
|
const roots = Array.isArray(lease.root_ids) ? [...new Set(lease.root_ids)] : [];
|
|
169
212
|
if (roots.length < 1 || roots.some(id => !policy.root_ids.includes(id))) return { configured:true, armed:false, reason:'roots-invalid', expires_at_utc:null };
|
|
170
213
|
if (lease.schema === AUTONOMOUS_GRANT_SCHEMA) {
|
|
214
|
+
const window=inspectAutonomousStandingWindow(lease,now);
|
|
215
|
+
if(!window.ok) return {configured:true,armed:false,reason:window.reason,
|
|
216
|
+
expires_at_utc:window.expires_at_utc,remaining_ms:window.remaining_ms,
|
|
217
|
+
standing:false,instance_nonce:lease.instance_nonce,root_ids:roots};
|
|
171
218
|
const epoch=await verifyStandingGrantEpoch({plane:'autonomous',grantFile:policy.lease_file,grantBytes:leaseBytes,grantInstanceNonce:lease.instance_nonce,policyPath:policy.policy_path});
|
|
172
|
-
if(!epoch.trusted)return { configured:true,armed:false,reason:epoch.reason,expires_at_utc:
|
|
173
|
-
remaining_ms:
|
|
174
|
-
return { configured:true, armed:true, reason:'standing-grant', expires_at_utc:
|
|
175
|
-
remaining_ms:
|
|
219
|
+
if(!epoch.trusted)return { configured:true,armed:false,reason:epoch.reason,expires_at_utc:window.expires_at_utc,
|
|
220
|
+
remaining_ms:window.remaining_ms,standing:false,instance_nonce:lease.instance_nonce,root_ids:roots };
|
|
221
|
+
return { configured:true, armed:true, reason:'standing-grant', expires_at_utc:window.expires_at_utc,
|
|
222
|
+
remaining_ms:window.remaining_ms, standing:true, instance_nonce:lease.instance_nonce, root_ids:roots, authority_epoch:epoch };
|
|
176
223
|
}
|
|
177
224
|
const expires = Date.parse(lease.expires_at_utc);
|
|
178
225
|
if (!Number.isFinite(expires)) return { configured:true, armed:false, reason:'expiry-invalid', expires_at_utc:null };
|
|
@@ -308,7 +308,7 @@ async function executeProfile({ ctx, events, goalId, actionKey, profileId, epoch
|
|
|
308
308
|
const r34Paused=await pauseR34Ambiguous(checked.reason ?? error);
|
|
309
309
|
if (r34Paused) return r34Paused;
|
|
310
310
|
await appendEvent(ctx,events,signingKeyPath,'goal_paused',{ reason:'profile_execution_without_receipt', profile_id:profileId,
|
|
311
|
-
action_key:actionKey, detail:truncated(error) });
|
|
311
|
+
action_key:actionKey, receipt_id:receiptId, request_sha256:requestSha256, detail:truncated(error,512) });
|
|
312
312
|
return { status:'paused', observation:null, existing:false };
|
|
313
313
|
}
|
|
314
314
|
result = null;
|
|
@@ -152,7 +152,7 @@ export const R36_CAPABILITY_ENTRIES=Object.freeze([
|
|
|
152
152
|
gateway('desktop.action','desktop_action','desktop_control','action','DEADBYTE_DESKTOP_RUNTIME','desktop',{mutating:true,receipt_class:'desktop'}),
|
|
153
153
|
|
|
154
154
|
direct('autonomous.session_status','autonomous_session_status','DEADBYTE_AUTONOMOUS_RUNTIME','autonomous',{receipt_class:'autonomous'}),
|
|
155
|
-
direct('native_diff.preview','native_diff_preview','DEADBYTE_AUTONOMOUS_RUNTIME','
|
|
155
|
+
direct('native_diff.preview','native_diff_preview','DEADBYTE_AUTONOMOUS_RUNTIME','coding',{receipt_class:'native_diff'}),
|
|
156
156
|
direct('native_diff.apply','native_diff_apply','DEADBYTE_AUTONOMOUS_RUNTIME','autonomous',{mutating:true,receipt_class:'native_diff'}),
|
|
157
157
|
direct('native_diff.verify','native_diff_verify','DEADBYTE_AUTONOMOUS_RUNTIME','autonomous',{receipt_class:'verification'}),
|
|
158
158
|
direct('autonomous.goal_submit','autonomous_goal_submit','DEADBYTE_AUTONOMOUS_RUNTIME','autonomous',{mutating:true,receipt_class:'autonomous'}),
|
|
@@ -3,7 +3,8 @@ import { assertHostArmed } from './host-plane.mjs';
|
|
|
3
3
|
|
|
4
4
|
const CODING_ARMED_READ_CAPABILITIES = new Set([
|
|
5
5
|
'coding.tree','coding.stat','coding.search','coding.files_read','coding.file_read',
|
|
6
|
-
'semantic.outline','semantic.definition','semantic.references','semantic.diagnostics','semantic.implementations','semantic.rename_preview'
|
|
6
|
+
'semantic.outline','semantic.definition','semantic.references','semantic.diagnostics','semantic.implementations','semantic.rename_preview',
|
|
7
|
+
'native_diff.preview'
|
|
7
8
|
]);
|
|
8
9
|
|
|
9
10
|
export const CAPABILITY_STATES = Object.freeze({
|
|
@@ -20,7 +20,7 @@ const CONTRACTS = Object.freeze({
|
|
|
20
20
|
get_recent_tool_calls:{native:'operation_history.recent',required:[],mutation:false},
|
|
21
21
|
get_usage_stats:{native:'operation_history.stats',required:[],mutation:false},
|
|
22
22
|
give_feedback_to_desktop_commander:{native:'commander.feedback',required:['message'],mutation:true},
|
|
23
|
-
host_exec:{native:'host.exec',required:['
|
|
23
|
+
host_exec:{native:'host.exec',required:['root_id'],mutation:true},
|
|
24
24
|
host_file_read:{native:'host.file_read',required:['path'],mutation:false},
|
|
25
25
|
host_file_write:{native:'host.file_write',required:['path','content','expected_sha256'],mutation:true},
|
|
26
26
|
interact_with_process:{native:'process.input',required:['session_id','input'],mutation:true},
|
|
@@ -53,13 +53,41 @@ export function commanderCompatibilityContract(name) {
|
|
|
53
53
|
return CONTRACTS[name] ?? {native:DEADBYTE_NATIVE_TOOLS[name] ?? null,required:[],mutation:false};
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
function validateHostExecRequest(args) {
|
|
57
|
+
const mode=args.mode??'script';
|
|
58
|
+
const common=['mode','root_id','cwd','timeout_ms'];
|
|
59
|
+
let required, allowed;
|
|
60
|
+
if(mode==='script'){
|
|
61
|
+
required=['root_id','command_id','script_path','script_sha256'];
|
|
62
|
+
allowed=[...common,'command_id','script_path','script_sha256','args'];
|
|
63
|
+
}else if(mode==='inline'){
|
|
64
|
+
required=['root_id','command_id','command'];
|
|
65
|
+
allowed=[...common,'command_id','command'];
|
|
66
|
+
}else if(mode==='native'){
|
|
67
|
+
required=['root_id','executable','executable_sha256'];
|
|
68
|
+
allowed=[...common,'executable','executable_sha256','args'];
|
|
69
|
+
}else{
|
|
70
|
+
throw new Error('host_exec mode must be script, inline, or native');
|
|
71
|
+
}
|
|
72
|
+
const missing=required.filter(k=>!own(args,k)||args[k]===undefined||args[k]===null||args[k]==='');
|
|
73
|
+
if(missing.length) throw new Error(`missing required fields: ${missing.join(', ')}`);
|
|
74
|
+
const unknown=Object.keys(args).filter(k=>!allowed.includes(k));
|
|
75
|
+
if(unknown.length) throw new Error(`host_exec ${mode} unexpected fields: ${unknown.join(', ')}`);
|
|
76
|
+
const id=/^[A-Za-z0-9._-]{1,64}$/;
|
|
77
|
+
if(typeof args.root_id!=='string'||!id.test(args.root_id)) throw new Error('host_exec root_id invalid');
|
|
78
|
+
if(mode!=='native'&&(typeof args.command_id!=='string'||!id.test(args.command_id))) throw new Error('host_exec command_id invalid');
|
|
79
|
+
if(mode==='inline'&&(typeof args.command!=='string'||args.command.length>262144||args.command.includes(String.fromCharCode(0)))) throw new Error('host_exec inline command invalid');
|
|
80
|
+
if(mode==='script'&&!/^[0-9a-f]{64}$/.test(args.script_sha256)) throw new Error('host_exec script_sha256 invalid');
|
|
81
|
+
if(mode==='native'&&!/^[0-9a-f]{64}$/.test(args.executable_sha256)) throw new Error('host_exec executable_sha256 invalid');
|
|
82
|
+
}
|
|
83
|
+
|
|
56
84
|
export function validateCommanderRequest(name,args={}) {
|
|
57
85
|
const c=commanderCompatibilityContract(name);
|
|
58
86
|
if (!args || typeof args!=='object' || Array.isArray(args)) throw new Error('request arguments must be an object');
|
|
59
87
|
const missing=c.required.filter(k=>!own(args,k)||args[k]===undefined||args[k]===null||args[k]==='');
|
|
60
88
|
if(missing.length) throw new Error(`missing required fields: ${missing.join(', ')}`);
|
|
61
89
|
if(c.mutation && !['create_directory','start_process','force_terminate','kill_process','interact_with_process','host_exec'].includes(name) && !('expected_sha256' in args) && !('expected_source_identity' in args)) throw new Error('mutation requires an explicit precondition');
|
|
62
|
-
if(
|
|
90
|
+
if(name==='host_exec') validateHostExecRequest(args);
|
|
63
91
|
return Object.freeze({commander_tool:name,native_tool:c.native,mutation:c.mutation,args});
|
|
64
92
|
}
|
|
65
93
|
|
package/src/deadbyte-cli.mjs
CHANGED
|
@@ -11,9 +11,12 @@ import { defaultPublicKeyPath } from './trust.mjs';
|
|
|
11
11
|
import { verifyAuditChain } from './audit-verify.mjs';
|
|
12
12
|
import { openRemoteResultJournal, parseRemoteResultCursor } from './remote-result-journal.mjs';
|
|
13
13
|
import { DEADBYTE_VERSION } from './version.mjs';
|
|
14
|
+
import { runNativeInspect } from './native-inspector-r67.mjs';
|
|
15
|
+
import { exportOfflineDiagnostics } from './r67-diagnostic-export.mjs';
|
|
16
|
+
import { verifyOfflineDiagnosticsZip } from './r67-diagnostics-verify.mjs';
|
|
14
17
|
import { parseActivePointer } from './release-slot.mjs';
|
|
15
18
|
import { printDoctor } from './doctor-r45.mjs';
|
|
16
|
-
import { createLiveTimelineFilter, createLiveTimelineTracker, createLiveTimelineWriter, formatCompactAuditEvent, formatRemoteLifecycle, formatRemoteToolCall, formatRuntimeDiagnosticLine, selectLiveLogNames } from './remote-live-log.mjs';
|
|
19
|
+
import { classifyRemoteAuditOutcome, createLiveTimelineFilter, createLiveTimelineTracker, createLiveTimelineWriter, formatCompactAuditEvent, formatRemoteLifecycle, formatRemoteToolCall, formatRuntimeDiagnosticLine, selectLiveLogNames } from './remote-live-log.mjs';
|
|
17
20
|
import { prepareRemoteConsole, remoteDisplayText } from './remote-console.mjs';
|
|
18
21
|
import { ensureRuntimeCoherence } from './runtime-coherence.mjs';
|
|
19
22
|
import { windowsPowerShellEnvironment } from './runtime-update.mjs';
|
|
@@ -60,7 +63,14 @@ function printHelp(){
|
|
|
60
63
|
` npx -y ${exact} supervisor status`,
|
|
61
64
|
` npx -y ${exact} supervisor recover`,
|
|
62
65
|
` npx -y ${exact} audit verify`,
|
|
63
|
-
` npx -y ${exact} audit status`,
|
|
66
|
+
` npx -y ${exact} audit status`,
|
|
67
|
+
` npx -y ${exact} diagnostics export --output <local.zip> # offline, never uploads`,
|
|
68
|
+
` npx -y ${exact} diagnostics verify --input <local.zip> # local structural/CRC verify`,
|
|
69
|
+
` npx -y ${exact} inspect process [limit] # local native process snapshot`,
|
|
70
|
+
` npx -y ${exact} inspect identity PID # native process creation token`,
|
|
71
|
+
` npx -y ${exact} inspect memory self [limit] # local VirtualQueryEx metadata only`,
|
|
72
|
+
` npx -y ${exact} inspect memory PID <creation_filetime> [limit] # PID-reuse guarded`,
|
|
73
|
+
` npx -y ${exact} inspect pe <file> # local native PE32/PE32+ inspection`,''
|
|
64
74
|
].join('\n'));
|
|
65
75
|
}
|
|
66
76
|
async function remoteContext(){
|
|
@@ -260,13 +270,15 @@ function auditTimelineRecord(file,line,auditEvent=null){
|
|
|
260
270
|
if(event.event_type==='tool.request') return {event_type:'tool.call',request_id:event.request_id,tool:event.tool,
|
|
261
271
|
observed_at_utc:observed,arguments:event.args??{},payload_sha256};
|
|
262
272
|
if(event.event_type==='tool.result'){
|
|
263
|
-
const
|
|
273
|
+
const classified=classifyRemoteAuditOutcome(event);
|
|
274
|
+
const unknown=classified==='unknown';
|
|
264
275
|
const recoveryReason=unknown&&typeof event.outcome?.recovery?.reason==='string'?event.outcome.recovery.reason:null;
|
|
265
276
|
return {event_type:'tool.result',request_id:event.request_id,tool:event.tool,
|
|
266
|
-
status:
|
|
277
|
+
status:classified==='pending'?'pending':classified==='ok'?'ok':'error',observed_at_utc:observed,payload_sha256,
|
|
267
278
|
...(Number.isFinite(Number(event.outcome?.duration_ms))?{duration_ms:Number(event.outcome.duration_ms)}:{}),
|
|
268
279
|
...(unknown?{side_effect_state:'unknown'}:{}),
|
|
269
|
-
...(typeof event.outcome?.reason==='string'&&event.outcome.reason?{reason:event.outcome.reason}:(recoveryReason?{reason:recoveryReason}:
|
|
280
|
+
...(typeof event.outcome?.reason==='string'&&event.outcome.reason?{reason:event.outcome.reason}:(recoveryReason?{reason:recoveryReason}:
|
|
281
|
+
(classified==='pending'&&typeof event.outcome?.status==='string'?{reason:event.outcome.status}:{})))};
|
|
270
282
|
}
|
|
271
283
|
return null;
|
|
272
284
|
}
|
|
@@ -286,9 +298,9 @@ async function replayRemoteResults(root,cursor,{displayMode='unicode'}={}){
|
|
|
286
298
|
continue;
|
|
287
299
|
}
|
|
288
300
|
const unknown=event.side_effect_state==='unknown';
|
|
289
|
-
const marker=unknown?'OUTCOME_UNKNOWN':event.status==='error'?(displayMode==='ascii'?'ERR':'✗'):(displayMode==='ascii'?'OK':'✓');
|
|
301
|
+
const marker=unknown?'OUTCOME_UNKNOWN':event.status==='pending'?'PENDING':event.status==='error'?(displayMode==='ascii'?'ERR':'✗'):(displayMode==='ascii'?'OK':'✓');
|
|
290
302
|
const duration=Number.isFinite(Number(event.duration_ms))?` ${event.duration_ms<1000?Math.round(event.duration_ms)+'ms':(event.duration_ms/1000).toFixed(2)+'s'}`:'';
|
|
291
|
-
const reason=(event.status==='error'||unknown)&&typeof event.reason==='string'&&event.reason?` — ${event.reason}`:'';
|
|
303
|
+
const reason=(event.status==='error'||event.status==='pending'||unknown)&&typeof event.reason==='string'&&event.reason?` — ${event.reason}`:'';
|
|
292
304
|
process.stdout.write(remoteDisplayText(`[REPLAY] #${event.seq} ${event.tool}${duration} ${marker}${reason}\n`,displayMode));
|
|
293
305
|
}
|
|
294
306
|
next=page.next_cursor;
|
|
@@ -681,6 +693,28 @@ async function main(argv){
|
|
|
681
693
|
if(command==='remote'){await runRemote(rest);return;}
|
|
682
694
|
if(command==='supervisor'){await runSupervisor(rest);return;}
|
|
683
695
|
if(command==='audit'){await runAudit(rest);return;}
|
|
696
|
+
if(command==='diagnostics'){
|
|
697
|
+
if(rest.length!==3)throw new Error('diagnostics export --output or verify --input; no network upload supported');
|
|
698
|
+
if(rest[0]==='export'&&rest[1]==='--output'){
|
|
699
|
+
const report=await exportOfflineDiagnostics({stateRoot:stateRoot(),outputPath:rest[2]});
|
|
700
|
+
process.stdout.write(`${JSON.stringify(report)}\n`);
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
if(rest[0]==='verify'&&rest[1]==='--input'){
|
|
704
|
+
const file=path.resolve(rest[2]);
|
|
705
|
+
await requireRegular(file,'diagnostic ZIP');
|
|
706
|
+
const report=verifyOfflineDiagnosticsZip(await readFile(file));
|
|
707
|
+
process.stdout.write(`${JSON.stringify(report)}\n`);
|
|
708
|
+
return;
|
|
709
|
+
}
|
|
710
|
+
throw new Error('unsupported diagnostics mode; network upload is forbidden');
|
|
711
|
+
}
|
|
712
|
+
if(command==='inspect'){
|
|
713
|
+
const result=await runNativeInspect(rest);
|
|
714
|
+
process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
715
|
+
if(result.status!=='ok')process.exitCode=2;
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
684
718
|
throw new Error(`unknown command '${command}'`);
|
|
685
719
|
}
|
|
686
720
|
|