deadbyte-mcp 0.15.44 → 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 +69 -131
- package/PROVENANCE.json +257 -243
- package/README.txt +18 -18
- package/RELEASE.json +348 -334
- package/SBOM.cdx.json +2 -2
- package/TEST-MATRIX.json +503 -491
- 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/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/package.json +2 -2
- package/scripts/benchmark-l0-r71.mjs +76 -0
- package/scripts/gate-windows-r71.ps1 +64 -0
- package/scripts/npm-release-r48.mjs +2 -0
- package/scripts/npm-release-readiness-r71.mjs +21 -0
- package/scripts/verify-r70-full-regression.ps1 +72 -0
- 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/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 +8 -6
- package/src/native-diff-v2.mjs +18 -5
- package/src/native-diff.mjs +21 -5
- package/src/r70-owner-approval.mjs +78 -0
- package/src/remote-live-log.mjs +48 -14
- package/src/remote-result-journal.mjs +1 -1
- package/src/runtime-update.mjs +2051 -1891
- package/src/tool-audit.mjs +2 -0
- package/src/version.mjs +1 -1
- package/test/autonomous-local-supervisor.test.mjs +2 -1
- package/test/autonomous-output-contract.test.mjs +17 -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/commander-compat-runtime.test.mjs +42 -0
- package/test/controller-policy-preflight-r59.test.mjs +1 -0
- package/test/native-diff-topology-r36.test.mjs +35 -2
- package/test/native-diff.test.mjs +83 -3
- package/test/r59-tool-surface-compat.test.mjs +9 -5
- package/test/r65-authority-runtime-epoch.test.mjs +9 -1
- package/test/r67-isolated-slot-rollback-restore.test.mjs +2 -1
- package/test/r67-npm-publish-gate.test.mjs +4 -2
- package/test/r67-release-contract.test.mjs +8 -7
- 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/remote-result-journal.test.mjs +12 -0
- package/test/remote-session-cli.test.mjs +2 -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-native-inspect-r67.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
package/src/deadbyte-cli.mjs
CHANGED
|
@@ -16,7 +16,7 @@ import { exportOfflineDiagnostics } from './r67-diagnostic-export.mjs';
|
|
|
16
16
|
import { verifyOfflineDiagnosticsZip } from './r67-diagnostics-verify.mjs';
|
|
17
17
|
import { parseActivePointer } from './release-slot.mjs';
|
|
18
18
|
import { printDoctor } from './doctor-r45.mjs';
|
|
19
|
-
import { 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';
|
|
20
20
|
import { prepareRemoteConsole, remoteDisplayText } from './remote-console.mjs';
|
|
21
21
|
import { ensureRuntimeCoherence } from './runtime-coherence.mjs';
|
|
22
22
|
import { windowsPowerShellEnvironment } from './runtime-update.mjs';
|
|
@@ -270,13 +270,15 @@ function auditTimelineRecord(file,line,auditEvent=null){
|
|
|
270
270
|
if(event.event_type==='tool.request') return {event_type:'tool.call',request_id:event.request_id,tool:event.tool,
|
|
271
271
|
observed_at_utc:observed,arguments:event.args??{},payload_sha256};
|
|
272
272
|
if(event.event_type==='tool.result'){
|
|
273
|
-
const
|
|
273
|
+
const classified=classifyRemoteAuditOutcome(event);
|
|
274
|
+
const unknown=classified==='unknown';
|
|
274
275
|
const recoveryReason=unknown&&typeof event.outcome?.recovery?.reason==='string'?event.outcome.recovery.reason:null;
|
|
275
276
|
return {event_type:'tool.result',request_id:event.request_id,tool:event.tool,
|
|
276
|
-
status:
|
|
277
|
+
status:classified==='pending'?'pending':classified==='ok'?'ok':'error',observed_at_utc:observed,payload_sha256,
|
|
277
278
|
...(Number.isFinite(Number(event.outcome?.duration_ms))?{duration_ms:Number(event.outcome.duration_ms)}:{}),
|
|
278
279
|
...(unknown?{side_effect_state:'unknown'}:{}),
|
|
279
|
-
...(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}:{})))};
|
|
280
282
|
}
|
|
281
283
|
return null;
|
|
282
284
|
}
|
|
@@ -296,9 +298,9 @@ async function replayRemoteResults(root,cursor,{displayMode='unicode'}={}){
|
|
|
296
298
|
continue;
|
|
297
299
|
}
|
|
298
300
|
const unknown=event.side_effect_state==='unknown';
|
|
299
|
-
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':'✓');
|
|
300
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'}`:'';
|
|
301
|
-
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}`:'';
|
|
302
304
|
process.stdout.write(remoteDisplayText(`[REPLAY] #${event.seq} ${event.tool}${duration} ${marker}${reason}\n`,displayMode));
|
|
303
305
|
}
|
|
304
306
|
next=page.next_cursor;
|
package/src/native-diff-v2.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import path from 'node:path';
|
|
|
4
4
|
import { canonicalJson } from './canonical-json.mjs';
|
|
5
5
|
import { validatePortableRelativePath } from './path-policy.mjs';
|
|
6
6
|
import { loadPrivateSigningKey, loadPublicVerifyKey } from './trust.mjs';
|
|
7
|
-
import { assertAutonomousArmed, recheckAutonomousAuthority } from './autonomous-policy.mjs';
|
|
7
|
+
import { assertAutonomousArmed, autonomousSessionStatus, recheckAutonomousAuthority } from './autonomous-policy.mjs';
|
|
8
8
|
|
|
9
9
|
export const NATIVE_DIFF_V2_SCHEMA='deadbyte.native-diff.v2';
|
|
10
10
|
export const NATIVE_DIFF_V2_PREIMAGE_SCHEMA='deadbyte.native-diff-preimage.v2';
|
|
@@ -107,9 +107,16 @@ export function createNativeDiffV2Runtime({policy,codingRuntime,machineFsRuntime
|
|
|
107
107
|
if(!machineFsRuntime?.state||!machineFsRuntime?.removeEmptyDir) throw new Error('native diff V2 requires machine fs topology runtime');
|
|
108
108
|
if(!signingKeyPath||!verifyKeyPath) throw new Error('native diff V2 requires trust keys');
|
|
109
109
|
|
|
110
|
-
async function materializeOperations(rootId,rawOperations){
|
|
111
|
-
if(
|
|
112
|
-
|
|
110
|
+
async function materializeOperations(rootId,rawOperations,{codingOnly=false}={}){
|
|
111
|
+
if(codingOnly){
|
|
112
|
+
const lease=await codingRuntime.sessionStatus();
|
|
113
|
+
if(!lease.armed) throw new Error(`coding plane is disarmed: ${lease.reason}`);
|
|
114
|
+
if(!lease.root_ids.includes(rootId)||codingRuntime.policy.roots[rootId]?.read!==true)
|
|
115
|
+
throw new Error(`native diff preview root '${rootId}' is not allowed by Coding lease`);
|
|
116
|
+
} else {
|
|
117
|
+
if(!policy.root_ids.includes(rootId)) throw new Error(`native diff root '${rootId}' is not allowed`);
|
|
118
|
+
await assertAutonomousArmed(policy,rootId);
|
|
119
|
+
}
|
|
113
120
|
const {normalized,payloadBytes}=normalizeRawOperations(rawOperations,policy);
|
|
114
121
|
const operations=[];
|
|
115
122
|
for(const op of normalized){
|
|
@@ -168,7 +175,13 @@ export function createNativeDiffV2Runtime({policy,codingRuntime,machineFsRuntime
|
|
|
168
175
|
async function preview({rootId,operations:rawOperations,title='',applicationScope=null}){
|
|
169
176
|
if(typeof title!=='string'||title.length>160) throw new Error('native diff title must be <=160 characters');
|
|
170
177
|
if(applicationScope!==null&&!SHA256_RE.test(applicationScope)) throw new Error('native diff application_scope must be SHA-256 or null');
|
|
171
|
-
const
|
|
178
|
+
const autonomous=policy.root_ids.includes(rootId)?await autonomousSessionStatus(policy):null;
|
|
179
|
+
const codingOnly=autonomous?.armed!==true||!autonomous.root_ids?.includes(rootId);
|
|
180
|
+
const {operations,payloadBytes}=await materializeOperations(rootId,rawOperations,{codingOnly});
|
|
181
|
+
if(codingOnly) return {status:'preview_only',schema:NATIVE_DIFF_V2_SCHEMA,root_id:rootId,
|
|
182
|
+
operation_count:operations.length,payload_bytes:payloadBytes,
|
|
183
|
+
paths:operations.map(op=>op.path??op.source_path),
|
|
184
|
+
operations:operations.map(({content,old_string,new_string,...op})=>op)};
|
|
172
185
|
const identity={schema:NATIVE_DIFF_V2_SCHEMA,policy_sha256:policy.policy_sha256,coding_policy_sha256:policy.coding_policy_sha256,root_id:rootId,title,operations,...(applicationScope===null?{}:{application_scope:applicationScope})};
|
|
173
186
|
const diffId=sha256Object(identity); const ctx=diffContext(policy,diffId); const signing=await loadPrivateSigningKey(signingKeyPath);
|
|
174
187
|
const envelope=signEnvelope(signing,DIFF_DOMAIN,{...identity,diff_id:diffId,created_at_utc:new Date().toISOString()});
|
package/src/native-diff.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import path from 'node:path';
|
|
|
4
4
|
import { canonicalJson } from './canonical-json.mjs';
|
|
5
5
|
import { validatePortableRelativePath } from './path-policy.mjs';
|
|
6
6
|
import { loadPrivateSigningKey, loadPublicVerifyKey } from './trust.mjs';
|
|
7
|
-
import { assertAutonomousArmed, recheckAutonomousAuthority } from './autonomous-policy.mjs';
|
|
7
|
+
import { assertAutonomousArmed, autonomousSessionStatus, recheckAutonomousAuthority } from './autonomous-policy.mjs';
|
|
8
8
|
import { createNativeDiffV2Runtime, NATIVE_DIFF_V2_SCHEMA } from './native-diff-v2.mjs';
|
|
9
9
|
|
|
10
10
|
export const NATIVE_DIFF_SCHEMA = 'deadbyte.native-diff.v1';
|
|
@@ -102,9 +102,19 @@ function createNativeDiffRuntimeV1({ policy, codingRuntime, signingKeyPath, veri
|
|
|
102
102
|
if (!policy || !codingRuntime?.policy) throw new Error('native diff runtime requires autonomous and coding policy');
|
|
103
103
|
if (!signingKeyPath || !verifyKeyPath) throw new Error('native diff runtime requires trust keys');
|
|
104
104
|
|
|
105
|
-
async function materializeOperations(rootId, rawOperations) {
|
|
106
|
-
if (
|
|
107
|
-
|
|
105
|
+
async function materializeOperations(rootId, rawOperations, {codingOnly=false} = {}) {
|
|
106
|
+
if (codingOnly) {
|
|
107
|
+
// Preview authorization delegates ONLY to the existing, locally armed
|
|
108
|
+
// Coding read lease. No Autonomous grant, signer, or target mutation.
|
|
109
|
+
const lease=await codingRuntime.sessionStatus();
|
|
110
|
+
if (!lease.armed) throw new Error(`coding plane is disarmed: ${lease.reason}`);
|
|
111
|
+
if (!lease.root_ids.includes(rootId) || codingRuntime.policy.roots[rootId]?.read !== true) {
|
|
112
|
+
throw new Error(`native diff preview root '${rootId}' is not allowed by Coding lease`);
|
|
113
|
+
}
|
|
114
|
+
} else {
|
|
115
|
+
if (!policy.root_ids.includes(rootId)) throw new Error(`native diff root '${rootId}' is not allowed`);
|
|
116
|
+
await assertAutonomousArmed(policy, rootId);
|
|
117
|
+
}
|
|
108
118
|
const { normalized, payloadBytes } = normalizeRawOperations(rawOperations, policy);
|
|
109
119
|
const operations = [];
|
|
110
120
|
for (const op of normalized) {
|
|
@@ -132,7 +142,13 @@ function createNativeDiffRuntimeV1({ policy, codingRuntime, signingKeyPath, veri
|
|
|
132
142
|
async function preview({ rootId, operations:rawOperations, title = '', applicationScope = null }) {
|
|
133
143
|
if (typeof title !== 'string' || title.length > 160) throw new Error('native diff title must be <=160 characters');
|
|
134
144
|
if (applicationScope !== null && !SHA256_RE.test(applicationScope)) throw new Error('native diff application_scope must be SHA-256 or null');
|
|
135
|
-
const
|
|
145
|
+
const autonomous=policy.root_ids.includes(rootId)?await autonomousSessionStatus(policy):null;
|
|
146
|
+
const codingOnly=autonomous?.armed!==true||!autonomous.root_ids?.includes(rootId);
|
|
147
|
+
const { operations, payloadBytes } = await materializeOperations(rootId, rawOperations, {codingOnly});
|
|
148
|
+
if (codingOnly) return {status:'preview_only',schema:NATIVE_DIFF_SCHEMA,root_id:rootId,
|
|
149
|
+
operation_count:operations.length,payload_bytes:payloadBytes,
|
|
150
|
+
paths:operations.map(op=>op.path),
|
|
151
|
+
operations:operations.map(({content,old_string,new_string,...op})=>op)};
|
|
136
152
|
const identity = { schema:NATIVE_DIFF_SCHEMA, policy_sha256:policy.policy_sha256,
|
|
137
153
|
coding_policy_sha256:policy.coding_policy_sha256, root_id:rootId, title, operations,
|
|
138
154
|
...(applicationScope === null ? {} : { application_scope:applicationScope }) };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import {createHash,createPublicKey,verify as verifySignature} from 'node:crypto';
|
|
2
|
+
import {lstat,realpath} from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import {canonicalJson} from './canonical-json.mjs';
|
|
5
|
+
|
|
6
|
+
const SUBJECT_SCHEMA='deadbyte.project-authority-subject.r70.v1';
|
|
7
|
+
const APPROVAL_SCHEMA='deadbyte.project-owner-approval.r70.v1';
|
|
8
|
+
const SCOPE='coding_autonomous_native_diff';
|
|
9
|
+
const DOMAIN=Buffer.from('DEADBYTE-R70-PROJECT-OWNER-APPROVAL\0','utf8');
|
|
10
|
+
const SHA=/^[0-9a-f]{64}$/;
|
|
11
|
+
const ID=/^[A-Za-z0-9._-]{1,64}$/;
|
|
12
|
+
const SUBJECT_FIELDS=['schema','scope','root_id','project_root','coding_policy_sha256',
|
|
13
|
+
'autonomous_policy_sha256','reviewed_artifact_sha256','issued_at_utc','expires_at_utc'];
|
|
14
|
+
const APPROVAL_FIELDS=['schema','subject_sha256','owner_key_id','subject','signature_base64'];
|
|
15
|
+
const EXPECTED_FIELDS=['rootId','projectRoot','codingPolicySha256','autonomousPolicySha256','reviewedArtifactSha256'];
|
|
16
|
+
const hash=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
17
|
+
const samePath=(a,b)=>process.platform==='win32'?a.toLowerCase()===b.toLowerCase():a===b;
|
|
18
|
+
|
|
19
|
+
function exact(value,fields,label){
|
|
20
|
+
if(!value||typeof value!=='object'||Array.isArray(value))throw new Error(`${label} invalid`);
|
|
21
|
+
const keys=Object.keys(value);
|
|
22
|
+
for(const key of keys)if(!fields.includes(key))throw new Error(`${label} unknown field '${key}'`);
|
|
23
|
+
for(const key of fields)if(!Object.hasOwn(value,key))throw new Error(`${label} missing field '${key}'`);
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
26
|
+
function digest(value,label){if(typeof value!=='string'||!SHA.test(value))throw new Error(`${label} invalid SHA-256`);return value;}
|
|
27
|
+
function instant(value,label){
|
|
28
|
+
if(typeof value!=='string'||!/^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{3}Z$/.test(value))throw new Error(`${label} invalid UTC`);
|
|
29
|
+
const parsed=Date.parse(value);
|
|
30
|
+
if(!Number.isFinite(parsed)||new Date(parsed).toISOString()!==value)throw new Error(`${label} invalid UTC`);
|
|
31
|
+
return parsed;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function verifyProjectOwnerApproval({approval,ownerPublicKey,expected,now=new Date()}={}){
|
|
35
|
+
exact(expected,EXPECTED_FIELDS,'owner approval expected subject');
|
|
36
|
+
exact(approval,APPROVAL_FIELDS,'owner approval');
|
|
37
|
+
exact(approval.subject,SUBJECT_FIELDS,'owner approval subject');
|
|
38
|
+
const subject=approval.subject;
|
|
39
|
+
if(approval.schema!==APPROVAL_SCHEMA||subject.schema!==SUBJECT_SCHEMA||subject.scope!==SCOPE)throw new Error('owner approval scope/schema mismatch');
|
|
40
|
+
if(typeof subject.root_id!=='string'||!ID.test(subject.root_id)||subject.root_id!==expected.rootId)throw new Error('owner approval root identity mismatch');
|
|
41
|
+
if(typeof subject.project_root!=='string'||!path.isAbsolute(subject.project_root)||
|
|
42
|
+
typeof expected.projectRoot!=='string'||!path.isAbsolute(expected.projectRoot))throw new Error('owner approval root path invalid');
|
|
43
|
+
let real;
|
|
44
|
+
try{
|
|
45
|
+
const entry=await lstat(expected.projectRoot);
|
|
46
|
+
if(!entry.isDirectory()||entry.isSymbolicLink())throw new Error('not a real directory');
|
|
47
|
+
real=await realpath(expected.projectRoot);
|
|
48
|
+
}catch{throw new Error('owner approval project root is not a real directory');}
|
|
49
|
+
if(!samePath(path.resolve(real),path.resolve(expected.projectRoot))||
|
|
50
|
+
!samePath(path.resolve(real),path.resolve(subject.project_root)))throw new Error('owner approval real root mismatch');
|
|
51
|
+
if(digest(subject.coding_policy_sha256,'coding policy')!==digest(expected.codingPolicySha256,'expected coding policy')||
|
|
52
|
+
digest(subject.autonomous_policy_sha256,'autonomous policy')!==digest(expected.autonomousPolicySha256,'expected autonomous policy')){
|
|
53
|
+
throw new Error('owner approval policy digest mismatch');
|
|
54
|
+
}
|
|
55
|
+
if(digest(subject.reviewed_artifact_sha256,'reviewed artifact')!==digest(expected.reviewedArtifactSha256,'expected reviewed artifact')){
|
|
56
|
+
throw new Error('owner approval reviewed artifact mismatch');
|
|
57
|
+
}
|
|
58
|
+
const issued=instant(subject.issued_at_utc,'owner approval issued time');
|
|
59
|
+
const expires=instant(subject.expires_at_utc,'owner approval expiry');
|
|
60
|
+
const observed=now instanceof Date?now.getTime():NaN;
|
|
61
|
+
if(!Number.isFinite(observed)||expires<=issued||expires-issued>3_600_000)throw new Error('owner approval lifetime invalid');
|
|
62
|
+
if(observed<issued||observed>=expires)throw new Error('owner approval expired or not yet valid');
|
|
63
|
+
const subjectSha=hash(Buffer.from(canonicalJson(subject),'utf8'));
|
|
64
|
+
if(digest(approval.subject_sha256,'owner approval subject')!==subjectSha)throw new Error('owner approval subject hash mismatch');
|
|
65
|
+
let key;
|
|
66
|
+
try{key=ownerPublicKey?.type==='public'?ownerPublicKey:createPublicKey(ownerPublicKey);}catch{throw new Error('owner approval public key invalid');}
|
|
67
|
+
if(key.asymmetricKeyType!=='ed25519')throw new Error('owner approval public key must be Ed25519');
|
|
68
|
+
const keyId=hash(key.export({type:'spki',format:'der'}));
|
|
69
|
+
if(digest(approval.owner_key_id,'owner approval key id')!==keyId)throw new Error('owner approval key identity mismatch');
|
|
70
|
+
if(typeof approval.signature_base64!=='string'||!/^[A-Za-z0-9+/]{86}==$/.test(approval.signature_base64))throw new Error('owner approval signature encoding invalid');
|
|
71
|
+
const signature=Buffer.from(approval.signature_base64,'base64');
|
|
72
|
+
const signed={schema:APPROVAL_SCHEMA,subject_sha256:subjectSha,owner_key_id:keyId};
|
|
73
|
+
if(signature.length!==64||!verifySignature(null,Buffer.concat([DOMAIN,Buffer.from(canonicalJson(signed),'utf8')]),key,signature)){
|
|
74
|
+
throw new Error('owner approval signature invalid');
|
|
75
|
+
}
|
|
76
|
+
return Object.freeze({approved:true,subject_sha256:subjectSha,owner_key_id:keyId,
|
|
77
|
+
project_root:real,root_id:subject.root_id,scope:SCOPE,expires_at_utc:subject.expires_at_utc});
|
|
78
|
+
}
|
package/src/remote-live-log.mjs
CHANGED
|
@@ -183,6 +183,7 @@ export function formatRemoteToolCall(event,{clock=()=>Date.now(),displayMode='un
|
|
|
183
183
|
function formatDuration(ms){
|
|
184
184
|
const value=Number(ms);
|
|
185
185
|
if(!Number.isFinite(value)||value<0) return '';
|
|
186
|
+
if(value<1) return value===0?'0ms':`${Number(value.toPrecision(3))}ms`;
|
|
186
187
|
if(value<1000) return `${Math.round(value)}ms`;
|
|
187
188
|
return `${(value/1000).toFixed(2)}s`;
|
|
188
189
|
}
|
|
@@ -191,7 +192,8 @@ export function formatCompactAuditEvent(event){
|
|
|
191
192
|
if(!event||typeof event!=='object'||Array.isArray(event)||typeof event.tool!=='string'||!/^[A-Za-z][A-Za-z0-9_.-]{0,127}$/.test(event.tool)) return null;
|
|
192
193
|
if(event.event_type==='tool.request') return `▶ RUN ${event.tool}${summarizeArgs(sanitizeAuditArgs(event.args??{}))}`;
|
|
193
194
|
if(event.event_type==='tool.result'){
|
|
194
|
-
const
|
|
195
|
+
const outcome=outcomeClass(event);
|
|
196
|
+
const marker=outcome==='unknown'?'⚠ UNKNOWN':outcome==='error'?'❌ ERR':outcome==='pending'?'⏳ PENDING':'✅ OK';
|
|
195
197
|
const duration=formatDuration(event.outcome?.duration_ms);
|
|
196
198
|
return `${marker} ${event.tool}${duration?` ${duration}`:''}`;
|
|
197
199
|
}
|
|
@@ -251,9 +253,16 @@ function traceText(meta,displayMode='unicode'){
|
|
|
251
253
|
(meta.parent_span_id?' parent='+shortTraceValue(meta.parent_span_id,displayMode):'');
|
|
252
254
|
}
|
|
253
255
|
function outcomeClass(event){
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
256
|
+
const outcome=event?.outcome;
|
|
257
|
+
if(outcome?.side_effect_state==='unknown') return 'unknown';
|
|
258
|
+
const status=outcome?.status;
|
|
259
|
+
if(status==='timeout'||status==='timed_out') return 'unknown';
|
|
260
|
+
if(outcome?.is_error===true||
|
|
261
|
+
['failed','denied','rejected','blocked','observed_failure','cancelled','canceled','unavailable','unsupported'].includes(status)) return 'error';
|
|
262
|
+
if(['pending','running','input_required','paused','processing','accepted'].includes(status)) return 'pending';
|
|
263
|
+
return 'ok';
|
|
264
|
+
}
|
|
265
|
+
export function classifyRemoteAuditOutcome(event){return outcomeClass(event);}
|
|
257
266
|
function parseFilterExpression(expression){
|
|
258
267
|
if(expression===null||expression===undefined||expression==='') return Object.freeze({});
|
|
259
268
|
if(typeof expression!=='string'||expression.length>512) throw new Error('timeline filter invalid');
|
|
@@ -264,7 +273,7 @@ function parseFilterExpression(expression){
|
|
|
264
273
|
const key=part.slice(0,at).trim();const value=part.slice(at+1).trim();
|
|
265
274
|
if(!['tool','category','status','trace'].includes(key)) throw new Error(`timeline filter key '${key}' unsupported`);
|
|
266
275
|
if(Object.hasOwn(out,key)) throw new Error(`timeline filter key '${key}' repeated`);
|
|
267
|
-
if(key==='status'&&!['ok','error','unknown'].includes(value)) throw new Error('timeline filter status invalid');
|
|
276
|
+
if(key==='status'&&!['ok','error','unknown','pending'].includes(value)) throw new Error('timeline filter status invalid');
|
|
268
277
|
if(key==='category'&&!Object.hasOwn(TOOL_ICONS,value)) throw new Error('timeline filter category invalid');
|
|
269
278
|
out[key]=value;
|
|
270
279
|
}
|
|
@@ -287,7 +296,7 @@ export function createLiveTimelineFilter(expression=''){
|
|
|
287
296
|
if(!requestId||!rawTool) return false;
|
|
288
297
|
if(event.event_type==='tool.request'){
|
|
289
298
|
const args=event.args??{};const tool=displayToolName(rawTool,args);const trace=traceIdentity(event,args);
|
|
290
|
-
const meta={tool,category:categoryForTool(tool),trace_id:trace.trace_id};
|
|
299
|
+
const meta={tool,raw_tool:rawTool,category:categoryForTool(tool),trace_id:trace.trace_id};
|
|
291
300
|
if(pending.has(requestId))pending.delete(requestId);
|
|
292
301
|
if(pending.size>=MAX_FILTER_IDENTITIES){pending.delete(pending.keys().next().value);evicted++;}
|
|
293
302
|
pending.set(requestId,meta);
|
|
@@ -296,7 +305,8 @@ export function createLiveTimelineFilter(expression=''){
|
|
|
296
305
|
if(event.event_type==='tool.result'){
|
|
297
306
|
const meta=pending.get(requestId)??{tool:rawTool,category:categoryForTool(rawTool),trace_id:traceIdentity(event).trace_id};
|
|
298
307
|
pending.delete(requestId);
|
|
299
|
-
|
|
308
|
+
const status=meta.raw_tool&&meta.raw_tool!==rawTool?'unknown':outcomeClass(event);
|
|
309
|
+
return baseMatch(meta)&&(!spec.status||spec.status===status);
|
|
300
310
|
}
|
|
301
311
|
return false;
|
|
302
312
|
},
|
|
@@ -312,10 +322,20 @@ export function createLiveTimelineWriter({stream=process.stdout,displayMode='uni
|
|
|
312
322
|
function flush(){
|
|
313
323
|
if(active){stream.write('\n');active=null;}
|
|
314
324
|
}
|
|
325
|
+
// Inspect terminal width for every emission: resize must not erase a wrapped prior line.
|
|
326
|
+
// Unknown Unicode cell width falls back to append-only output, never truncation.
|
|
327
|
+
function fitsOneRow(line){
|
|
328
|
+
const columns=stream.columns;
|
|
329
|
+
return /^[\x20-\x7e]*$/.test(line)&&(!Number.isInteger(columns)||line.length<columns);
|
|
330
|
+
}
|
|
315
331
|
function write(line,{event_type=null,request_id=null}={}){
|
|
316
332
|
if(typeof line!=='string'||!line) return;
|
|
317
333
|
const tty=stream.isTTY===true&&rewrite;
|
|
318
|
-
if(!tty
|
|
334
|
+
if(!tty||!fitsOneRow(line)){
|
|
335
|
+
if(active) flush();
|
|
336
|
+
stream.write(line+'\n');
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
319
339
|
if(active&&event_type==='tool.result'&&request_id&&request_id===active.request_id){
|
|
320
340
|
stream.write('\r\x1b[2K'+line+'\n');active=null;return;
|
|
321
341
|
}
|
|
@@ -340,7 +360,7 @@ export function createLiveTimelineTracker({clock=()=>Date.now(),verbose=false,fo
|
|
|
340
360
|
const MAX_PRESENTATION_IDENTITIES=4096;
|
|
341
361
|
const toolCounts=new Map();
|
|
342
362
|
const durationSamples=[];
|
|
343
|
-
let resultCount=0,okCount=0,errorCount=0,unknownCount=0,mutationCount=0,totalDurationMs=0,slowest=null,burst=null,foldedHeartbeatLines=0,peakInFlight=0;
|
|
363
|
+
let resultCount=0,okCount=0,errorCount=0,unknownCount=0,pendingCount=0,mutationCount=0,totalDurationMs=0,durationObservedCount=0,slowest=null,burst=null,foldedHeartbeatLines=0,peakInFlight=0;
|
|
344
364
|
let lastCapability=null,suppressedCapability=0,suppressedCapabilityReported=false;
|
|
345
365
|
let lastSourceSequence=0,pendingOverflow=0;
|
|
346
366
|
|
|
@@ -352,8 +372,10 @@ export function createLiveTimelineTracker({clock=()=>Date.now(),verbose=false,fo
|
|
|
352
372
|
}
|
|
353
373
|
function traceSuffix(meta){return trace&&meta?' '+traceText(meta,displayMode):'';}
|
|
354
374
|
function resultLine(event,span,sequence){
|
|
355
|
-
const
|
|
356
|
-
const
|
|
375
|
+
const outcome=outcomeClass(event);
|
|
376
|
+
const error=outcome==='error';
|
|
377
|
+
const unknown=outcome==='unknown';
|
|
378
|
+
const pendingResult=outcome==='pending';
|
|
357
379
|
const displayTool=span?.display_tool||event.tool;
|
|
358
380
|
const rawDuration=Number(event.outcome?.duration_ms);
|
|
359
381
|
const duration=Number.isFinite(rawDuration)
|
|
@@ -371,6 +393,7 @@ export function createLiveTimelineTracker({clock=()=>Date.now(),verbose=false,fo
|
|
|
371
393
|
?shortValue(event.outcome.receipt_sha256s[0],8):'';
|
|
372
394
|
const marker=unknown?'FAILED_AFTER_UNKNOWN_EFFECT':
|
|
373
395
|
error?(displayMode==='ascii'?'ERR':'✗'):
|
|
396
|
+
pendingResult?'PENDING':
|
|
374
397
|
['write','edit','run'].includes(category)?(displayMode==='ascii'?'SUCCEEDED':'✅ SUCCEEDED'):
|
|
375
398
|
(displayMode==='ascii'?'OK':'✓');
|
|
376
399
|
const rawStatus=safeAtom(event.outcome?.status);
|
|
@@ -402,11 +425,12 @@ export function createLiveTimelineTracker({clock=()=>Date.now(),verbose=false,fo
|
|
|
402
425
|
const countKey=toolCounts.has(displayTool)||toolCounts.size<256?displayTool:'[other]';
|
|
403
426
|
toolCounts.set(countKey,(toolCounts.get(countKey)??0)+1);
|
|
404
427
|
const outcome=outcomeClass(event);
|
|
405
|
-
if(outcome==='unknown') unknownCount++;else if(outcome==='error') errorCount++;else okCount++;
|
|
428
|
+
if(outcome==='unknown') unknownCount++;else if(outcome==='error') errorCount++;else if(outcome==='pending') pendingCount++;else okCount++;
|
|
406
429
|
if(['write','edit','run'].includes(categoryForTool(displayTool))) mutationCount++;
|
|
407
430
|
const duration=Number(event.outcome?.duration_ms);
|
|
408
431
|
if(Number.isFinite(duration)&&duration>=0){
|
|
409
432
|
totalDurationMs+=duration;
|
|
433
|
+
durationObservedCount++;
|
|
410
434
|
if(durationSamples.length<2048) durationSamples.push(duration);
|
|
411
435
|
if(!slowest||duration>slowest.duration_ms) slowest={tool:displayTool,duration_ms:duration};
|
|
412
436
|
}
|
|
@@ -444,6 +468,15 @@ export function createLiveTimelineTracker({clock=()=>Date.now(),verbose=false,fo
|
|
|
444
468
|
pending.delete(requestId);
|
|
445
469
|
completed.add(requestId);
|
|
446
470
|
if(completed.size>MAX_PRESENTATION_IDENTITIES)completed.delete(completed.values().next().value);
|
|
471
|
+
if(span&&span.tool!==tool){
|
|
472
|
+
const mismatchEvent={...event,outcome:{status:'correlation_mismatch',is_error:true,
|
|
473
|
+
side_effect_state:'unknown',duration_ms:event.outcome?.duration_ms,
|
|
474
|
+
reason:'CORRELATION_MISMATCH: terminal tool differs from START; inspect signed audit before retry'}};
|
|
475
|
+
addStats(mismatchEvent,span);
|
|
476
|
+
const prior=flushBurst();
|
|
477
|
+
const line=resultLine(mismatchEvent,span,sequence);
|
|
478
|
+
return prior?[prior,line]:line;
|
|
479
|
+
}
|
|
447
480
|
addStats(event,span);
|
|
448
481
|
const error=event.outcome?.is_error===true;
|
|
449
482
|
const nowMs=eventMs(event,clock);
|
|
@@ -502,10 +535,11 @@ export function createLiveTimelineTracker({clock=()=>Date.now(),verbose=false,fo
|
|
|
502
535
|
const sorted=[...durationSamples].sort((a,b)=>a-b);
|
|
503
536
|
const p50=sorted.length?(sorted.length%2?sorted[(sorted.length-1)/2]:(sorted[sorted.length/2-1]+sorted[sorted.length/2])/2):null;
|
|
504
537
|
const p95=sorted.length?sorted[Math.max(0,Math.ceil(sorted.length*0.95)-1)]:null;
|
|
538
|
+
const p99=sorted.length?sorted[Math.max(0,Math.ceil(sorted.length*0.99)-1)]:null;
|
|
505
539
|
return remoteDisplayText((displayMode==='ascii'?'[SUMMARY]':'📊 [SUMMARY]')+' '+resultCount+' calls | '+okCount+' ok | '+
|
|
506
|
-
errorCount+' error'+(errorCount===1?'':'s')+' | '+unknownCount+' unknown | '+mutationCount+' mutation'+(mutationCount===1?'':'s')+
|
|
540
|
+
errorCount+' error'+(errorCount===1?'':'s')+' | '+unknownCount+' unknown'+(pendingCount?' | '+pendingCount+' pending':'')+' | '+mutationCount+' mutation'+(mutationCount===1?'':'s')+
|
|
507
541
|
' | tool time '+(formatDuration(totalDurationMs)||'0ms')+
|
|
508
|
-
(p50!==null?' | p50 '+formatDuration(p50)+' | p95 '+formatDuration(p95):'')+
|
|
542
|
+
(p50!==null?' | p50 '+formatDuration(p50)+' | p95 '+formatDuration(p95)+' | p99 '+formatDuration(p99)+' | sample '+durationSamples.length+'/'+durationObservedCount:'')+
|
|
509
543
|
(slowest?' | slowest '+slowest.tool+' '+formatDuration(slowest.duration_ms):'')+
|
|
510
544
|
' | peak in-flight '+peakInFlight+
|
|
511
545
|
(foldedHeartbeatLines?' | folded '+foldedHeartbeatLines+' heartbeat lines':'')+
|
|
@@ -5,7 +5,7 @@ import { sanitizeAuditArgs } from './tool-audit.mjs';
|
|
|
5
5
|
export const REMOTE_RESULT_JOURNAL_SCHEMA='deadbyte.remote-result-journal.v1';
|
|
6
6
|
const SESSION=/^[0-9a-f]{24}$/;
|
|
7
7
|
const HASH=/^[0-9a-f]{64}$/;
|
|
8
|
-
const STATUS=new Set(['ok','error']);
|
|
8
|
+
const STATUS=new Set(['ok','error','pending']);
|
|
9
9
|
const SIDE_EFFECT_STATES=new Set(['unknown']);
|
|
10
10
|
const EVENT_TYPES=new Set(['tool.call','tool.result']);
|
|
11
11
|
|