deadbyte-mcp 0.15.24 → 0.15.26
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 +47 -37
- package/PROVENANCE.json +11 -11
- package/R49-PARENT.json +11 -0
- package/README.txt +16 -7
- package/RELEASE.json +15 -12
- package/SBOM.cdx.json +3 -3
- package/TEST-MATRIX.json +15 -12
- package/docs/R49-FULL-TOOL-CATALOG.json +13 -0
- package/docs/R49-REMOTE-CONTROL-DONORS.json +75 -0
- package/package.json +2 -2
- package/proof/commander-closure-20260928/DIFFERENTIAL-CHECKPOINT.json +17 -6
- package/scripts/commander-hardening-gate-r47.mjs +10 -1
- package/scripts/deferred-slot-operation-r46.mjs +44 -2
- package/scripts/gate-windows-r48.ps1 +45 -0
- package/scripts/gate-windows-r49.ps1 +54 -0
- package/scripts/init-host-policy.ps1 +9 -1
- package/scripts/npm-release-r48.mjs +2 -1
- package/scripts/windows-gate-evidence-r48.mjs +27 -0
- package/scripts/windows-gate-evidence-r49.mjs +27 -0
- package/src/autonomous-planner-contracts.mjs +1 -0
- package/src/autonomous-planner.mjs +11 -5
- package/src/autonomous-runtime.mjs +11 -1
- package/src/capability-ledger.mjs +1 -0
- package/src/commander-wire-adapter-r47.mjs +16 -0
- package/src/desktop-mcp-tools-r40.mjs +23 -1
- package/src/desktop-runtime-r40.mjs +46 -2
- package/src/machine-fs-smoke-client.mjs +6 -17
- package/src/mcp-host-smoke-client.mjs +3 -2
- package/src/mcp-smoke-client.mjs +4 -9
- package/src/observation-smoke-client.mjs +5 -10
- package/src/process-smoke-client.mjs +3 -3
- package/src/remote-mcp-smoke-client.mjs +7 -1
- package/src/runtime-catalog-expectation.mjs +45 -0
- package/src/tunnel-stdio-compat-smoke.mjs +5 -9
- package/src/version.mjs +1 -1
- package/test/autonomous-desktop-r40.test.mjs +27 -1
- package/test/coding-catalog-consistency.test.mjs +9 -1
- package/test/commander-real-parity-r47.test.mjs +8 -4
- package/test/contained.test.mjs +4 -6
- package/test/controller.test.mjs +2 -1
- package/test/desktop-mcp-tools-r40.test.mjs +19 -4
- package/test/desktop-runtime-r40.test.mjs +43 -2
- package/test/full-max-catalog-r48.test.mjs +5 -3
- package/test/r48-release-contract.test.mjs +14 -20
- package/test/r49-remote-control-donors.test.mjs +24 -0
- package/test/r49-windows-gate.test.mjs +33 -0
- package/test/remote-r24-catalog.test.mjs +9 -0
- package/test/tunnel-stdio-compat.test.mjs +4 -6
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": "deadbyte.r49-remote-control-donors.v1",
|
|
3
|
+
"observed_at_utc": "2026-09-30T00:40:00.000Z",
|
|
4
|
+
"rule": "Reimplement proven primitives natively; never import donor runtime authority or dependencies.",
|
|
5
|
+
"donors": [
|
|
6
|
+
{
|
|
7
|
+
"repository": "https://github.com/shahidx0x/better-remote-commander",
|
|
8
|
+
"commit": "eba57dd7f77cee98981bc7d95e59b8481ef1e309",
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"useful_primitives": ["heartbeat and stale-socket replacement", "bounded call correlation", "offline-stable tool metadata", "revocable device routing"],
|
|
11
|
+
"decision": "retain DEADBYTE identity-bound tunnel and authority planes; use the reconnect and stale-generation cases as adversarial test inputs"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"repository": "https://github.com/Jennifer9911/open-remote-mcp",
|
|
15
|
+
"commit": "fe9a7339f8fbb0040b9e10fcb0c4d040172d5c2a",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"useful_primitives": ["cloud policy may narrow but never broaden local authority", "device-code pairing", "realpath root enforcement", "persistent revocation audit"],
|
|
18
|
+
"decision": "already structurally stronger in DEADBYTE; preserve as release invariants and do not add a second pairing authority"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"repository": "https://github.com/Razewang/secure-host-mcp",
|
|
22
|
+
"commit": "200cb9474aa81b48ae79319dac63f689e6b351ee",
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"useful_primitives": ["bounded PTY ring offsets with explicit dropped bytes", "principal-owned jobs", "interrupted-not-survived recovery truth", "transactional structured patch rollback"],
|
|
25
|
+
"decision": "DEADBYTE already has stronger owned-session journals and unknown-effect semantics; use dropped-output and principal-substitution cases in compatibility gates"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"repository": "https://github.com/dddabtc/winremote-mcp",
|
|
29
|
+
"commit": "2185ee68428e76f29176291a2a862b1561468462",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"useful_primitives": ["task cancellation", "risk-tier catalog selection", "loopback-by-default remote binding", "annotated screenshot fallback ladder"],
|
|
32
|
+
"decision": "keep independent DEADBYTE authority planes instead of coarse tiers; retain cancellation and bind-target tests"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"repository": "https://github.com/getremcp/remcp",
|
|
36
|
+
"commit": "ce32908706686df85df4ca30fd26fc93719a4be4",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"useful_primitives": ["semantic wait_for_ui instead of fixed sleeps", "runtime crash restart", "catalog-first compact routing", "native UI then browser then OCR then coordinates ladder"],
|
|
39
|
+
"decision": "adopt bounded semantic Desktop wait natively without unrestricted mode, telemetry, or donor dependencies"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"repository": "https://github.com/trycua/cua",
|
|
43
|
+
"commit": "0f29c142d7fe3e05ea0ce276cee11b3a9725ba01",
|
|
44
|
+
"license": "MIT core with separately licensed optional components",
|
|
45
|
+
"useful_primitives": ["session-scoped stale references", "one action without blind retry", "typed action effect separate from postcondition", "fresh snapshot after action", "bounded semantic desktop and browser waits"],
|
|
46
|
+
"decision": "adopt only architecture semantics from MIT core documentation; do not import optional perception, model, AGPL, or CC assets"
|
|
47
|
+
}
|
|
48
|
+
],
|
|
49
|
+
"adopted_checkpoint": {
|
|
50
|
+
"capability": "desktop.wait",
|
|
51
|
+
"full_tool": "desktop_wait",
|
|
52
|
+
"compact_tool": "desktop_control",
|
|
53
|
+
"compact_op": "wait",
|
|
54
|
+
"authority": "none",
|
|
55
|
+
"properties": [
|
|
56
|
+
"strict closed input schema",
|
|
57
|
+
"baseline-frame binding",
|
|
58
|
+
"bounded timeout and poll interval",
|
|
59
|
+
"fresh observation on every attempt",
|
|
60
|
+
"optional local UIA predicate with query hash only",
|
|
61
|
+
"signed final observation receipt",
|
|
62
|
+
"no input dispatch and no action retry",
|
|
63
|
+
"autonomous goal ownership check for baseline frame"
|
|
64
|
+
]
|
|
65
|
+
},
|
|
66
|
+
"explicit_non_adoptions": [
|
|
67
|
+
"generic shell or caller-selected executable authority",
|
|
68
|
+
"unrestricted or god mode",
|
|
69
|
+
"coarse risk tiers replacing independent authority planes",
|
|
70
|
+
"telemetry or donor-hosted control plane",
|
|
71
|
+
"raw coordinates derived from stale observations",
|
|
72
|
+
"automatic action retry",
|
|
73
|
+
"optional CUA perception or model artifacts"
|
|
74
|
+
]
|
|
75
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "deadbyte-mcp",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.26",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Authenticated MCP agentic runtime with signed skills, persistent model backends, identity-bound remote devices, durable job supervision, immutable release slots, and separately revocable machine authority.",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"contained:run": "node src/contained-cli.mjs workspaces/demo input.txt",
|
|
43
43
|
"contained:smoke": "node src/contained-smoke.mjs",
|
|
44
44
|
"mcp:contained:smoke": "node src/mcp-contained-smoke-client.mjs",
|
|
45
|
-
|
|
45
|
+
"gate:windows": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/gate-windows-r49.ps1",
|
|
46
46
|
"authority:smoke": "node src/authority-smoke.mjs",
|
|
47
47
|
"mcp:remote:smoke": "node src/remote-mcp-smoke-client.mjs",
|
|
48
48
|
"mcp:host:smoke": "node src/mcp-host-smoke-client.mjs",
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "deadbyte.commander-differential-checkpoint.v1",
|
|
3
3
|
"status": "INCOMPLETE",
|
|
4
|
-
"observed_at_utc": "2026-09-
|
|
4
|
+
"observed_at_utc": "2026-09-29T13:36:00.000Z",
|
|
5
5
|
"source": {
|
|
6
6
|
"requested_path": "D:\\Projects\\deadbyte-mcp-r36-dev",
|
|
7
7
|
"requested_path_version": "0.12.0",
|
|
8
8
|
"actual_successor_workspace": "D:\\Projects\\deadbyte-mcp\\development\\deadbyte-mcp-r42-agentic-dev",
|
|
9
|
-
"version": "0.15.
|
|
9
|
+
"version": "0.15.25",
|
|
10
10
|
"git_head": "f9037d4847a7204ce4e1f808758ee3f0e9e7a738",
|
|
11
11
|
"path_drift_classification": "requested source path is a historical snapshot and cannot produce a successor of active 0.15.23"
|
|
12
12
|
},
|
|
@@ -62,6 +62,12 @@
|
|
|
62
62
|
"classification": "REAL_DEADBYTE_DEFECT_FIXED_IN_SOURCE",
|
|
63
63
|
"red": "reference exposes drawing markers, header/footer text, and literal DOCX part search while DEADBYTE omitted those document parts and searched ZIP bytes",
|
|
64
64
|
"green": "native bounded DOCX parsing now exposes drawing/header/footer evidence and searches document/header/footer w:t parts through deterministic compatibility sessions"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"id": "interactive-output-quiescence",
|
|
68
|
+
"classification": "REAL_DEADBYTE_DEFECT_FIXED_IN_SOURCE",
|
|
69
|
+
"red": "interact_with_process returned after the first stream advance and could omit the final END marker from a 1.1 MiB response",
|
|
70
|
+
"green": "bounded stream-quiescence waiting plus unconditional test cleanup passed 20 consecutive real PowerShell repetitions and the expanded 139-test hardening gate"
|
|
65
71
|
}
|
|
66
72
|
],
|
|
67
73
|
"focused_evidence": [
|
|
@@ -73,6 +79,8 @@
|
|
|
73
79
|
{"scope": "mcp-protocol-adversarial", "tests": 3, "pass": 3, "fail": 0, "skip": 0},
|
|
74
80
|
{"scope": "atomic-mutation-public-boundaries", "tests": 15, "pass": 14, "fail": 0, "skip": 1},
|
|
75
81
|
{"scope": "full-regression-r48", "files": 211, "batches": 8, "fail": 0, "task_receipt_sha256": "7711039e4807f6c2af02bbda897d0032b067e0a6631f789fd3bf801258160d3f"},
|
|
82
|
+
{"scope": "expanded-commander-hardening", "tests": 139, "pass": 139, "fail": 0, "skip": 0},
|
|
83
|
+
{"scope": "powershell-large-output-repeat", "runs": 20, "pass": 20, "fail": 0},
|
|
76
84
|
{"scope": "npm-audit-production", "vulnerabilities": 0},
|
|
77
85
|
{"scope": "real-performance-sample", "iterations_per_workload": 50, "reference_byte_pins_verified": true, "status": "HISTORICAL_ONLY_FRESH_RUN_BLOCKED_REFERENCE_RUNTIME_DEPS",
|
|
78
86
|
"results": {"read_file": {"reference_ops_per_sec": 55, "deadbyte_ops_per_sec": 1058}, "list_directory": {"reference_ops_per_sec": 3818, "deadbyte_ops_per_sec": 1959}, "get_file_info": {"reference_ops_per_sec": 1805, "deadbyte_ops_per_sec": 2231}, "read_multiple_files": {"reference_ops_per_sec": 30, "deadbyte_ops_per_sec": 562}}}
|
|
@@ -81,12 +89,12 @@
|
|
|
81
89
|
"changed_file_sha256": {
|
|
82
90
|
"src/commander-pdf-r48.mjs": "23cda18e86daa4163003fb5a80e0069bc19541d454f32a9a38b1d901ee39f26b",
|
|
83
91
|
"src/coding-search.mjs": "7f15b59bc240d896beddc2057354f8c72f296fe189db30c200d2c84a67d65773",
|
|
84
|
-
"src/commander-wire-adapter-r47.mjs": "
|
|
92
|
+
"src/commander-wire-adapter-r47.mjs": "a32226e302669553d39565176fc7ef9a0ace24834d2c19d3558ba33f13016ba0",
|
|
85
93
|
"src/commander-office-reader-r48.mjs": "7379825118da8fae16d63fe7c4d89b0ddb03e7649f3754adae58a4480f8b317f",
|
|
86
94
|
"test/commander-pdf-r48.test.mjs": "bfc2e6d7e1aa5332c1c81687001cdb5f923a45c5ce64925097fe11fd850e9214",
|
|
87
95
|
"test/commander-biff-reference-r48.test.mjs": "8e8b20604062a0398214e159729b10bedff334cb44bddfa4b4046b1ae396520f",
|
|
88
96
|
"test/commander-schema-differential-r48.test.mjs": "fb82a21e8752ccb82cbd6b631f3366bfe5af9a4c5a433db5a128c0a1fe703c66",
|
|
89
|
-
"test/commander-real-parity-r47.test.mjs": "
|
|
97
|
+
"test/commander-real-parity-r47.test.mjs": "5709ea1cf4e65c4f1759206123216cac6cb66d8a383c0b0a6c00f4a551d9c727"
|
|
90
98
|
,"test/commander-wire-contract-r47.test.mjs": "d8e884e241c705b12797f911fb967a4a33b1ec6f3e15b433735882b3de4a34e5"
|
|
91
99
|
,"test/commander-office-reader-r48.test.mjs": "abf1eb0977a064101420a0e908a4c2adbf9d606e9873433709910efafa2b4453"
|
|
92
100
|
,"test/commander-core-bridge-r47.test.mjs": "16092ed097420b9da99573c1e84f62d011fcb5db069242d70ffd1649c704fd35"
|
|
@@ -101,10 +109,13 @@
|
|
|
101
109
|
,"test/atomic-mutation.test.mjs": "98de1fc43092c27e0fa85f391607494b11e6cc0d53eaf47b6db1ab457c6d6a4b"
|
|
102
110
|
,"test/coding-mcp-unknown-effect.test.mjs": "f37e260c2def4c48434b3f251a4cb756a1852843784c08cf6c39dba9045dfb69"
|
|
103
111
|
,"scripts/commander-real-performance-benchmark-r47.mjs": "d7806aa408dc7ca74f05feec535ad6cc545f8c61892c51f0fe388bb13d975290"
|
|
112
|
+
,"scripts/commander-hardening-gate-r47.mjs": "6d6e18b2a17448dad569dfbf60ac103c6c8bcfe73c49af93506816c3c0b7fe73"
|
|
113
|
+
,"src/stdio-protocol-guard.mjs": "71e0ddc5e7abaedbb4659bdfb91b6e2db43a642cbec83eee62c16fb069a3c202"
|
|
114
|
+
,"test/commander-protocol-adversarial-r48.test.mjs": "bacb96828ea0431cd5f3a8ecb637894f0bdf80b5f52e9308ba0cbb982f50bd2a"
|
|
104
115
|
},
|
|
105
116
|
"release_created": true,
|
|
106
|
-
"candidate_version": "0.15.
|
|
107
|
-
"publish_attempt": {"status":"
|
|
117
|
+
"candidate_version": "0.15.25",
|
|
118
|
+
"publish_attempt": {"status":"PENDING_AUTH","npm_whoami":"E401 Unauthorized","registry_predecessor_version":"0.15.24","registry_predecessor_tarball_sha256":"23ea53fb4f331873c742c810f815d5ad18291f74c1bda1fd1d8c08475dbbd4ad"},
|
|
108
119
|
"published": false,
|
|
109
120
|
"activated": false,
|
|
110
121
|
"remaining_scope": "restore npm authentication, registry round-trip, successor activation, exact 0.15.23 rollback, exact successor restore and independent final closure"
|
|
@@ -13,7 +13,16 @@ const suites = [
|
|
|
13
13
|
'test/commander-exhaustive-surface-r47.test.mjs',
|
|
14
14
|
'test/commander-core-bridge-r47.test.mjs',
|
|
15
15
|
'test/commander-wire-contract-r47.test.mjs',
|
|
16
|
-
'test/commander-
|
|
16
|
+
'test/commander-reference-contract-r48.test.mjs',
|
|
17
|
+
'test/commander-schema-differential-r48.test.mjs',
|
|
18
|
+
'test/commander-biff-reference-r48.test.mjs',
|
|
19
|
+
'test/commander-office-reader-r48.test.mjs',
|
|
20
|
+
'test/commander-pdf-r48.test.mjs',
|
|
21
|
+
'test/commander-url-reader-r48.test.mjs',
|
|
22
|
+
'test/commander-external-process-r48.test.mjs',
|
|
23
|
+
'test/commander-protocol-r47.test.mjs',
|
|
24
|
+
'test/commander-protocol-adversarial-r48.test.mjs',
|
|
25
|
+
'test/prompts-resources.test.mjs'
|
|
17
26
|
];
|
|
18
27
|
|
|
19
28
|
const startedAt = new Date().toISOString();
|
|
@@ -14,6 +14,10 @@ const packageRoot=path.resolve(here,'..');
|
|
|
14
14
|
const stateRoot=path.resolve(process.env.DEADBYTE_STATE_ROOT||path.join(os.homedir(),'.deadbyte-mcp'));
|
|
15
15
|
const evidenceRoot=path.join(stateRoot,'evidence','deferred-slot-operations');
|
|
16
16
|
const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
17
|
+
const sleep=ms=>new Promise(resolve=>setTimeout(resolve,ms));
|
|
18
|
+
const packageIdentity=JSON.parse(await readFile(path.join(packageRoot,'package.json'),'utf8'));
|
|
19
|
+
if(packageIdentity?.name!=='deadbyte-mcp'||!/^[0-9]+\.[0-9]+\.[0-9]+$/.test(packageIdentity?.version??'')) throw new Error('deferred updater package identity invalid');
|
|
20
|
+
const expectedVersion=packageIdentity.version;
|
|
17
21
|
const atomicJson=async(file,value)=>{
|
|
18
22
|
await mkdir(path.dirname(file),{recursive:true});
|
|
19
23
|
const temp=`${file}.${process.pid}.${randomBytes(4).toString('hex')}.tmp`;
|
|
@@ -22,7 +26,7 @@ const atomicJson=async(file,value)=>{
|
|
|
22
26
|
};
|
|
23
27
|
function activationArgs(manifestSha){
|
|
24
28
|
if(!HEX64.test(manifestSha??'')) throw new Error('activate requires one lowercase manifest SHA-256');
|
|
25
|
-
return ['--stage',packageRoot,'--development-root',packageRoot,'--expected-version',
|
|
29
|
+
return ['--stage',packageRoot,'--development-root',packageRoot,'--expected-version',expectedVersion,
|
|
26
30
|
'--expected-manifest',manifestSha,'--process-policy',path.join(packageRoot,'controller','deadbyte-process-policy.json'),
|
|
27
31
|
'--process-policy-sha256',null,'--desktop-policy',path.join(packageRoot,'controller','deadbyte-desktop-policy.json'),
|
|
28
32
|
'--desktop-policy-sha256',null,'--semantic-lsp-config',path.join(packageRoot,'controller','deadbyte-semantic-lsp-config.json'),
|
|
@@ -81,6 +85,44 @@ async function normalizedArgs(mode,value,{explicitBridgeRoot=null,explicitBridge
|
|
|
81
85
|
}
|
|
82
86
|
throw new Error("operation must be exactly 'activate' or 'rollback'");
|
|
83
87
|
}
|
|
88
|
+
async function awaitHandoffCompletion(result,{timeoutMs=900000,pollMs=1000}={}){
|
|
89
|
+
if(result?.handed_off!==true) return result;
|
|
90
|
+
if(typeof result.handoff_path!=='string'||!path.isAbsolute(result.handoff_path)) throw new Error('slot activation handoff path invalid');
|
|
91
|
+
const evidenceDir=path.dirname(result.handoff_path);
|
|
92
|
+
const receiptPath=path.join(evidenceDir,'receipt.json');
|
|
93
|
+
const failurePath=path.join(evidenceDir,'failure-receipt.json');
|
|
94
|
+
const expected=result.pointer;
|
|
95
|
+
const publicKey=createPublicKey(await readFile(path.join(stateRoot,'trust','ed25519-public.pem')));
|
|
96
|
+
const deadline=Date.now()+timeoutMs;
|
|
97
|
+
while(Date.now()<deadline){
|
|
98
|
+
try{
|
|
99
|
+
const envelope=JSON.parse(await readFile(receiptPath,'utf8'));
|
|
100
|
+
if(!verifySlotUpdateEnvelope(envelope,publicKey)) throw new Error('activation receipt signature invalid');
|
|
101
|
+
const body=envelope.body,active=body?.active_pointer;
|
|
102
|
+
if(body?.schema!=='deadbyte.r27-slot-update-receipt.v1'||body?.rollback_performed!==false) throw new Error('activation receipt semantics invalid');
|
|
103
|
+
if(active?.release_id!==expected?.release_id||active?.version!==expected?.version||active?.manifest_sha256!==expected?.manifest_sha256||active?.generation_root!==expected?.generation_root) {
|
|
104
|
+
throw new Error('activation receipt target mismatch');
|
|
105
|
+
}
|
|
106
|
+
parseActivePointer(JSON.stringify(active));
|
|
107
|
+
const pointer=parseActivePointer(await readFile(path.join(stateRoot,'active-release.json'),'utf8'));
|
|
108
|
+
if(pointer.release_id!==active.release_id||pointer.generation_root!==active.generation_root||pointer.manifest_sha256!==active.manifest_sha256) {
|
|
109
|
+
throw new Error('active pointer does not match signed activation receipt');
|
|
110
|
+
}
|
|
111
|
+
return {receipt_path:receiptPath,receipt_sha256:envelope.receipt_sha256,pointer};
|
|
112
|
+
}catch(error){
|
|
113
|
+
if(error?.code!=='ENOENT') throw error;
|
|
114
|
+
}
|
|
115
|
+
try{
|
|
116
|
+
const failure=JSON.parse(await readFile(failurePath,'utf8'));
|
|
117
|
+
if(!verifySlotUpdateEnvelope(failure,publicKey)) throw new Error('activation failure receipt signature invalid');
|
|
118
|
+
throw new Error(`slot activation failed: ${failure.body?.error?.message??'failure receipt emitted'}`);
|
|
119
|
+
}catch(error){
|
|
120
|
+
if(error?.code!=='ENOENT') throw error;
|
|
121
|
+
}
|
|
122
|
+
await sleep(pollMs);
|
|
123
|
+
}
|
|
124
|
+
throw new Error(`slot activation timed out after ${timeoutMs}ms`);
|
|
125
|
+
}
|
|
84
126
|
const rawArgs=process.argv.slice(2);
|
|
85
127
|
const mode=rawArgs[0],value=rawArgs[1];
|
|
86
128
|
if(!value||!['activate','rollback'].includes(mode)) throw new Error('usage: deferred-slot-operation-r46.mjs <activate manifest_sha256|rollback activation_receipt> [--bridge-root ABS --bridge-script-sha256 HEX64]');
|
|
@@ -102,7 +144,7 @@ if(workerFlag==='--worker'){
|
|
|
102
144
|
await atomicJson(statePath,{schema:'deadbyte.deferred-slot-operation.v1',operation_id:operationIdArg,mode,state:'running',started_at_utc:new Date().toISOString(),bridge_root:explicitBridgeRoot,bridge_script_sha256:explicitBridgeSha256});
|
|
103
145
|
try{
|
|
104
146
|
const args=await normalizedArgs(mode,value,{explicitBridgeRoot,explicitBridgeSha256});
|
|
105
|
-
const result=await runSlotUpdateCli(args,{stateRoot});
|
|
147
|
+
const result=await awaitHandoffCompletion(await runSlotUpdateCli(args,{stateRoot}));
|
|
106
148
|
await atomicJson(statePath,{schema:'deadbyte.deferred-slot-operation.v1',operation_id:operationIdArg,mode,state:'completed',
|
|
107
149
|
completed_at_utc:new Date().toISOString(),receipt_path:result.receipt_path,receipt_sha256:result.receipt_sha256,
|
|
108
150
|
active_release:result.pointer.release_id,generation_root:result.pointer.generation_root,bridge_root:explicitBridgeRoot,bridge_script_sha256:explicitBridgeSha256});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
$ErrorActionPreference = 'Stop'
|
|
2
|
+
Set-StrictMode -Version 3.0
|
|
3
|
+
|
|
4
|
+
function Invoke-GateStep {
|
|
5
|
+
param([Parameter(Mandatory)][string]$Name,[Parameter(Mandatory)][string[]]$NpmArgs)
|
|
6
|
+
Write-Host "==== $Name ===="
|
|
7
|
+
& npm.cmd @NpmArgs
|
|
8
|
+
if ($LASTEXITCODE -ne 0) { throw "DEADBYTE 0.15.25 / R48 gate failed at $Name with exit code $LASTEXITCODE" }
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
Invoke-GateStep 'containment-build' @('run','containment:build')
|
|
12
|
+
Invoke-GateStep 'process-policy-refresh' @('run','process:policy:refresh')
|
|
13
|
+
Invoke-GateStep 'desktop-policy-refresh' @('run','desktop:policy:refresh')
|
|
14
|
+
Invoke-GateStep 'hardware-build' @('run','hardware:build')
|
|
15
|
+
|
|
16
|
+
$hostPolicy = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\controller\deadbyte-host-policy.json'))
|
|
17
|
+
Remove-Item -LiteralPath $hostPolicy -Force -ErrorAction SilentlyContinue
|
|
18
|
+
if (Test-Path -LiteralPath $hostPolicy) { throw 'could not establish hermetic Host policy absence' }
|
|
19
|
+
|
|
20
|
+
Invoke-GateStep 'r48-release-focused' @('run','r48:release:test')
|
|
21
|
+
Invoke-GateStep 'r48-catalog' @('run','r48:catalog:test')
|
|
22
|
+
Invoke-GateStep 'commander-hardening' @('run','r47:hardening:test')
|
|
23
|
+
Invoke-GateStep 'full-regression' @('run','r48:full:test')
|
|
24
|
+
Invoke-GateStep 'mcp-smoke' @('run','mcp:smoke')
|
|
25
|
+
Invoke-GateStep 'mcp-agent-smoke' @('run','mcp:agent:smoke')
|
|
26
|
+
Invoke-GateStep 'mcp-coding-smoke' @('run','mcp:coding:smoke')
|
|
27
|
+
Invoke-GateStep 'mcp-machine-fs-smoke' @('run','mcp:machine-fs:smoke')
|
|
28
|
+
Invoke-GateStep 'mcp-observation-smoke' @('run','mcp:observation:smoke')
|
|
29
|
+
Invoke-GateStep 'mcp-process-smoke' @('run','mcp:process:smoke')
|
|
30
|
+
Invoke-GateStep 'mcp-autonomous-smoke' @('run','mcp:autonomous:smoke')
|
|
31
|
+
Invoke-GateStep 'tunnel-stdio-compat-smoke' @('run','mcp:tunnel-compat:smoke')
|
|
32
|
+
Invoke-GateStep 'containment-smoke' @('run','containment:smoke')
|
|
33
|
+
Invoke-GateStep 'contained-smoke' @('run','contained:smoke')
|
|
34
|
+
Invoke-GateStep 'mcp-contained-smoke' @('run','mcp:contained:smoke')
|
|
35
|
+
Invoke-GateStep 'host-policy-refresh' @('run','host:policy:init')
|
|
36
|
+
Invoke-GateStep 'manifest-write' @('run','manifest:write')
|
|
37
|
+
Invoke-GateStep 'manifest-verify' @('run','manifest:verify')
|
|
38
|
+
Invoke-GateStep 'doctor' @('run','doctor')
|
|
39
|
+
Invoke-GateStep 'mcp-host-smoke' @('run','mcp:host:smoke')
|
|
40
|
+
Invoke-GateStep 'authority-smoke' @('run','authority:smoke')
|
|
41
|
+
Invoke-GateStep 'manifest-final-verify' @('run','manifest:verify')
|
|
42
|
+
|
|
43
|
+
& node.exe (Join-Path $PSScriptRoot 'windows-gate-evidence-r48.mjs')
|
|
44
|
+
if ($LASTEXITCODE -ne 0) { throw "R48 evidence writer failed with exit code $LASTEXITCODE" }
|
|
45
|
+
Write-Host '==== DEADBYTE 0.15.25 / R48 WINDOWS GATE: PASS ===='
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
$ErrorActionPreference = 'Stop'
|
|
2
|
+
Set-StrictMode -Version 3.0
|
|
3
|
+
|
|
4
|
+
function Invoke-GateStep {
|
|
5
|
+
param([Parameter(Mandatory)][string]$Name,[Parameter(Mandatory)][string[]]$NpmArgs)
|
|
6
|
+
Write-Host "==== $Name ===="
|
|
7
|
+
& npm.cmd @NpmArgs
|
|
8
|
+
if ($LASTEXITCODE -ne 0) { throw "DEADBYTE 0.15.26 / R49 gate failed at $Name with exit code $LASTEXITCODE" }
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function Invoke-NodeTest {
|
|
12
|
+
param([Parameter(Mandatory)][string]$Name,[Parameter(Mandatory)][string[]]$TestFiles)
|
|
13
|
+
Write-Host "==== $Name ===="
|
|
14
|
+
& node.exe --test --test-concurrency=1 @TestFiles
|
|
15
|
+
if ($LASTEXITCODE -ne 0) { throw "DEADBYTE 0.15.26 / R49 gate failed at $Name with exit code $LASTEXITCODE" }
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
Invoke-GateStep 'containment-build' @('run','containment:build')
|
|
19
|
+
Invoke-GateStep 'process-policy-refresh' @('run','process:policy:refresh')
|
|
20
|
+
Invoke-GateStep 'desktop-policy-refresh' @('run','desktop:policy:refresh')
|
|
21
|
+
Invoke-GateStep 'hardware-build' @('run','hardware:build')
|
|
22
|
+
|
|
23
|
+
$hostPolicy = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\controller\deadbyte-host-policy.json'))
|
|
24
|
+
Remove-Item -LiteralPath $hostPolicy -Force -ErrorAction SilentlyContinue
|
|
25
|
+
if (Test-Path -LiteralPath $hostPolicy) { throw 'could not establish hermetic Host policy absence' }
|
|
26
|
+
|
|
27
|
+
Invoke-GateStep 'r49-release-focused' @('run','r48:release:test')
|
|
28
|
+
Invoke-NodeTest 'r49-donor-proof' @('test/r49-remote-control-donors.test.mjs')
|
|
29
|
+
Invoke-NodeTest 'r49-desktop-wait' @('test/desktop-runtime-r40.test.mjs','test/desktop-mcp-tools-r40.test.mjs','test/autonomous-desktop-r40.test.mjs')
|
|
30
|
+
Invoke-GateStep 'r49-catalog' @('run','r48:catalog:test')
|
|
31
|
+
Invoke-GateStep 'commander-hardening' @('run','r47:hardening:test')
|
|
32
|
+
Invoke-GateStep 'full-regression' @('run','r48:full:test')
|
|
33
|
+
Invoke-GateStep 'mcp-smoke' @('run','mcp:smoke')
|
|
34
|
+
Invoke-GateStep 'mcp-agent-smoke' @('run','mcp:agent:smoke')
|
|
35
|
+
Invoke-GateStep 'mcp-coding-smoke' @('run','mcp:coding:smoke')
|
|
36
|
+
Invoke-GateStep 'mcp-machine-fs-smoke' @('run','mcp:machine-fs:smoke')
|
|
37
|
+
Invoke-GateStep 'mcp-observation-smoke' @('run','mcp:observation:smoke')
|
|
38
|
+
Invoke-GateStep 'mcp-process-smoke' @('run','mcp:process:smoke')
|
|
39
|
+
Invoke-GateStep 'mcp-autonomous-smoke' @('run','mcp:autonomous:smoke')
|
|
40
|
+
Invoke-GateStep 'tunnel-stdio-compat-smoke' @('run','mcp:tunnel-compat:smoke')
|
|
41
|
+
Invoke-GateStep 'containment-smoke' @('run','containment:smoke')
|
|
42
|
+
Invoke-GateStep 'contained-smoke' @('run','contained:smoke')
|
|
43
|
+
Invoke-GateStep 'mcp-contained-smoke' @('run','mcp:contained:smoke')
|
|
44
|
+
Invoke-GateStep 'host-policy-refresh' @('run','host:policy:init')
|
|
45
|
+
Invoke-GateStep 'manifest-write' @('run','manifest:write')
|
|
46
|
+
Invoke-GateStep 'manifest-verify' @('run','manifest:verify')
|
|
47
|
+
Invoke-GateStep 'doctor' @('run','doctor')
|
|
48
|
+
Invoke-GateStep 'mcp-host-smoke' @('run','mcp:host:smoke')
|
|
49
|
+
Invoke-GateStep 'authority-smoke' @('run','authority:smoke')
|
|
50
|
+
Invoke-GateStep 'manifest-final-verify' @('run','manifest:verify')
|
|
51
|
+
|
|
52
|
+
& node.exe (Join-Path $PSScriptRoot 'windows-gate-evidence-r49.mjs')
|
|
53
|
+
if ($LASTEXITCODE -ne 0) { throw "R49 evidence writer failed with exit code $LASTEXITCODE" }
|
|
54
|
+
Write-Host '==== DEADBYTE 0.15.26 / R49 WINDOWS GATE: PASS ===='
|
|
@@ -10,7 +10,15 @@ Set-StrictMode -Version 3.0
|
|
|
10
10
|
$ErrorActionPreference = 'Stop'
|
|
11
11
|
|
|
12
12
|
function Get-Sha256Lower([string]$Path) {
|
|
13
|
-
|
|
13
|
+
$stream = [System.IO.File]::OpenRead($Path)
|
|
14
|
+
try {
|
|
15
|
+
$sha = [System.Security.Cryptography.SHA256]::Create()
|
|
16
|
+
try {
|
|
17
|
+
([System.BitConverter]::ToString($sha.ComputeHash($stream))).Replace('-', '').ToLowerInvariant()
|
|
18
|
+
}
|
|
19
|
+
finally { $sha.Dispose() }
|
|
20
|
+
}
|
|
21
|
+
finally { $stream.Dispose() }
|
|
14
22
|
}
|
|
15
23
|
|
|
16
24
|
if ([string]::IsNullOrWhiteSpace($CoreRoot)) {
|
|
@@ -105,7 +105,8 @@ async function main() {
|
|
|
105
105
|
|
|
106
106
|
console.log('[3/7] Packing artifact with npm pack...');
|
|
107
107
|
const packed = parseJson(runNpm(['pack', '--json'], { timeout: 180000 }));
|
|
108
|
-
const
|
|
108
|
+
const packRecord = Array.isArray(packed) ? packed[0] : packed?.[pkg.name];
|
|
109
|
+
const filename = packRecord?.filename;
|
|
109
110
|
if (!filename) throw new Error('npm pack did not return a tarball filename');
|
|
110
111
|
const tarball = path.join(root, filename);
|
|
111
112
|
let releaseSucceeded = false;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {createHash} from 'node:crypto';
|
|
2
|
+
import {mkdir,open,readFile} from 'node:fs/promises';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import {fileURLToPath} from 'node:url';
|
|
6
|
+
import {doctor} from '../src/doctor-r45.mjs';
|
|
7
|
+
|
|
8
|
+
const root=path.resolve(path.dirname(fileURLToPath(import.meta.url)),'..');
|
|
9
|
+
const stateRoot=path.resolve(process.env.DEADBYTE_STATE_ROOT||path.join(os.homedir(),'.deadbyte-mcp'));
|
|
10
|
+
const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
11
|
+
const insist=(ok,message)=>{if(!ok)throw new Error(message);};
|
|
12
|
+
const pkg=JSON.parse(await readFile(path.join(root,'package.json'),'utf8'));
|
|
13
|
+
const release=JSON.parse(await readFile(path.join(root,'RELEASE.json'),'utf8'));
|
|
14
|
+
const active=JSON.parse(await readFile(path.join(stateRoot,'active-release.json'),'utf8'));
|
|
15
|
+
const manifestSha256=sha256(await readFile(path.join(root,'MANIFEST.SHA256')));
|
|
16
|
+
insist(pkg.version==='0.15.25'&&release.version===pkg.version&&release.train==='R48','R48 candidate identity mismatch');
|
|
17
|
+
insist(active.release_id===release.parent.release_id&&active.manifest_sha256===release.parent.manifest_sha256&&active.generation_manifest_sha256===release.parent.generation_manifest_sha256,'active runtime is not the exact sealed R48 parent');
|
|
18
|
+
const health=await doctor();
|
|
19
|
+
insist(health.status==='ok'&&health.package_version===pkg.version&&health.manifest?.verified===true,'R48 doctor evidence invalid');
|
|
20
|
+
insist(health.policy?.host_v2_ready===true,'R48 Host policy v2 is not ready');
|
|
21
|
+
const evidence={schema:'deadbyte.r48-windows-gate.v1',status:'passed',exit_code:0,version:pkg.version,train:'R48',completed_at_utc:new Date().toISOString(),manifest_sha256:manifestSha256,parent:release.parent,active_predecessor:{release_id:active.release_id,version:active.version,manifest_sha256:active.manifest_sha256,generation_manifest_sha256:active.generation_manifest_sha256},doctor:{verified_entries:health.manifest.verified_entries,host_v2_ready:true},gates:{full_regression:true,commander_hardening:true,exact_catalog:true,stdio_smokes:true,manifest_final_verify:true}};
|
|
22
|
+
const bytes=Buffer.from(`${JSON.stringify(evidence,null,2)}\n`);
|
|
23
|
+
const dir=path.join(stateRoot,'evidence','release'); await mkdir(dir,{recursive:true});
|
|
24
|
+
const target=path.join(dir,`r48-windows-gate-${manifestSha256.slice(0,16)}.json`);
|
|
25
|
+
try{const handle=await open(target,'wx',0o600);try{await handle.writeFile(bytes);await handle.sync();}finally{await handle.close();}}
|
|
26
|
+
catch(error){if(error?.code!=='EEXIST')throw error;const prior=JSON.parse(await readFile(target,'utf8'));insist(prior.schema===evidence.schema&&prior.status==='passed'&&prior.version===evidence.version&&prior.manifest_sha256===manifestSha256&&prior.parent?.release_id===release.parent.release_id,'conflicting R48 gate evidence identity');}
|
|
27
|
+
console.log(JSON.stringify({status:'passed',path:target,sha256:sha256(bytes),manifest_sha256:manifestSha256}));
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {createHash} from 'node:crypto';
|
|
2
|
+
import {mkdir,open,readFile} from 'node:fs/promises';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import {fileURLToPath} from 'node:url';
|
|
6
|
+
import {doctor} from '../src/doctor-r45.mjs';
|
|
7
|
+
|
|
8
|
+
const root=path.resolve(path.dirname(fileURLToPath(import.meta.url)),'..');
|
|
9
|
+
const stateRoot=path.resolve(process.env.DEADBYTE_STATE_ROOT||path.join(os.homedir(),'.deadbyte-mcp'));
|
|
10
|
+
const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
11
|
+
const insist=(ok,message)=>{if(!ok)throw new Error(message);};
|
|
12
|
+
const pkg=JSON.parse(await readFile(path.join(root,'package.json'),'utf8'));
|
|
13
|
+
const release=JSON.parse(await readFile(path.join(root,'RELEASE.json'),'utf8'));
|
|
14
|
+
const active=JSON.parse(await readFile(path.join(stateRoot,'active-release.json'),'utf8'));
|
|
15
|
+
const manifestSha256=sha256(await readFile(path.join(root,'MANIFEST.SHA256')));
|
|
16
|
+
insist(pkg.version==='0.15.26'&&release.version===pkg.version&&release.train==='R49','R49 candidate identity mismatch');
|
|
17
|
+
insist(active.release_id===release.parent.release_id&&active.manifest_sha256===release.parent.manifest_sha256&&active.generation_manifest_sha256===release.parent.generation_manifest_sha256,'active runtime is not the exact sealed R49 parent');
|
|
18
|
+
const health=await doctor();
|
|
19
|
+
insist(health.status==='ok'&&health.package_version===pkg.version&&health.manifest?.verified===true,'R49 doctor evidence invalid');
|
|
20
|
+
insist(health.policy?.host_v2_ready===true,'R49 Host policy v2 is not ready');
|
|
21
|
+
const evidence={schema:'deadbyte.r49-windows-gate.v1',status:'passed',exit_code:0,version:pkg.version,train:'R49',completed_at_utc:new Date().toISOString(),manifest_sha256:manifestSha256,parent:release.parent,active_predecessor:{release_id:active.release_id,version:active.version,manifest_sha256:active.manifest_sha256,generation_manifest_sha256:active.generation_manifest_sha256},doctor:{verified_entries:health.manifest.verified_entries,host_v2_ready:true},gates:{full_regression:true,commander_hardening:true,donor_proof:true,desktop_wait:true,exact_catalog:true,stdio_smokes:true,manifest_final_verify:true}};
|
|
22
|
+
const bytes=Buffer.from(`${JSON.stringify(evidence,null,2)}\n`);
|
|
23
|
+
const dir=path.join(stateRoot,'evidence','release'); await mkdir(dir,{recursive:true});
|
|
24
|
+
const target=path.join(dir,`r49-windows-gate-${manifestSha256.slice(0,16)}.json`);
|
|
25
|
+
try{const handle=await open(target,'wx',0o600);try{await handle.writeFile(bytes);await handle.sync();}finally{await handle.close();}}
|
|
26
|
+
catch(error){if(error?.code!=='EEXIST')throw error;const prior=JSON.parse(await readFile(target,'utf8'));insist(prior.schema===evidence.schema&&prior.status==='passed'&&prior.version===evidence.version&&prior.manifest_sha256===manifestSha256&&prior.parent?.release_id===release.parent.release_id,'conflicting R49 gate evidence identity');}
|
|
27
|
+
console.log(JSON.stringify({status:'passed',path:target,sha256:sha256(bytes),manifest_sha256:manifestSha256}));
|
|
@@ -132,6 +132,7 @@ const r36TypedActionSchemas=[
|
|
|
132
132
|
z.strictObject({kind:z.literal('observation_system_status')}),
|
|
133
133
|
z.strictObject({kind:z.literal('desktop_status')}),
|
|
134
134
|
z.strictObject({kind:z.literal('desktop_observe')}),
|
|
135
|
+
z.strictObject({kind:z.literal('desktop_wait'),baseline_frame_id:z.string().regex(HEX64),until:z.enum(['frame_changed','topology_changed','foreground_changed','uia_present','uia_absent']),uia_query:plannerDesktopQuery.nullable().default(null),timeout_ms:z.number().int().min(100).max(30000).default(5000),poll_ms:z.number().int().min(50).max(1000).default(100)}),
|
|
135
136
|
z.strictObject({kind:z.literal('desktop_target'),frame_id:z.string().regex(HEX64),uia_query:plannerDesktopQuery}),
|
|
136
137
|
z.strictObject({
|
|
137
138
|
kind:z.literal('desktop_action'),action_kind:plannerDesktopActionKind,expected_frame_id:z.string().regex(HEX64),
|
|
@@ -134,11 +134,17 @@ function validateR36TypedAction(action) {
|
|
|
134
134
|
if (typeof action.destination_path === 'string') pathFields.push(action.destination_path);
|
|
135
135
|
for (const item of action.files ?? []) if (typeof item?.path === 'string') pathFields.push(item.path);
|
|
136
136
|
for (const candidate of pathFields) validatePortableRelativePath(candidate);
|
|
137
|
-
if(action.kind==='desktop_target'){
|
|
137
|
+
if(action.kind==='desktop_target'||action.kind==='desktop_wait'){
|
|
138
138
|
const q=action.uia_query;
|
|
139
|
-
|
|
140
|
-
if(q
|
|
141
|
-
if(q
|
|
139
|
+
const needsQuery=action.kind==='desktop_target'||action.until==='uia_present'||action.until==='uia_absent';
|
|
140
|
+
if(needsQuery&&!q)throw new Error('desktop UIA query required');
|
|
141
|
+
if(!needsQuery&&q)throw new Error('desktop non-UIA wait cannot carry query');
|
|
142
|
+
if(q){
|
|
143
|
+
if(q.kind==='root'&&q.value!=='') throw new Error('desktop root query value must be empty');
|
|
144
|
+
if(q.kind!=='root'&&q.value.length<1) throw new Error('desktop UIA query value required');
|
|
145
|
+
if(q.ordinal>=q.max_results) throw new Error('desktop UIA ordinal must be below max_results');
|
|
146
|
+
}
|
|
147
|
+
if(action.kind==='desktop_wait'&&action.poll_ms>action.timeout_ms)throw new Error('desktop wait poll exceeds timeout');
|
|
142
148
|
}
|
|
143
149
|
if(action.kind==='desktop_action'){
|
|
144
150
|
const pointer=['pointer_move','click_primary','click_secondary','double_click_primary','scroll'].includes(action.action_kind);
|
|
@@ -372,7 +378,7 @@ export function buildPlannerPrompt({ goal, policy, view }) {
|
|
|
372
378
|
'patch: operations are DEADBYTE Native Diff operations (write, replace, delete) and MUST use exact SHA-256 preconditions from supplied context.',
|
|
373
379
|
'run_profile: profile_id must be one of the policy profile ids in state.',
|
|
374
380
|
'delegate: operation is one bounded existing-runtime action. Allowed kinds: machine_stat, machine_list, machine_read, observation_search_start, observation_search_status, observation_search_page, observation_search_cancel, observation_process_list, observation_system_status, process_start, process_read, process_status, process_list, process_action, process_terminate.',
|
|
375
|
-
'When Desktop capabilities are present, use typed desktop_status, desktop_observe, desktop_target with one bounded UIA query, and desktop_action. desktop_action requires separate Desktop authority; Autonomous authority never implies Desktop authority. After stale or unknown Desktop evidence, observe again and replan; never blindly repeat an action.',
|
|
381
|
+
'When Desktop capabilities are present, use typed desktop_status, desktop_observe, bounded desktop_wait, desktop_target with one bounded UIA query, and desktop_action. desktop_wait is read-only and replaces fixed sleeps; it never retries an action. desktop_action requires separate Desktop authority; Autonomous authority never implies Desktop authority. After stale or unknown Desktop evidence, observe again and replan; never blindly repeat an action.',
|
|
376
382
|
'Delegate paths are relative to the goal root. Process start accepts only profile_id and cwd; process_action accepts only session_id and fixed action_id. Never emit raw stdin, executable, PID, environment, shell command, or process arguments.',
|
|
377
383
|
'finish only when the goal is actually satisfied. Required release profiles are enforced by the engine and cannot be bypassed.',
|
|
378
384
|
'clarify only when one bounded operator choice is genuinely required. Ask one concrete question and provide 2-5 short mutually exclusive choices.',
|
|
@@ -726,7 +726,7 @@ const CAPABILITY_BY_ACTION=Object.freeze({
|
|
|
726
726
|
machine_stat:'machine_fs.stat',machine_list:'machine_fs.list',machine_read:'machine_fs.read',
|
|
727
727
|
observation_search_start:'observation.search_start',observation_search_status:'observation.search_status',observation_search_page:'observation.search_page',observation_search_cancel:'observation.search_cancel',
|
|
728
728
|
observation_process_list:'observation.process_list',observation_system_status:'observation.system_status',
|
|
729
|
-
desktop_status:'desktop.status',desktop_observe:'desktop.observe',desktop_target:'desktop.target',desktop_action:'desktop.action'
|
|
729
|
+
desktop_status:'desktop.status',desktop_observe:'desktop.observe',desktop_wait:'desktop.wait',desktop_target:'desktop.target',desktop_action:'desktop.action'
|
|
730
730
|
});
|
|
731
731
|
function capabilityIdForOperation(operation){return CAPABILITY_BY_ACTION[operation?.kind]??null;}
|
|
732
732
|
function assertDelegatedIdentity(events, operation) {
|
|
@@ -745,6 +745,12 @@ function assertDelegatedIdentity(events, operation) {
|
|
|
745
745
|
event.payload?.operation?.kind==='desktop_observe'&&event.payload?.result?.frame?.frame_id===operation.frame_id);
|
|
746
746
|
if(!owned) throw new Error(`desktop frame '${operation.frame_id}' was not freshly observed by this goal`);
|
|
747
747
|
}
|
|
748
|
+
if(operation.kind==='desktop_wait'){
|
|
749
|
+
const owned=events.some(event=>event.type==='delegated_action_completed'&&
|
|
750
|
+
['desktop_observe','desktop_wait','desktop_target'].includes(event.payload?.operation?.kind)&&
|
|
751
|
+
event.payload?.result?.frame?.frame_id===operation.baseline_frame_id);
|
|
752
|
+
if(!owned)throw new Error(`desktop wait baseline '${operation.baseline_frame_id}' was not freshly observed by this goal`);
|
|
753
|
+
}
|
|
748
754
|
if(operation.kind==='desktop_action'){
|
|
749
755
|
const frameOwned=events.some(event=>event.type==='delegated_action_completed'&&
|
|
750
756
|
['desktop_observe','desktop_target'].includes(event.payload?.operation?.kind)&&
|
|
@@ -856,6 +862,9 @@ async function invokeDelegatedOperation(goal, operation, runtimes, desktopContex
|
|
|
856
862
|
case 'desktop_observe':
|
|
857
863
|
if(!desktopRuntime) throw new Error('desktop runtime unavailable');
|
|
858
864
|
return desktopRuntime.observe({preview:false});
|
|
865
|
+
case 'desktop_wait':
|
|
866
|
+
if(!desktopRuntime) throw new Error('desktop runtime unavailable');
|
|
867
|
+
return desktopRuntime.wait({baselineFrameId:operation.baseline_frame_id,until:operation.until,query:operation.uia_query,timeoutMs:operation.timeout_ms,pollMs:operation.poll_ms,preview:false});
|
|
859
868
|
case 'desktop_target':
|
|
860
869
|
if(!desktopRuntime) throw new Error('desktop runtime unavailable');
|
|
861
870
|
return desktopRuntime.ground({frameId:operation.frame_id,query:operation.uia_query});
|
|
@@ -903,6 +912,7 @@ async function verifyDelegatedEvidence(operation, result, runtimes, verifyKeyPat
|
|
|
903
912
|
if(!runtimes.desktopRuntime?.verifyReceipt) throw new Error('desktop receipt verifier unavailable');
|
|
904
913
|
const refs=[];
|
|
905
914
|
if(operation.kind==='desktop_observe'&&result?.receipt_id) refs.push([result.receipt_id,result.receipt_sha256,'desktop_observation']);
|
|
915
|
+
if(operation.kind==='desktop_wait'&&result?.receipt_id) refs.push([result.receipt_id,result.receipt_sha256,'desktop_wait_observation']);
|
|
906
916
|
if(operation.kind==='desktop_target'&&result?.grounding?.receipt_id) refs.push([result.grounding.receipt_id,result.grounding.receipt_sha256,'desktop_grounding']);
|
|
907
917
|
if(operation.kind==='desktop_action'){
|
|
908
918
|
refs.push(
|
|
@@ -147,6 +147,7 @@ export const R36_CAPABILITY_ENTRIES=Object.freeze([
|
|
|
147
147
|
|
|
148
148
|
gateway('desktop.status','desktop_status','desktop_control','status','DEADBYTE_DESKTOP_RUNTIME','none',{receipt_class:'desktop'}),
|
|
149
149
|
gateway('desktop.observe','desktop_observe','desktop_control','observe','DEADBYTE_DESKTOP_RUNTIME','none',{receipt_class:'desktop'}),
|
|
150
|
+
gateway('desktop.wait','desktop_wait','desktop_control','wait','DEADBYTE_DESKTOP_RUNTIME','none',{receipt_class:'desktop'}),
|
|
150
151
|
gateway('desktop.target','desktop_target','desktop_control','target','DEADBYTE_DESKTOP_RUNTIME','none',{receipt_class:'desktop'}),
|
|
151
152
|
gateway('desktop.action','desktop_action','desktop_control','action','DEADBYTE_DESKTOP_RUNTIME','desktop',{mutating:true,receipt_class:'desktop'}),
|
|
152
153
|
|
|
@@ -581,6 +581,19 @@ export function createCommanderWireAdapter({machineFsRuntime=null,processRuntime
|
|
|
581
581
|
}
|
|
582
582
|
return null;
|
|
583
583
|
}
|
|
584
|
+
async function waitForStreamQuiescence(sessionId,observed,timeoutMs,settleMs=100){
|
|
585
|
+
const deadline=Date.now()+timeoutMs;
|
|
586
|
+
let current=observed;
|
|
587
|
+
while(current.state==='running'&&Date.now()<deadline){
|
|
588
|
+
const baseline=current.stream_head;
|
|
589
|
+
const waitMs=Math.min(settleMs,Math.max(1,deadline-Date.now()));
|
|
590
|
+
const next=await processRuntime.read({sessionId,offset:baseline,maxBytes:1,waitMs});
|
|
591
|
+
if(next.state!=='running') return next;
|
|
592
|
+
if(next.stream_head>baseline){ current=next; continue; }
|
|
593
|
+
return next;
|
|
594
|
+
}
|
|
595
|
+
return current;
|
|
596
|
+
}
|
|
584
597
|
async function readProcessRange(sessionId,start,end){
|
|
585
598
|
if(!Number.isInteger(start)||!Number.isInteger(end)||start<0||end<start) throw new Error('native process range invalid');
|
|
586
599
|
if(end-start>RDC_PROCESS_SNAPSHOT_MAX) throw new Error(`RDC process response exceeds ${RDC_PROCESS_SNAPSHOT_MAX} byte compatibility bound`);
|
|
@@ -710,6 +723,9 @@ export function createCommanderWireAdapter({machineFsRuntime=null,processRuntime
|
|
|
710
723
|
if((observed.stream_head??before.stream_head)<=before.stream_head&&observed.state==='running'&&waitMs>0){
|
|
711
724
|
observed=await waitForStreamAdvance(sessionId,before.stream_head,waitMs)??observed;
|
|
712
725
|
}
|
|
726
|
+
if((observed.stream_head??before.stream_head)>before.stream_head&&observed.state==='running'&&waitMs>0){
|
|
727
|
+
observed=await waitForStreamQuiescence(sessionId,observed,waitMs);
|
|
728
|
+
}
|
|
713
729
|
const streamHead=Number.isInteger(observed.stream_head)?observed.stream_head:before.stream_head;
|
|
714
730
|
const earliest=Number.isInteger(observed.earliest_offset)?observed.earliest_offset:observed.offset;
|
|
715
731
|
const start=Math.max(before.stream_head,earliest);
|