@danceiny/gotry 0.0.1-rc.21 → 0.0.1-rc.24
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/README.md +102 -194
- package/README.zh-CN.md +115 -210
- package/bin/gotry-backend.js +53 -0
- package/bin/gotry-bootstrap.js +466 -35
- package/bin/gotry-inner.js +255 -36
- package/bin/gotry-process-liveness.d.ts +27 -0
- package/bin/gotry-process-liveness.js +97 -0
- package/bin/gotry-runtime-resolution.d.ts +1 -1
- package/bin/gotry-runtime-resolution.js +2 -2
- package/client/client.js +174 -0
- package/cordis.gotry-patch.yml +70 -93
- package/dist/capabilities/agent-reach-deep.js +45 -122
- package/dist/capabilities/agent-reach.js +63 -148
- package/dist/capabilities/anything.js +89 -75
- package/dist/capabilities/artifacts.js +123 -104
- package/dist/capabilities/channel-health.js +65 -45
- package/dist/capabilities/channel-registry.js +108 -87
- package/dist/capabilities/doctor.js +357 -235
- package/dist/capabilities/effect.js +223 -309
- package/dist/capabilities/fact-log.js +28 -14
- package/dist/capabilities/flyai.js +245 -156
- package/dist/capabilities/ground-transfer.js +509 -0
- package/dist/capabilities/hbcli.js +144 -148
- package/dist/capabilities/hotelbyte-transaction.js +194 -0
- package/dist/capabilities/incident-log.js +131 -61
- package/dist/capabilities/model-override.js +30 -10
- package/dist/capabilities/opensky.js +54 -43
- package/dist/capabilities/resilience.js +50 -32
- package/dist/capabilities/session/action-cache.js +50 -44
- package/dist/capabilities/session/adapters/ctrip-flight.js +119 -62
- package/dist/capabilities/session/adapters/ctrip-hotel.js +125 -110
- package/dist/capabilities/session/adapters/dida-portal.js +206 -0
- package/dist/capabilities/session/adapters/meituan-local.js +35 -54
- package/dist/capabilities/session/adapters/rail-12306.js +169 -112
- package/dist/capabilities/session/benchmark.js +85 -149
- package/dist/capabilities/session/extension-bridge.js +320 -259
- package/dist/capabilities/session/extension-channel.js +57 -76
- package/dist/capabilities/session/extension-distribution.js +115 -119
- package/dist/capabilities/session/extract.js +31 -21
- package/dist/capabilities/session/golden-score.js +55 -33
- package/dist/capabilities/session/health-watch.js +146 -154
- package/dist/capabilities/session/read-guard.js +55 -47
- package/dist/capabilities/session/static-flight-golden.js +49 -36
- package/dist/capabilities/session/transport.js +54 -61
- package/dist/capabilities/session/wizard.js +63 -93
- package/dist/capabilities/session-consent.js +143 -47
- package/dist/capabilities/session-login.js +95 -126
- package/dist/capabilities/session-search.js +391 -253
- package/dist/capabilities/sponsor-plugin.js +341 -0
- package/dist/capabilities/visa-policy.js +87 -73
- package/dist/capabilities/weather.js +163 -235
- package/dist/scripts/action-cache-tests.js +24 -59
- package/dist/scripts/agent-planning-turn-deadline-e2e.js +91 -142
- package/dist/scripts/agent-planning-turn-deadline-tests.js +80 -176
- package/dist/scripts/agent-reach-deep-tests.js +30 -40
- package/dist/scripts/agent-reach-tests.js +26 -18
- package/dist/scripts/agent-reach-wrapper-tests.js +46 -50
- package/dist/scripts/anything-tests.js +58 -62
- package/dist/scripts/artifact-client-contract-tests.js +69 -0
- package/dist/scripts/artifacts-capability-tests.js +235 -0
- package/dist/scripts/async-collect.js +26 -15
- package/dist/scripts/benchmark-environment-bridge-e2e.js +287 -684
- package/dist/scripts/benchmark-environment-bridge-tests.js +818 -3123
- package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +66 -279
- package/dist/scripts/booking-copilot-availability-policy-tests.js +153 -1257
- package/dist/scripts/booking-copilot-bin-proof-tests.js +22 -45
- package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +64 -76
- package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +69 -199
- package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +393 -759
- package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +33 -75
- package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +60 -110
- package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +28 -66
- package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +72 -271
- package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +73 -275
- package/dist/scripts/booking-copilot-runtime-proof-tests.js +784 -3398
- package/dist/scripts/booking-copilot-server-proof-tests.js +63 -168
- package/dist/scripts/booking-copilot-startup-proof-tests.js +38 -124
- package/dist/scripts/booking-executor-tests.js +80 -0
- package/dist/scripts/booking-recovery-chain-tests.js +182 -0
- package/dist/scripts/booking-saga-tests.js +61 -123
- package/dist/scripts/booking-surface-contract-proof-tests.js +152 -1167
- package/dist/scripts/bootstrap-tests.js +1383 -128
- package/dist/scripts/build-changelog.js +89 -130
- package/dist/scripts/build-metrics-report.js +135 -143
- package/dist/scripts/changelog-tests.js +35 -82
- package/dist/scripts/channel-probe-tests.js +44 -116
- package/dist/scripts/channel-probe.js +84 -167
- package/dist/scripts/channel-registry-tests.js +97 -185
- package/dist/scripts/companion-tests.js +25 -70
- package/dist/scripts/dida-cookie-probe.js +87 -0
- package/dist/scripts/dida-sw-probe.js +114 -0
- package/dist/scripts/diff-test.js +17 -12
- package/dist/scripts/doctor-tests.js +428 -120
- package/dist/scripts/dsh-artifact-e2e.js +150 -0
- package/dist/scripts/dsh-artifact-web-e2e.js +443 -0
- package/dist/scripts/dsh-http-proxy-sse-proof.js +90 -0
- package/dist/scripts/dsh-runtime-closure-tests.js +110 -153
- package/dist/scripts/dsh-runtime-closure.js +75 -63
- package/dist/scripts/dsh-session-v3-migration-proof.js +106 -0
- package/dist/scripts/dsh-subprocess-local-proof.js +149 -0
- package/dist/scripts/dsh-target-closure-proof.js +178 -0
- package/dist/scripts/effect-tests.js +165 -552
- package/dist/scripts/engine-run.js +1 -3
- package/dist/scripts/engine-tests.js +16 -10
- package/dist/scripts/evaluation-cadence-tests.js +69 -242
- package/dist/scripts/evaluation-contract-tests.js +193 -499
- package/dist/scripts/extension-distribution-cli.js +19 -15
- package/dist/scripts/extension-distribution-tests.js +98 -211
- package/dist/scripts/extension-tests.js +366 -389
- package/dist/scripts/fact-gate-tests.js +725 -263
- package/dist/scripts/fixtures/extension-bridge-unref-child.mjs +21 -0
- package/dist/scripts/flight-hotel-anchor-363-registered-e2e.js +169 -0
- package/dist/scripts/flight-malformed-tests.js +159 -0
- package/dist/scripts/flyai-tests.js +325 -68
- package/dist/scripts/g5-guard-tests.js +131 -0
- package/dist/scripts/g5-guard.js +189 -0
- package/dist/scripts/gen-lunar-anchors.js +106 -0
- package/dist/scripts/gotry-backend-kernel-tests.js +79 -0
- package/dist/scripts/ground-transfer-tests.js +956 -0
- package/dist/scripts/hbcli-e2e-tests.js +71 -90
- package/dist/scripts/hbcli-live-optin-tests.js +96 -0
- package/dist/scripts/hbcli-release-contract-tests.js +122 -0
- package/dist/scripts/hbcli-tests.js +41 -115
- package/dist/scripts/health-watch-cli.js +42 -28
- package/dist/scripts/hotel-date-gate-tests.js +496 -0
- package/dist/scripts/hotelbyte-reconcile-tests.js +141 -0
- package/dist/scripts/hotelbyte-spawn-e2e-tests.js +373 -0
- package/dist/scripts/i18n-tests.js +16 -9
- package/dist/scripts/incident-tests.js +281 -87
- package/dist/scripts/issue-194-job-id-guard-tests.js +106 -0
- package/dist/scripts/issue-233-cancel-refund-commission-tests.js +392 -0
- package/dist/scripts/issue-271-liveness-tests.js +547 -0
- package/dist/scripts/issue-289-model-retry-real-tests.js +296 -0
- package/dist/scripts/issue-289-model-retry-tests.js +441 -0
- package/dist/scripts/issue-289-web-retry-e2e.js +630 -0
- package/dist/scripts/issue-338-home-city-e2e.js +577 -0
- package/dist/scripts/issue343-real-entry-e2e.js +160 -0
- package/dist/scripts/journey-tests.js +22 -27
- package/dist/scripts/kernel-manifest-evidence.js +109 -0
- package/dist/scripts/kernel-manifest-gate.js +126 -0
- package/dist/scripts/kernel-manifest-tests.js +212 -0
- package/dist/scripts/kernel-manifest-trace-entry.js +7 -0
- package/dist/scripts/kernel-manifest-trace-hook.mjs +28 -0
- package/dist/scripts/kernel-manifest.js +369 -0
- package/dist/scripts/ledger-repair-apply-tests.js +316 -0
- package/dist/scripts/ledger-repair-plan-tests.js +375 -0
- package/dist/scripts/ledger-tests.js +325 -340
- package/dist/scripts/ledger-workflow-crash.js +10 -20
- package/dist/scripts/map-tools-vendor-package-proof.js +206 -134
- package/dist/scripts/memory-capture-tests.js +242 -61
- package/dist/scripts/memory-decay-tests.js +18 -52
- package/dist/scripts/memory-lifecycle-tests.js +657 -0
- package/dist/scripts/memory-lifecycle.js +196 -0
- package/dist/scripts/memory-metrics.js +24 -12
- package/dist/scripts/memory-value-report.js +474 -222
- package/dist/scripts/memory-value-tests.js +328 -0
- package/dist/scripts/metrics-report-tests.js +62 -199
- package/dist/scripts/model-override-e2e.js +66 -105
- package/dist/scripts/nightly-evidence-tests.js +64 -89
- package/dist/scripts/nightly-evidence.js +108 -111
- package/dist/scripts/nudge-digest.js +39 -28
- package/dist/scripts/onboarding-tests.js +63 -88
- package/dist/scripts/opensky-check.js +18 -13
- package/dist/scripts/opensky-tests.js +28 -28
- package/dist/scripts/persona-surface-guard-tests.js +37 -12
- package/dist/scripts/pnpm-dsh-closure-proof.js +2 -5
- package/dist/scripts/policy-anchor-359-registered-e2e.js +214 -0
- package/dist/scripts/price-drift-tests.js +126 -227
- package/dist/scripts/price-drift-watch.js +209 -253
- package/dist/scripts/probe-poi-tests.js +52 -45
- package/dist/scripts/product-metrics.js +187 -273
- package/dist/scripts/publish-preverify.js +47 -41
- package/dist/scripts/realtime-pricing-tests.js +37 -76
- package/dist/scripts/replay-async.js +20 -18
- package/dist/scripts/replay-real.js +16 -18
- package/dist/scripts/replay.js +52 -82
- package/dist/scripts/session-attach-diagnose.js +16 -12
- package/dist/scripts/session-attach-poc.js +34 -37
- package/dist/scripts/session-benchmark.js +66 -147
- package/dist/scripts/session-dida-live-e2e.js +151 -0
- package/dist/scripts/session-extract-tests.js +14 -35
- package/dist/scripts/session-login.js +14 -13
- package/dist/scripts/session-tests.js +545 -583
- package/dist/scripts/sf-live-benchmark.js +92 -110
- package/dist/scripts/sf-live-cli-tests.js +2 -9
- package/dist/scripts/sf-soft-score-tests.js +19 -60
- package/dist/scripts/sf-summary-tests.js +149 -0
- package/dist/scripts/sf-summary.js +466 -84
- package/dist/scripts/skeleton-check.js +16 -14
- package/dist/scripts/skeleton-integration-test.js +11 -10
- package/dist/scripts/skills-contract-tests.js +51 -46
- package/dist/scripts/smoke-session-gate-tests.js +12 -20
- package/dist/scripts/smoke.js +541 -422
- package/dist/scripts/sponsor-reuse-tests.js +262 -0
- package/dist/scripts/state-cli-tests.js +226 -101
- package/dist/scripts/state-cli.js +549 -212
- package/dist/scripts/static-golden-tests.js +46 -180
- package/dist/scripts/time-eval-tests.js +210 -192
- package/dist/scripts/travel-timeline-tests.js +29 -93
- package/dist/scripts/turn-handoff-collect-tests.js +46 -93
- package/dist/scripts/turn-handoff-collect.js +71 -99
- package/dist/scripts/turn-policy-tests.js +28 -29
- package/dist/scripts/typed-contract-canary.js +77 -162
- package/dist/scripts/tz-resolver-sanity.js +50 -0
- package/dist/scripts/tz-resolver-tests.js +584 -0
- package/dist/scripts/unified-tests.js +23 -19
- package/dist/scripts/visa-policy-tests.js +31 -44
- package/dist/scripts/weather-tests.js +121 -543
- package/dist/scripts/wish-channel-gate-tests.js +29 -86
- package/dist/scripts/write-gate-tests.js +522 -0
- package/dist/scripts/z3-lifecycle-fault-tests.js +188 -0
- package/dist/scripts/z3-lifecycle-tests.js +170 -0
- package/dist/scripts/z3-race-repeat-tests.js +39 -0
- package/dist/scripts/z3-race-tests.js +18 -12
- package/dist/src/artifact-gate.js +652 -221
- package/dist/src/backend/kernel.js +91 -0
- package/dist/src/backend/modules/booking-copilot.js +55 -0
- package/dist/src/backend/modules/booking-executor.js +124 -0
- package/dist/src/backend/modules/session-search.js +194 -0
- package/dist/src/benchmark-agent-conformance.js +296 -262
- package/dist/src/benchmark-environment-bridge.js +298 -413
- package/dist/src/benchmark-headless-child-diagnostics.js +93 -100
- package/dist/src/benchmark-tool-isolation.js +94 -67
- package/dist/src/bookable-facts.js +299 -174
- package/dist/src/booking-saga.js +64 -120
- package/dist/src/booking-surface/availability-policy.js +443 -576
- package/dist/src/booking-surface/cancel-refund-commission.js +379 -0
- package/dist/src/booking-surface/contracts.js +24 -80
- package/dist/src/booking-surface/dsh-planner.js +510 -281
- package/dist/src/booking-surface/dsh-plugin.js +17 -1
- package/dist/src/booking-surface/error-codes.js +82 -10
- package/dist/src/booking-surface/index.js +0 -3
- package/dist/src/booking-surface/profile.js +10 -54
- package/dist/src/booking-surface/recovery-chain.js +367 -0
- package/dist/src/booking-surface/runtime.js +765 -891
- package/dist/src/booking-surface/server.js +200 -251
- package/dist/src/booking-surface/startup.js +58 -54
- package/dist/src/booking-surface/validation.js +150 -218
- package/dist/src/bridge.js +20 -13
- package/dist/src/companions.js +48 -74
- package/dist/src/contracts.js +21 -43
- package/dist/src/dsh-llm.js +82 -120
- package/dist/src/engine.js +253 -239
- package/dist/src/evaluation-cadence.js +72 -209
- package/dist/src/evaluation-contracts.js +220 -843
- package/dist/src/flight-pack-adapter.js +54 -0
- package/dist/src/flight-pack-contract.js +2 -0
- package/dist/src/gotry-backend.js +70 -0
- package/dist/src/hotel-date-gate.js +118 -0
- package/dist/src/i18n.js +18 -7
- package/dist/src/index.js +1425 -1629
- package/dist/src/journey.js +132 -81
- package/dist/src/ledger-repair-apply.js +538 -0
- package/dist/src/ledger-repair-plan.js +463 -0
- package/dist/src/loop.js +257 -166
- package/dist/src/memory-capture.js +180 -32
- package/dist/src/memory-decay.js +30 -14
- package/dist/src/memory-lifecycle.js +1310 -0
- package/dist/src/memory-utility.js +27 -40
- package/dist/src/mock-llm.js +36 -61
- package/dist/src/model.js +81 -36
- package/dist/src/realtime-pricing.js +63 -72
- package/dist/src/slot-spec.js +84 -106
- package/dist/src/state-ledger.js +310 -471
- package/dist/src/subagent-job-id-guard.js +58 -0
- package/dist/src/time-anchor.js +231 -33
- package/dist/src/tool-packet.js +20 -8
- package/dist/src/travel-slots.js +58 -35
- package/dist/src/travel-timeline.js +44 -63
- package/dist/src/turn-deadline.js +121 -127
- package/dist/src/turn-policy.js +61 -89
- package/dist/src/tz-resolver.js +143 -0
- package/dist/src/unified.js +504 -381
- package/dist/src/wish-pool.js +39 -14
- package/dist/src/write-gate.js +495 -0
- package/dist/src/z3-shared.js +273 -7
- package/extension/README.md +4 -3
- package/extension/background.js +125 -14
- package/extension/content-bridge.js +23 -1
- package/extension/content-main.js +15 -4
- package/extension/manifest.json +16 -8
- package/package.json +251 -220
- package/ts/capabilities/agent-reach.ts +4 -4
- package/ts/capabilities/anything.ts +1 -1
- package/ts/capabilities/artifacts.ts +46 -9
- package/ts/capabilities/flyai.ts +156 -37
- package/ts/capabilities/hbcli.ts +1 -1
- package/ts/capabilities/incident-log.ts +88 -59
- package/ts/capabilities/session/adapters/ctrip-flight.ts +99 -36
- package/ts/capabilities/session/adapters/dida-portal.ts +250 -0
- package/ts/capabilities/session/adapters/rail-12306.ts +123 -24
- package/ts/capabilities/session/extension-bridge.ts +226 -101
- package/ts/capabilities/session/extension-channel.ts +22 -9
- package/ts/capabilities/session/wizard.ts +2 -2
- package/ts/capabilities/session-consent.ts +98 -14
- package/ts/capabilities/session-login.ts +1 -0
- package/ts/capabilities/session-search.ts +315 -31
- package/ts/dsh-runtime/vendor/README.md +8 -4
- package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +7 -1
- package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +5 -3
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +1 -1
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +1 -1
- package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +6 -6
- package/ts/package.json +236 -16
- package/ts/scripts/map-tools-vendor-package-proof.ts +152 -31
- package/ts/scripts/state-cli.ts +418 -51
- package/ts/src/artifact-gate.ts +561 -15
- package/ts/src/benchmark-environment-bridge.ts +37 -20
- package/ts/src/bookable-facts.ts +183 -7
- package/ts/src/booking-surface/cancel-refund-commission.ts +488 -0
- package/ts/src/booking-surface/dsh-planner.ts +240 -32
- package/ts/src/booking-surface/dsh-plugin.js +17 -1
- package/ts/src/booking-surface/error-codes.ts +75 -0
- package/ts/src/booking-surface/recovery-chain.ts +409 -0
- package/ts/src/booking-surface/server.ts +84 -51
- package/ts/src/booking-surface/validation.ts +2 -0
- package/ts/src/contracts.ts +12 -2
- package/ts/src/dsh-llm.ts +4 -8
- package/ts/src/index.ts +609 -90
- package/ts/src/loop.ts +116 -7
- package/ts/src/memory-capture.ts +227 -3
- package/ts/src/mock-llm.ts +4 -8
- package/ts/src/model.ts +88 -2
- package/ts/src/state-ledger.ts +47 -29
- package/ts/src/subagent-job-id-guard.ts +72 -0
- package/ts/src/time-anchor.ts +217 -13
- package/ts/src/unified.ts +316 -54
|
@@ -1,96 +1,290 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* D-NEW / #271 Phase A 事故观察器测试。
|
|
3
|
+
*
|
|
4
|
+
* 覆盖真实 native ESM dist 产物的 uncaughtExceptionMonitor:有观察器时
|
|
5
|
+
* fatal 事故留下 JSONL、仍按宿主语义非零退出;无观察器时只有 Node 原生
|
|
6
|
+
* 非零退出。另覆盖同一 fd 的 fsync/close、写入失败返回值、监听器卸载和
|
|
7
|
+
* guardToolExecute 结构化业务失败。
|
|
8
|
+
*
|
|
9
|
+
* 运行: cd ts && npx tsx scripts/incident-tests.ts
|
|
10
|
+
*/
|
|
1
11
|
import assert from 'node:assert/strict';
|
|
2
12
|
import { spawn } from 'node:child_process';
|
|
3
|
-
import
|
|
13
|
+
import fs from 'node:fs';
|
|
14
|
+
import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
|
|
15
|
+
import { syncBuiltinESMExports } from 'node:module';
|
|
4
16
|
import { tmpdir } from 'node:os';
|
|
5
17
|
import { join } from 'node:path';
|
|
6
18
|
import { fileURLToPath } from 'node:url';
|
|
7
19
|
import { dirname } from 'node:path';
|
|
8
|
-
import { recordIncident, resolveIncidentsPath } from '../capabilities/incident-log.js';
|
|
20
|
+
import { guardToolExecute, installProcessGuards, recordIncident, resolveIncidentsPath } from '../capabilities/incident-log.js';
|
|
9
21
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
22
|
+
const repoRoot = join(here, '../..');
|
|
23
|
+
const distModule = join(repoRoot, 'dist/capabilities/incident-log.js');
|
|
10
24
|
const tmp = await mkdtemp(join(tmpdir(), 'incident-test-'));
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
'--experimental-strip-types',
|
|
36
|
-
childPath
|
|
37
|
-
], {
|
|
38
|
-
stdio: [
|
|
39
|
-
'ignore',
|
|
40
|
-
'pipe',
|
|
41
|
-
'pipe'
|
|
42
|
-
]
|
|
25
|
+
const cleanEnv = () => {
|
|
26
|
+
const env = { ...process.env };
|
|
27
|
+
delete env.NODE_OPTIONS;
|
|
28
|
+
delete env.NODE_PATH;
|
|
29
|
+
return env;
|
|
30
|
+
};
|
|
31
|
+
async function runChild(code, stateRoot) {
|
|
32
|
+
const childPath = join(stateRoot, 'child.mjs');
|
|
33
|
+
await writeFile(childPath, code);
|
|
34
|
+
return await new Promise((resolve, reject) => {
|
|
35
|
+
const child = spawn(process.execPath, [childPath], { cwd: repoRoot, env: cleanEnv(), stdio: ['ignore', 'pipe', 'pipe'] });
|
|
36
|
+
let stdout = '';
|
|
37
|
+
let stderr = '';
|
|
38
|
+
const timer = setTimeout(() => {
|
|
39
|
+
child.kill('SIGKILL');
|
|
40
|
+
reject(new Error(`child timeout: ${stderr.slice(0, 400)}`));
|
|
41
|
+
}, 3000);
|
|
42
|
+
child.stdout.on('data', (data) => { stdout += data.toString(); });
|
|
43
|
+
child.stderr.on('data', (data) => { stderr += data.toString(); });
|
|
44
|
+
child.on('error', (error) => { clearTimeout(timer); reject(error); });
|
|
45
|
+
child.on('close', (codeValue, signal) => {
|
|
46
|
+
clearTimeout(timer);
|
|
47
|
+
resolve({ stdout, stderr, code: codeValue, signal });
|
|
48
|
+
});
|
|
43
49
|
});
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
assert.
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
console.log('
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
assert.ok(fs.existsSync(distModule), `build-dist output missing: ${distModule}`);
|
|
53
|
+
// Unit 1: the writer uses one fd, calls real fsync, and reports boolean success.
|
|
54
|
+
{
|
|
55
|
+
let fsyncCalls = 0;
|
|
56
|
+
const originalFsync = fs.fsyncSync;
|
|
57
|
+
fs.fsyncSync = ((fd) => { fsyncCalls += 1; return originalFsync(fd); });
|
|
58
|
+
syncBuiltinESMExports();
|
|
59
|
+
try {
|
|
60
|
+
const ok = recordIncident({ ts: '2026-09-09T00:00:00Z', kind: 'uncaughtException', message: 'synthetic', stack: 'no-stack' }, tmp);
|
|
61
|
+
assert.equal(ok, true);
|
|
62
|
+
assert.equal(fsyncCalls, 1);
|
|
63
|
+
const content = await readFile(resolveIncidentsPath(tmp), 'utf8');
|
|
64
|
+
const written = JSON.parse(content.trim().split('\n')[0]);
|
|
65
|
+
assert.equal(written.kind, 'uncaughtException');
|
|
66
|
+
assert.equal(written.message, 'synthetic');
|
|
67
|
+
assert.equal(written.stack, 'no-stack');
|
|
68
|
+
}
|
|
69
|
+
finally {
|
|
70
|
+
fs.fsyncSync = originalFsync;
|
|
71
|
+
syncBuiltinESMExports();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
console.log('UNIT 1 OK: recordIncident 同一 fd 真实 fsync + boolean success');
|
|
75
|
+
// Unit 2: a failing fsync is contained, returns false, and closes the fd.
|
|
76
|
+
{
|
|
77
|
+
let closeCalls = 0;
|
|
78
|
+
const originalFsync = fs.fsyncSync;
|
|
79
|
+
const originalClose = fs.closeSync;
|
|
80
|
+
fs.fsyncSync = (() => { throw new Error('synthetic fsync failure'); });
|
|
81
|
+
fs.closeSync = ((fd) => { closeCalls += 1; return originalClose(fd); });
|
|
82
|
+
syncBuiltinESMExports();
|
|
83
|
+
try {
|
|
84
|
+
let result = true;
|
|
85
|
+
assert.doesNotThrow(() => { result = recordIncident({ ts: '2026-09-09T00:00:01Z', kind: 'plugin_error', message: 'fsync-failure' }, tmp); });
|
|
86
|
+
assert.equal(result, false);
|
|
87
|
+
assert.equal(closeCalls, 1);
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
fs.fsyncSync = originalFsync;
|
|
91
|
+
fs.closeSync = originalClose;
|
|
92
|
+
syncBuiltinESMExports();
|
|
93
|
+
}
|
|
94
|
+
closeCalls = 0;
|
|
95
|
+
const originalClose2 = fs.closeSync;
|
|
96
|
+
fs.closeSync = ((fd) => { closeCalls += 1; originalClose2(fd); throw new Error('synthetic close report'); });
|
|
97
|
+
syncBuiltinESMExports();
|
|
98
|
+
try {
|
|
99
|
+
assert.equal(recordIncident({ ts: '2026-09-09T00:00:02Z', kind: 'plugin_error', message: 'close-failure' }, tmp), false);
|
|
100
|
+
assert.equal(closeCalls, 1);
|
|
101
|
+
}
|
|
102
|
+
finally {
|
|
103
|
+
fs.closeSync = originalClose2;
|
|
104
|
+
syncBuiltinESMExports();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
console.log('UNIT 2 OK: fsync failure returns false, closes fd, does not throw');
|
|
108
|
+
// Unit 3: install/dispose changes only the monitor listener and never leaks it.
|
|
109
|
+
{
|
|
110
|
+
const before = process.listenerCount('uncaughtExceptionMonitor');
|
|
111
|
+
const dispose = installProcessGuards(tmp, { uncaughtException: 'unit', unhandledRejection: 'unit' });
|
|
112
|
+
assert.equal(process.listenerCount('uncaughtExceptionMonitor'), before + 1);
|
|
113
|
+
const duplicateDispose = installProcessGuards(tmp);
|
|
114
|
+
duplicateDispose();
|
|
115
|
+
assert.equal(process.listenerCount('uncaughtExceptionMonitor'), before + 1);
|
|
116
|
+
dispose();
|
|
117
|
+
assert.equal(process.listenerCount('uncaughtExceptionMonitor'), before);
|
|
118
|
+
const disposeB = installProcessGuards(tmp);
|
|
119
|
+
dispose();
|
|
120
|
+
assert.equal(process.listenerCount('uncaughtExceptionMonitor'), before + 1);
|
|
121
|
+
disposeB();
|
|
122
|
+
assert.equal(process.listenerCount('uncaughtExceptionMonitor'), before);
|
|
123
|
+
}
|
|
124
|
+
console.log('UNIT 3 OK: monitor install/dispose 无监听泄漏');
|
|
125
|
+
// Integration 0: the packaged native ESM writer returns true and invokes real fsync.
|
|
126
|
+
{
|
|
127
|
+
const stateRoot = join(tmp, 'dist-writer');
|
|
128
|
+
await fs.promises.mkdir(stateRoot, { recursive: true });
|
|
129
|
+
const result = await runChild(`
|
|
130
|
+
import fs from 'node:fs'
|
|
131
|
+
import { syncBuiltinESMExports } from 'node:module'
|
|
132
|
+
import { recordIncident, resolveIncidentsPath } from ${JSON.stringify(distModule)}
|
|
133
|
+
const originalFsync = fs.fsyncSync
|
|
134
|
+
let fsyncCalls = 0
|
|
135
|
+
fs.fsyncSync = ((fd) => { fsyncCalls += 1; return originalFsync(fd) })
|
|
136
|
+
syncBuiltinESMExports()
|
|
137
|
+
const ok = recordIncident({ ts: '2026-09-09T00:00:03Z', kind: 'plugin_error', message: 'native-dist-writer' }, ${JSON.stringify(stateRoot)})
|
|
138
|
+
if (!ok || fsyncCalls !== 1 || !fs.existsSync(resolveIncidentsPath(${JSON.stringify(stateRoot)}))) process.exit(42)
|
|
139
|
+
`, stateRoot);
|
|
140
|
+
assert.equal(result.code, 0, `native dist writer assertion failed: ${result.stderr}`);
|
|
141
|
+
const line = JSON.parse((await readFile(resolveIncidentsPath(stateRoot), 'utf8')).trim());
|
|
142
|
+
assert.equal(line.message, 'native-dist-writer');
|
|
143
|
+
}
|
|
144
|
+
console.log('INTEG 0 OK: native dist writer true + real fsync + JSONL');
|
|
145
|
+
// Integration 0b: direct dist entrypoint smoke is fatal; importing it with
|
|
146
|
+
// argv2=--smoke does not trigger the CLI branch.
|
|
147
|
+
{
|
|
148
|
+
const directRoot = join(tmp, 'direct-smoke');
|
|
149
|
+
const importedRoot = join(tmp, 'imported-smoke');
|
|
150
|
+
const importedMarker = join(importedRoot, 'continued.marker');
|
|
151
|
+
await fs.promises.mkdir(directRoot, { recursive: true });
|
|
152
|
+
await fs.promises.mkdir(importedRoot, { recursive: true });
|
|
153
|
+
const direct = await new Promise((resolve, reject) => {
|
|
154
|
+
const child = spawn(process.execPath, [distModule, '--smoke', directRoot], { cwd: repoRoot, env: cleanEnv(), stdio: ['ignore', 'pipe', 'pipe'] });
|
|
155
|
+
let stdout = '', stderr = '';
|
|
156
|
+
const timer = setTimeout(() => { child.kill('SIGKILL'); reject(new Error('direct smoke timeout')); }, 3000);
|
|
157
|
+
child.stdout.on('data', (data) => { stdout += data.toString(); });
|
|
158
|
+
child.stderr.on('data', (data) => { stderr += data.toString(); });
|
|
159
|
+
child.on('error', (error) => { clearTimeout(timer); reject(error); });
|
|
160
|
+
child.on('close', (code, signal) => { clearTimeout(timer); resolve({ stdout, stderr, code, signal }); });
|
|
161
|
+
});
|
|
162
|
+
assert.equal(direct.code, 1, `direct dist smoke should exit 1: ${direct.stderr}`);
|
|
163
|
+
const directIncident = JSON.parse((await readFile(resolveIncidentsPath(directRoot), 'utf8')).trim());
|
|
164
|
+
assert.equal(directIncident.message, 'intentional smoke-uncaught');
|
|
165
|
+
const imported = await runChild(`
|
|
166
|
+
import { writeFileSync } from 'node:fs'
|
|
167
|
+
process.argv.push('--smoke', ${JSON.stringify(importedRoot)})
|
|
168
|
+
await import(${JSON.stringify(distModule)})
|
|
169
|
+
setTimeout(() => writeFileSync(${JSON.stringify(importedMarker)}, 'continued'), 50)
|
|
170
|
+
`, importedRoot);
|
|
171
|
+
assert.equal(imported.code, 0, `imported module must not trigger smoke: ${imported.stderr}`);
|
|
172
|
+
assert.equal(fs.existsSync(importedMarker), true);
|
|
173
|
+
assert.equal(fs.existsSync(resolveIncidentsPath(importedRoot)), false);
|
|
174
|
+
}
|
|
175
|
+
console.log('INTEG 0b OK: direct smoke fatal; imported --smoke inert');
|
|
176
|
+
// Integration 1-2: native dist, observer + fatal => durable log, exit 1, no marker.
|
|
177
|
+
for (const [kind, trigger, expectedKind] of [
|
|
178
|
+
['uncaughtException', "setTimeout(() => { throw new Error('native-uncaught') }, 20)", 'uncaughtException'],
|
|
179
|
+
['unhandledRejection', "setTimeout(() => Promise.reject(new Error('native-rejection')), 20)", 'unhandledRejection'],
|
|
180
|
+
]) {
|
|
181
|
+
const stateRoot = join(tmp, `guard-${kind}`);
|
|
182
|
+
const marker = join(stateRoot, 'after-fatal.marker');
|
|
183
|
+
await fs.promises.mkdir(stateRoot, { recursive: true });
|
|
184
|
+
const result = await runChild(`
|
|
185
|
+
import { installProcessGuards } from ${JSON.stringify(distModule)}
|
|
186
|
+
import { writeFileSync } from 'node:fs'
|
|
187
|
+
installProcessGuards(${JSON.stringify(stateRoot)}, { uncaughtException: 'native-test', unhandledRejection: 'native-test' })
|
|
188
|
+
${trigger}
|
|
189
|
+
setTimeout(() => writeFileSync(${JSON.stringify(marker)}, 'after-fatal'), 100)
|
|
190
|
+
`, stateRoot);
|
|
191
|
+
assert.equal(result.code, 1, `${kind} should retain native nonzero exit: ${result.stderr}`);
|
|
192
|
+
assert.equal(result.signal, null);
|
|
193
|
+
assert.equal(fs.existsSync(marker), false);
|
|
194
|
+
const lines = (await readFile(resolveIncidentsPath(stateRoot), 'utf8')).trim().split('\n').filter(Boolean);
|
|
195
|
+
assert.equal(lines.length, 1);
|
|
196
|
+
const incident = JSON.parse(lines[0]);
|
|
197
|
+
assert.equal(incident.kind, expectedKind);
|
|
198
|
+
assert.match(incident.message, /native-(uncaught|rejection)/);
|
|
199
|
+
assert.equal(incident.source, 'native-test');
|
|
200
|
+
}
|
|
201
|
+
console.log('INTEG 1-2 OK: native dist monitor records uncaught/rejection and preserves exit 1');
|
|
202
|
+
// Integration 3-4: no monitor is the Node native comparison pair.
|
|
203
|
+
for (const [kind, trigger] of [
|
|
204
|
+
['uncaughtException', "setTimeout(() => { throw new Error('plain-uncaught') }, 20)"],
|
|
205
|
+
['unhandledRejection', "setTimeout(() => Promise.reject(new Error('plain-rejection')), 20)"],
|
|
206
|
+
]) {
|
|
207
|
+
const stateRoot = join(tmp, `plain-${kind}`);
|
|
208
|
+
const marker = join(stateRoot, 'after-fatal.marker');
|
|
209
|
+
await fs.promises.mkdir(stateRoot, { recursive: true });
|
|
210
|
+
const result = await runChild(`import { writeFileSync } from 'node:fs'\n${trigger}\nsetTimeout(() => writeFileSync(${JSON.stringify(marker)}, 'after-fatal'), 100)`, stateRoot);
|
|
211
|
+
assert.equal(result.code, 1, `${kind} without monitor should retain native nonzero exit: ${result.stderr}`);
|
|
212
|
+
assert.equal(result.signal, null);
|
|
213
|
+
assert.equal(fs.existsSync(marker), false);
|
|
214
|
+
assert.equal(fs.existsSync(resolveIncidentsPath(stateRoot)), false);
|
|
215
|
+
}
|
|
216
|
+
console.log('INTEG 3-4 OK: no-monitor native comparison exits 1 without incident log');
|
|
217
|
+
// Integration 5: an existing host handler owns the exit code; the observer does not bypass it.
|
|
218
|
+
{
|
|
219
|
+
const stateRoot = join(tmp, 'host-handler');
|
|
220
|
+
await fs.promises.mkdir(stateRoot, { recursive: true });
|
|
221
|
+
const hostMarker = join(stateRoot, 'host-handler.marker');
|
|
222
|
+
const result = await runChild(`
|
|
223
|
+
import { installProcessGuards } from ${JSON.stringify(distModule)}
|
|
224
|
+
import { writeFileSync } from 'node:fs'
|
|
225
|
+
installProcessGuards(${JSON.stringify(stateRoot)})
|
|
226
|
+
process.on('uncaughtException', (_error, origin) => {
|
|
227
|
+
writeFileSync(${JSON.stringify(hostMarker)}, origin)
|
|
228
|
+
process.exitCode = 23
|
|
229
|
+
})
|
|
230
|
+
setTimeout(() => { throw new Error('host-owned-fatal') }, 20)
|
|
231
|
+
setTimeout(() => {}, 100)
|
|
232
|
+
`, stateRoot);
|
|
233
|
+
assert.equal(result.code, 23, `host handler exit code was bypassed: ${result.stderr}`);
|
|
234
|
+
assert.equal(result.signal, null);
|
|
235
|
+
assert.equal((await readFile(hostMarker, 'utf8')), 'uncaughtException');
|
|
236
|
+
const incident = JSON.parse((await readFile(resolveIncidentsPath(stateRoot), 'utf8')).trim());
|
|
237
|
+
assert.equal(incident.kind, 'uncaughtException');
|
|
238
|
+
}
|
|
239
|
+
console.log('INTEG 5 OK: host fatal handler retains exit policy');
|
|
240
|
+
// Integration 6: a thrown non-Error with hostile message/stack accessors
|
|
241
|
+
// cannot break the observer; the host receives the original object identity.
|
|
242
|
+
{
|
|
243
|
+
const stateRoot = join(tmp, 'host-non-error');
|
|
244
|
+
const hostMarker = join(stateRoot, 'host-handler.marker');
|
|
245
|
+
await fs.promises.mkdir(stateRoot, { recursive: true });
|
|
246
|
+
const result = await runChild(`
|
|
247
|
+
import { installProcessGuards } from ${JSON.stringify(distModule)}
|
|
248
|
+
import { writeFileSync } from 'node:fs'
|
|
249
|
+
installProcessGuards(${JSON.stringify(stateRoot)})
|
|
250
|
+
const original = Object.create(null)
|
|
251
|
+
Object.defineProperty(original, 'message', { enumerable: true, get() { throw new Error('message getter') } })
|
|
252
|
+
Object.defineProperty(original, 'stack', { enumerable: true, get() { throw new Error('stack getter') } })
|
|
253
|
+
process.on('uncaughtException', (_error, origin) => {
|
|
254
|
+
writeFileSync(${JSON.stringify(hostMarker)}, _error === original ? origin : 'wrong-identity')
|
|
255
|
+
process.exitCode = 23
|
|
256
|
+
})
|
|
257
|
+
setTimeout(() => { throw original }, 20)
|
|
258
|
+
setTimeout(() => {}, 100)
|
|
259
|
+
`, stateRoot);
|
|
260
|
+
assert.equal(result.code, 23, `non-Error throw bypassed host handler: ${result.stderr}`);
|
|
261
|
+
assert.equal(result.signal, null);
|
|
262
|
+
assert.equal((await readFile(hostMarker, 'utf8')), 'uncaughtException');
|
|
263
|
+
const incident = JSON.parse((await readFile(resolveIncidentsPath(stateRoot), 'utf8')).trim());
|
|
264
|
+
assert.equal(incident.kind, 'uncaughtException');
|
|
265
|
+
assert.equal(typeof incident.message, 'string');
|
|
266
|
+
}
|
|
267
|
+
console.log('INTEG 6 OK: non-Error throw safe formatting + original host identity/exit policy');
|
|
268
|
+
// Unit 4: tool business errors remain structured and do not escape.
|
|
269
|
+
{
|
|
270
|
+
const asyncBoom = guardToolExecute('synthetic-tool', tmp, async () => { throw new Error('boom-async'); });
|
|
271
|
+
const r1 = await asyncBoom({ x: 1 }, undefined);
|
|
272
|
+
assert.equal(r1.ok, false);
|
|
273
|
+
assert.ok(String(r1.summary).includes('synthetic-tool'));
|
|
274
|
+
assert.ok(String(r1.evidence).includes('tool_execute_error'));
|
|
275
|
+
const syncBoom = guardToolExecute('synthetic-tool-sync', tmp, () => { throw new Error('boom-sync'); });
|
|
276
|
+
const r2 = await syncBoom({}, undefined);
|
|
277
|
+
assert.equal(r2.ok, false);
|
|
278
|
+
const nonErrorBoom = guardToolExecute('synthetic-tool-nonerror', tmp, () => { throw Object.create(null); });
|
|
279
|
+
const r3 = await nonErrorBoom({}, undefined);
|
|
280
|
+
assert.equal(r3.ok, false);
|
|
281
|
+
const toolErrs = (await readFile(resolveIncidentsPath(tmp), 'utf8')).trim().split('\n').filter(Boolean)
|
|
282
|
+
.map((line) => JSON.parse(line)).filter((line) => line.kind === 'tool_execute_error');
|
|
283
|
+
assert.equal(toolErrs.length, 3);
|
|
284
|
+
}
|
|
285
|
+
console.log('UNIT 4 OK: guardToolExecute 保持结构化业务失败');
|
|
286
|
+
}
|
|
287
|
+
finally {
|
|
288
|
+
await rm(tmp, { recursive: true, force: true });
|
|
289
|
+
}
|
|
290
|
+
console.log('INCIDENT TESTS: all focused checks OK');
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Issue #194 focused regression.
|
|
3
|
+
*
|
|
4
|
+
* This mounts the actual dsh ToolRuntime, LocalJobRegistry, and job tools, then
|
|
5
|
+
* supplies only a deterministic in-process subagent listing. It never starts a
|
|
6
|
+
* provider, opens Chrome, reads credentials, or writes shared state.
|
|
7
|
+
*/
|
|
8
|
+
import assert from 'node:assert/strict';
|
|
9
|
+
import { Context } from '@deepseek-ai/cordis';
|
|
10
|
+
import { ToolRuntime } from '@deepseek-ai/dsh-tools';
|
|
11
|
+
import { LocalJobRegistry } from '@deepseek-ai/dsh-jobs-local';
|
|
12
|
+
import { SystemPrompt } from '@deepseek-ai/dsh-system-prompt';
|
|
13
|
+
import { apply as applyJobs } from '@deepseek-ai/dsh-tool-jobs';
|
|
14
|
+
import { installSubagentJobIdGuard } from '../src/subagent-job-id-guard.js';
|
|
15
|
+
const parentId = 'parent-session-issue-194';
|
|
16
|
+
const durableId = 'dc5c8d88-d23e-4df0-ba95-ccbc80e2742a';
|
|
17
|
+
const oneShotId = 'one-shot-session-issue-194';
|
|
18
|
+
const unrelatedId = 'unrelated-session-issue-194';
|
|
19
|
+
const listedParents = [];
|
|
20
|
+
const continuable = {
|
|
21
|
+
kind: 'child',
|
|
22
|
+
id: durableId,
|
|
23
|
+
activity: 'inactive',
|
|
24
|
+
hasChildren: false,
|
|
25
|
+
mode: 'continuable',
|
|
26
|
+
label: 'fixture continuable child',
|
|
27
|
+
};
|
|
28
|
+
const oneShot = {
|
|
29
|
+
kind: 'child',
|
|
30
|
+
id: oneShotId,
|
|
31
|
+
activity: 'inactive',
|
|
32
|
+
hasChildren: false,
|
|
33
|
+
mode: 'one-shot',
|
|
34
|
+
};
|
|
35
|
+
const ctx = new Context();
|
|
36
|
+
await ctx.plugin(SystemPrompt);
|
|
37
|
+
await ctx.plugin(ToolRuntime, {});
|
|
38
|
+
await ctx.plugin(LocalJobRegistry, {});
|
|
39
|
+
await ctx.inject(['tools', 'jobs'], () => applyJobs(ctx, {}));
|
|
40
|
+
const removeSubagents = ctx.provide('subagents', {
|
|
41
|
+
listChildren: async (id, _signal) => {
|
|
42
|
+
listedParents.push(String(id));
|
|
43
|
+
return id === parentId ? [continuable, oneShot] : [];
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
installSubagentJobIdGuard(ctx);
|
|
47
|
+
const agent = { id: parentId, ctx };
|
|
48
|
+
const signal = () => new AbortController().signal;
|
|
49
|
+
const resultText = (result) => {
|
|
50
|
+
const block = result.content[0];
|
|
51
|
+
if (!block || typeof block !== 'object' || !('text' in block))
|
|
52
|
+
return '';
|
|
53
|
+
return typeof block.text === 'string' ? block.text : '';
|
|
54
|
+
};
|
|
55
|
+
const execute = (name, jobId, caller = agent) => ctx.tools.execute({
|
|
56
|
+
callId: `issue-194-${name}-${jobId}`,
|
|
57
|
+
name,
|
|
58
|
+
arguments: { job_id: jobId },
|
|
59
|
+
agent: caller,
|
|
60
|
+
signal: signal(),
|
|
61
|
+
});
|
|
62
|
+
try {
|
|
63
|
+
for (const name of ['job_output', 'job_kill']) {
|
|
64
|
+
const result = await execute(name, durableId);
|
|
65
|
+
assert.equal(result.isError, true);
|
|
66
|
+
assert.match(resultText(result), /^Error: SUBAGENT_ID_IS_NOT_JOB_ID:/);
|
|
67
|
+
assert.match(resultText(result), /continuable subagent durable id, not a background job id/);
|
|
68
|
+
assert.match(resultText(result), /completion notice/);
|
|
69
|
+
assert.match(resultText(result), /list_agents/);
|
|
70
|
+
assert.match(resultText(result), /send_message/);
|
|
71
|
+
if (name === 'job_kill')
|
|
72
|
+
assert.match(resultText(result), /interrupt_agent/);
|
|
73
|
+
assert.match(result.error.message, /SUBAGENT_ID_IS_NOT_JOB_ID/);
|
|
74
|
+
assert.doesNotMatch(result.error.message, /unknown job/);
|
|
75
|
+
}
|
|
76
|
+
// A UUID-shaped but unlisted id keeps native dsh behavior; no global UUID
|
|
77
|
+
// heuristic or jobs ownership expansion is allowed.
|
|
78
|
+
const unrelated = await execute('job_output', '8e7f2c4a-3c92-4ce8-bc2a-2e1bdceec2f4');
|
|
79
|
+
assert.equal(unrelated.isError, true);
|
|
80
|
+
assert.match(resultText(unrelated), /^Error: unknown job /);
|
|
81
|
+
// A one-shot child is not a continuable durable conversation and also keeps
|
|
82
|
+
// native jobs behavior, even when it is visible in the same direct listing.
|
|
83
|
+
const oneShotResult = await execute('job_output', oneShotId);
|
|
84
|
+
assert.equal(oneShotResult.isError, true);
|
|
85
|
+
assert.match(resultText(oneShotResult), /^Error: unknown job /);
|
|
86
|
+
// The lookup is scoped to the exact caller's direct children.
|
|
87
|
+
const otherAgent = { id: unrelatedId, ctx };
|
|
88
|
+
const otherParentResult = await execute('job_output', durableId, otherAgent);
|
|
89
|
+
assert.equal(otherParentResult.isError, true);
|
|
90
|
+
assert.match(resultText(otherParentResult), /^Error: unknown job /);
|
|
91
|
+
assert.deepEqual(listedParents, [parentId, parentId, parentId, parentId, unrelatedId]);
|
|
92
|
+
console.log(JSON.stringify({
|
|
93
|
+
dsh: '0.1.5-rc.1',
|
|
94
|
+
toolRuntime: 'real ToolRuntime + LocalJobRegistry + dsh-tool-jobs',
|
|
95
|
+
guarded: ['job_output', 'job_kill'],
|
|
96
|
+
durableId,
|
|
97
|
+
nativeUnknownIds: 3,
|
|
98
|
+
exactParentLookups: listedParents,
|
|
99
|
+
sharedState: false,
|
|
100
|
+
liveSession: false,
|
|
101
|
+
}));
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
await removeSubagents();
|
|
105
|
+
await ctx.fiber.dispose();
|
|
106
|
+
}
|