@jjh32456/dsh-longlive 1.6.7 → 1.8.0
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/CHANGELOG.md +70 -1508
- package/LICENSE +1 -1
- package/QUICKSTART.md +34 -13
- package/README.en.md +18 -7
- package/README.md +34 -9
- package/SPEC.md +5 -5
- package/cordis.patch.yml +23 -9
- package/docs/ANSWER-GUARD.md +92 -0
- package/docs/ARCHITECTURE.md +4 -3
- package/docs/AUTO-RECALL-WIRING.md +1 -1
- package/docs/AUTO-RECALL.md +15 -9
- package/docs/CONFIG.md +168 -35
- package/docs/ERRORS.md +17 -5
- package/docs/FAQ.md +7 -7
- package/docs/FEATURES.md +96 -28
- package/docs/MIGRATION-1.6.0.md +2 -2
- package/docs/OPERATIONS.md +6 -6
- package/docs/PANEL-INTEGRATION.md +6 -0
- package/docs/PRIVACY.md +88 -0
- package/docs/QUICKSTART.md +5 -5
- package/docs/README.en.md +4 -2
- package/docs/RESIDENT-WATCHER.md +1 -1
- package/docs/SESSION-WATCH.md +6 -6
- package/docs/TROUBLESHOOTING.md +4 -4
- package/package.json +47 -117
- package/runbook.md +2 -2
- package/scripts/backfill-auto-cards.mjs +98 -0
- package/scripts/install-surgery-task.ps1 +5 -2
- package/scripts/lib/session-watch-fixture.mjs +1 -1
- package/scripts/longlive-doctor.mjs +6 -0
- package/scripts/migrate-180.mjs +163 -0
- package/scripts/recall-index-build.mjs +128 -0
- package/scripts/session-watch-drill.mjs +1 -1
- package/scripts/surgery-run.cmd +1 -1
- package/scripts/unattended-surgery.ps1 +5 -2
- package/scripts/verify-card-anchors.mjs +138 -0
- package/src/actions/audit.js +125 -0
- package/src/actions/evidence.js +122 -0
- package/src/actions/fs.js +162 -0
- package/src/activity/index.js +760 -0
- package/src/activity/model.js +351 -0
- package/src/activity/store.js +644 -0
- package/src/activity/thinking.js +176 -0
- package/src/adapters/constants.js +11 -0
- package/src/adapters/engram/data/aliases.json +51 -0
- package/src/adapters/engram/data/policy.json +8 -0
- package/src/adapters/engram/data/routing-rules.json +546 -0
- package/src/adapters/engram/index.js +235 -0
- package/src/adapters/registry.js +315 -0
- package/src/answer/audit.js +193 -0
- package/src/answer/evidence.js +30 -0
- package/src/answer/guard.js +1370 -0
- package/src/answer/index.js +1067 -0
- package/src/answer/query.js +111 -0
- package/src/answer/second-hop.mjs +101 -0
- package/src/auto-truncate.js +1 -1
- package/src/config.js +171 -47
- package/src/deps.js +6 -4
- package/src/features.js +182 -6
- package/src/heartbeat.js +156 -23
- package/src/identity/handover.js +52 -1
- package/src/identity/index.js +13 -5
- package/src/identity/inject-position.js +2 -2
- package/src/index.js +97 -7
- package/src/lifecycle/gap-clocks.js +328 -0
- package/src/lifecycle/index.js +269 -0
- package/src/live.js +22 -2
- package/src/memory/activity-capture.js +229 -0
- package/src/memory/anchors.js +194 -0
- package/src/memory/audit-records.js +222 -0
- package/src/memory/auto-cards.js +401 -0
- package/src/memory/capture.js +442 -0
- package/src/memory/card-anchors.js +203 -0
- package/src/memory/conflicts.js +106 -0
- package/src/memory/decay.js +311 -0
- package/src/memory/distill.js +471 -0
- package/src/memory/event-index.js +917 -0
- package/src/memory/evidence-chain.js +295 -0
- package/src/memory/evidence.js +145 -0
- package/src/memory/filter-runner.js +1 -1
- package/src/memory/filter.js +5 -1
- package/src/memory/forget-v2.js +410 -0
- package/src/memory/forget.js +71 -0
- package/src/memory/frames-activation.js +247 -0
- package/src/memory/fts-query.js +174 -0
- package/src/memory/governance.js +604 -0
- package/src/memory/index.js +1 -0
- package/src/memory/l2-gate.js +169 -0
- package/src/memory/lock.js +121 -0
- package/src/memory/migrate.js +139 -0
- package/src/memory/recall-v2.js +223 -0
- package/src/memory/recall.js +65 -2
- package/src/memory/records.js +425 -0
- package/src/memory/retention.js +128 -0
- package/src/memory/review.js +124 -0
- package/src/memory/trust.js +88 -0
- package/src/memory/version-chain.js +264 -0
- package/src/memory/wal.js +137 -0
- package/src/memory/working-frame.js +516 -0
- package/src/metrics/classify.mjs +5 -3
- package/src/metrics/index.mjs +21 -1
- package/src/metrics/prestep-latency.mjs +300 -0
- package/src/metrics/store.mjs +25 -0
- package/src/policy-profile.js +18 -3
- package/src/recall/anaphora.mjs +87 -0
- package/src/recall/cards.mjs +7 -0
- package/src/recall/embedding.mjs +8 -8
- package/src/recall/entities.mjs +112 -0
- package/src/recall/index.js +235 -19
- package/src/recall/inject-order.mjs +10 -8
- package/src/recall/privacy.mjs +105 -16
- package/src/recall/recall-core.mjs +116 -10
- package/src/recall/shared-visibility.js +302 -0
- package/src/recall/time-normalizer.mjs +196 -0
- package/src/role/activation.js +191 -0
- package/src/role/attention.js +318 -0
- package/src/role/base.js +36 -0
- package/src/role/channels.js +423 -0
- package/src/role/index.js +425 -0
- package/src/role/interfaces.js +115 -0
- package/src/role/personality.js +370 -0
- package/src/role/readers.js +151 -0
- package/src/role/relationships.js +477 -0
- package/src/role/store.js +202 -0
- package/src/role/writeprotect.js +373 -0
- package/src/router/aliases.json +176 -25
- package/src/router/background/agent-runner.mjs +1 -1
- package/src/router/background/anchor.mjs +1 -1
- package/src/router/background/audit.mjs +2 -2
- package/src/router/background/budget-ledger.mjs +2 -2
- package/src/router/background/host-sim.mjs +1 -1
- package/src/router/background/memory.mjs +4 -4
- package/src/router/background/queue.mjs +1 -1
- package/src/router/background/retry.mjs +1 -1
- package/src/router/background/router.mjs +1 -1
- package/src/router/background/stream.mjs +1 -1
- package/src/router/background/tool-policy.mjs +1 -1
- package/src/router/design-headings.json +5 -5
- package/src/router/face/config.mjs +1 -1
- package/src/router/face/identity.mjs +3 -3
- package/src/router/judge.mjs +8 -7
- package/src/router/policies/generic.json +21 -4
- package/src/router/route.js +109 -22
- package/src/router/router.mjs +10 -6
- package/src/router/routing-rules.json +260 -445
- package/src/router/run-sim.mjs +8 -8
- package/src/router/runtime.js +23 -12
- package/src/router/service/board.mjs +95 -15
- package/src/router/service/config.mjs +5 -5
- package/src/router/service/context.mjs +1 -1
- package/src/router/service/hint.mjs +14 -0
- package/src/router/service/queue.mjs +1 -1
- package/src/router/service/service.mjs +27 -11
- package/src/router/shadow.mjs +4 -3
- package/src/surgery-recovery.js +2 -2
- package/src/tool-output.js +2 -2
- package/src/tools.js +39 -7
- package/src/truncate-visible.js +2 -2
- package/src/ui/actions.js +1312 -0
- package/src/ui/panel-api.js +367 -0
- package/src/ui/panel-auth.js +251 -0
- package/src/ui/panel-integrity.js +243 -0
- package/src/ui/routes-readonly.js +695 -0
- package/src/ui/routes.js +3 -0
- package/docs/DEV.md +0 -279
- package/docs/PRESENCE-BUS-WIRING.md +0 -491
- package/docs/PRESENCE-BUS.md +0 -694
- package/docs/SURGERY.md +0 -186
- package/scripts/mark-core-cards.mjs +0 -289
- package/scripts/pack.mjs +0 -392
- package/scripts/router-proposals.mjs +0 -386
- package/src/router/fixtures/M1.json +0 -16
- package/src/router/fixtures/M2.json +0 -16
- package/src/router/fixtures/M3.json +0 -20
- package/src/router/fixtures/M4.json +0 -20
- package/src/router/fixtures/M5.json +0 -45
- package/src/router/fixtures/M6.json +0 -53
- package/src/router/fixtures/M7.json +0 -46
- package/src/router/fixtures/S1.json +0 -20
- package/src/router/fixtures/S2.json +0 -23
- package/src/router/fixtures/S3.json +0 -20
- package/src/router/fixtures/S4.json +0 -34
- package/src/router/fixtures/S5.json +0 -43
- package/src/router/fixtures/S6.json +0 -47
- package/src/router/fixtures/T1.json +0 -23
- package/src/router/fixtures/T2.json +0 -16
- package/src/router/fixtures/T3.json +0 -19
- package/src/router/fixtures/T4.json +0 -16
- package/src/router/fixtures/X1.json +0 -17
- package/src/router/fixtures/X2.json +0 -20
- package/src/router/gen-design-headings.mjs +0 -107
- package/src/router/policies/owner-rulings-2026-11-03.json +0 -62
- package/test/auto-recall.test.mjs +0 -474
- package/test/auto-truncate.test.mjs +0 -931
- package/test/autobind.test.mjs +0 -385
- package/test/bus.test.mjs +0 -1572
- package/test/cli-guard.test.mjs +0 -198
- package/test/conclusion.test.mjs +0 -408
- package/test/config-schema.test.mjs +0 -204
- package/test/d6-output.test.mjs +0 -194
- package/test/d6.test.mjs +0 -395
- package/test/deps.test.mjs +0 -342
- package/test/doctor-setup.test.mjs +0 -297
- package/test/embedding-recall.test.mjs +0 -347
- package/test/feature-flags.test.mjs +0 -568
- package/test/filter-shadow.test.mjs +0 -170
- package/test/fixtures/baseline-0.8.0-registration.json +0 -556
- package/test/fixtures/d6-header-tools.json +0 -1
- package/test/fixtures/lock-child.mjs +0 -67
- package/test/fixtures/pre-step-container.mjs +0 -100
- package/test/fixtures/privacy-memory/topics/pii-unmarked.md +0 -9
- package/test/fixtures/privacy-memory/topics/secret-local-only.md +0 -11
- package/test/fixtures/profile-session-longlive-config.json +0 -20
- package/test/fixtures/proposal-cas-child.mjs +0 -66
- package/test/host-engine-status.test.mjs +0 -307
- package/test/hot-truncate.test.mjs +0 -1349
- package/test/identity-card-marker.test.mjs +0 -307
- package/test/identity-router/run.mjs +0 -721
- package/test/integration-pre-step.test.mjs +0 -553
- package/test/live.test.mjs +0 -1020
- package/test/maintenance-schedule.test.mjs +0 -538
- package/test/memory.test.mjs +0 -2828
- package/test/metrics.test.mjs +0 -478
- package/test/orchestrator.test.mjs +0 -266
- package/test/p1_probe.mjs +0 -97
- package/test/packaging.test.mjs +0 -182
- package/test/portability.test.mjs +0 -343
- package/test/rc4-regressions.test.mjs +0 -562
- package/test/rc5-regressions.test.mjs +0 -197
- package/test/rc6-chinese.test.mjs +0 -394
- package/test/router-1100/apply-off.test.mjs +0 -175
- package/test/router-1100/budget-reconcile.test.mjs +0 -215
- package/test/router-1100/config-context.test.mjs +0 -211
- package/test/router-1100/helpers.mjs +0 -129
- package/test/router-1100/hint-envelope.test.mjs +0 -150
- package/test/router-1100/lock-crossproc.test.mjs +0 -206
- package/test/router-1100/proposal-cas-crossproc.test.mjs +0 -184
- package/test/router-1100/router-apply.test.mjs +0 -372
- package/test/router-1100/router-fixb.test.mjs +0 -602
- package/test/router-1100/router-proposals.test.mjs +0 -405
- package/test/router-1100/router-queue-lease-wal.test.mjs +0 -355
- package/test/router-1100/router-security-cr.test.mjs +0 -333
- package/test/router-1100/service-lifecycle.test.mjs +0 -220
- package/test/router-1100/tools-contract.test.mjs +0 -164
- package/test/router-1100/turn-reflect-tick.test.mjs +0 -89
- package/test/router-1100/v6-contract.test.mjs +0 -158
- package/test/router-1100/v6b-contract.test.mjs +0 -293
- package/test/router-1100/v6c-contract.test.mjs +0 -249
- package/test/router-1100/wal-rotation.test.mjs +0 -375
- package/test/router-1100/wp1-config.test.mjs +0 -170
- package/test/router-1100/wp1-default-off.test.mjs +0 -77
- package/test/router-1100/wp1-model-status.test.mjs +0 -90
- package/test/router-1100/wp1-status.test.mjs +0 -220
- package/test/router-1100/wp1-tools.test.mjs +0 -146
- package/test/router-1100/wp5-cli.test.mjs +0 -240
- package/test/router-1100/wp5-model-auto.test.mjs +0 -418
- package/test/router-1100/wp6-merge.test.mjs +0 -386
- package/test/router-1100/wp6-wake.test.mjs +0 -502
- package/test/router-background/audit.test.mjs +0 -37
- package/test/router-background/budget-ledger.test.mjs +0 -330
- package/test/router-background/cross-process.test.mjs +0 -222
- package/test/router-background/fixtures/cross-child.mjs +0 -85
- package/test/router-background/fixtures/real-shapes.mjs +0 -239
- package/test/router-background/router.test.mjs +0 -1044
- package/test/router-background/stream-retry.test.mjs +0 -358
- package/test/router-background/tool-agent.test.mjs +0 -384
- package/test/router-face/bridge.test.mjs +0 -169
- package/test/router-face/face.test.mjs +0 -316
- package/test/router-failclosed.test.mjs +0 -466
- package/test/router-identity.test.mjs +0 -384
- package/test/router-l1-l2.contract.test.mjs +0 -1075
- package/test/router-memory-tools.test.mjs +0 -262
- package/test/router-policy.test.mjs +0 -225
- package/test/router-runtime.test.mjs +0 -438
- package/test/router-shadow.test.mjs +0 -287
- package/test/router.test.mjs +0 -903
- package/test/run-rc.mjs +0 -299
- package/test/run.mjs +0 -2469
- package/test/safety-defaults.test.mjs +0 -179
- package/test/seeded-load.test.mjs +0 -436
- package/test/session-original.test.mjs +0 -338
- package/test/surgery-recovery.test.mjs +0 -936
- package/test/t7_drive.mjs +0 -151
- package/test/tool-output.test.mjs +0 -393
- package/test/tool-schema.test.mjs +0 -177
- package/test/tools_contract.test.mjs +0 -716
- package/test/truncate-visible.test.mjs +0 -1150
- package/test/ui-flags.test.mjs +0 -477
- package/test/v4-hardening.test.mjs +0 -427
|
@@ -1,307 +0,0 @@
|
|
|
1
|
-
// C1 (1.4.0): engines.dsh startup self-check — data for the panel.
|
|
2
|
-
//
|
|
3
|
-
// Pins the three promises that make this advisory instead of a new failure mode:
|
|
4
|
-
// 1. a mismatch only warns and writes `<memoryRoot>/.longlive/status.json`; it
|
|
5
|
-
// never throws and never stops tools from registering;
|
|
6
|
-
// 2. a matching host writes nothing, and clears a stale mismatch so a fixed
|
|
7
|
-
// installation stops showing the panel red dot;
|
|
8
|
-
// 3. an undetectable/unparseable version is "unknown": plugin loads, no new
|
|
9
|
-
// record, no crash, and an existing record is left untouched.
|
|
10
|
-
//
|
|
11
|
-
// The host-manifest fallback is also exercised with temp files and an injected
|
|
12
|
-
// `readFile`, so no test depends on the machine's real DSH installation.
|
|
13
|
-
|
|
14
|
-
import fs from 'node:fs';
|
|
15
|
-
import os from 'node:os';
|
|
16
|
-
import path from 'node:path';
|
|
17
|
-
import { fileURLToPath } from 'node:url';
|
|
18
|
-
import test from 'node:test';
|
|
19
|
-
import assert from 'node:assert/strict';
|
|
20
|
-
|
|
21
|
-
import { apply } from '../src/index.js';
|
|
22
|
-
import {
|
|
23
|
-
HOST_PACKAGE_ENV,
|
|
24
|
-
detectHostPackageVersion,
|
|
25
|
-
detectHostVersion,
|
|
26
|
-
hostPackageCandidates,
|
|
27
|
-
} from '../src/host-version.js';
|
|
28
|
-
import {
|
|
29
|
-
ENGINE_STATUS_DIR,
|
|
30
|
-
ENGINE_STATUS_FILE,
|
|
31
|
-
engineStatusPath,
|
|
32
|
-
recordEngineStatus,
|
|
33
|
-
} from '../src/engine-status.js';
|
|
34
|
-
|
|
35
|
-
const PACKAGE_ROOT = path.dirname(fileURLToPath(new URL('../package.json', import.meta.url)));
|
|
36
|
-
const DECLARED_RANGE = JSON.parse(fs.readFileSync(path.join(PACKAGE_ROOT, 'package.json'), 'utf8')).engines.dsh;
|
|
37
|
-
const FIXED_NOW = '2026-11-05T13:02:01.000Z';
|
|
38
|
-
|
|
39
|
-
function tempDir(t, prefix = 'longlive-engine-') {
|
|
40
|
-
const dir = fs.mkdtempSync(path.join(os.tmpdir(), prefix));
|
|
41
|
-
t.after(() => fs.rmSync(dir, { recursive: true, force: true }));
|
|
42
|
-
return dir;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function statusFile(memoryRoot) {
|
|
46
|
-
return path.join(memoryRoot, ENGINE_STATUS_DIR, ENGINE_STATUS_FILE);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function readStatus(memoryRoot) {
|
|
50
|
-
return JSON.parse(fs.readFileSync(statusFile(memoryRoot), 'utf8'));
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function writeStatus(memoryRoot, value) {
|
|
54
|
-
const file = statusFile(memoryRoot);
|
|
55
|
-
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
56
|
-
fs.writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function fakeContext() {
|
|
60
|
-
const tools = [];
|
|
61
|
-
const warnings = [];
|
|
62
|
-
const hooks = [];
|
|
63
|
-
const ctx = {
|
|
64
|
-
tools: {
|
|
65
|
-
register(definition) {
|
|
66
|
-
tools.push(definition);
|
|
67
|
-
return () => {};
|
|
68
|
-
},
|
|
69
|
-
},
|
|
70
|
-
on(name, listener) {
|
|
71
|
-
hooks.push({ name, listener });
|
|
72
|
-
return () => {};
|
|
73
|
-
},
|
|
74
|
-
logger() {
|
|
75
|
-
return { warn: (message) => warnings.push(String(message)), info() {}, debug() {} };
|
|
76
|
-
},
|
|
77
|
-
effect(fn) {
|
|
78
|
-
const dispose = fn();
|
|
79
|
-
return typeof dispose === 'function' ? dispose : () => {};
|
|
80
|
-
},
|
|
81
|
-
};
|
|
82
|
-
return { ctx, tools, warnings, hooks };
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function runApply(t, config = {}, prepare = null) {
|
|
86
|
-
const temp = tempDir(t);
|
|
87
|
-
const home = path.join(temp, 'home');
|
|
88
|
-
const memoryRoot = path.join(temp, 'memory');
|
|
89
|
-
fs.mkdirSync(home, { recursive: true });
|
|
90
|
-
fs.mkdirSync(memoryRoot, { recursive: true });
|
|
91
|
-
if (prepare) prepare({ temp, home, memoryRoot });
|
|
92
|
-
|
|
93
|
-
const { ctx, tools, warnings } = fakeContext();
|
|
94
|
-
const returned = apply(ctx, {
|
|
95
|
-
home,
|
|
96
|
-
memoryRoot,
|
|
97
|
-
env: {},
|
|
98
|
-
heartbeatMs: 0,
|
|
99
|
-
recoverOnStart: false,
|
|
100
|
-
filterEnabled: false,
|
|
101
|
-
routerRuntime: 'off',
|
|
102
|
-
defineTool: (definition) => definition,
|
|
103
|
-
now: () => Date.parse(FIXED_NOW),
|
|
104
|
-
...config,
|
|
105
|
-
});
|
|
106
|
-
return { temp, home, memoryRoot, ctx, tools, warnings, returned };
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// ---------------------------------------------------------------------------
|
|
110
|
-
// Host manifest fallback
|
|
111
|
-
// ---------------------------------------------------------------------------
|
|
112
|
-
|
|
113
|
-
test('detectHostVersion reads a host package.json through config.hostPackagePath', (t) => {
|
|
114
|
-
const dir = tempDir(t);
|
|
115
|
-
const manifest = path.join(dir, 'package.json');
|
|
116
|
-
fs.writeFileSync(manifest, JSON.stringify({
|
|
117
|
-
name: '@deepseek-ai/dsh-desktop-runtime',
|
|
118
|
-
version: '0.2.2',
|
|
119
|
-
}), 'utf8');
|
|
120
|
-
|
|
121
|
-
const detection = detectHostVersion({}, { hostPackagePath: manifest }, {});
|
|
122
|
-
assert.equal(detection.version, '0.2.2');
|
|
123
|
-
assert.equal(detection.source, 'hostPackage');
|
|
124
|
-
assert.equal(detection.path, manifest);
|
|
125
|
-
assert.equal(detection.origin, 'config.hostPackagePath');
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
test('detectHostVersion understands the desktop-runtime.json release.version shape', (t) => {
|
|
129
|
-
const dir = tempDir(t);
|
|
130
|
-
const runtime = path.join(dir, 'desktop-runtime.json');
|
|
131
|
-
fs.writeFileSync(runtime, JSON.stringify({ release: { version: '0.2.1-rc.5' } }), 'utf8');
|
|
132
|
-
|
|
133
|
-
const detection = detectHostVersion({}, { hostPackagePath: runtime }, {});
|
|
134
|
-
assert.equal(detection.version, '0.2.1-rc.5');
|
|
135
|
-
assert.equal(detection.path, runtime);
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
test('a corrupt or missing host manifest is skipped, and the next candidate wins', (t) => {
|
|
139
|
-
const dir = tempDir(t);
|
|
140
|
-
const broken = path.join(dir, 'package.json');
|
|
141
|
-
fs.writeFileSync(broken, '{ not json', 'utf8');
|
|
142
|
-
const valid = path.join(dir, 'fallback-package.json');
|
|
143
|
-
fs.writeFileSync(valid, JSON.stringify({ version: '0.3.0' }), 'utf8');
|
|
144
|
-
|
|
145
|
-
const viaEnv = detectHostVersion({}, { hostPackagePath: broken }, { [HOST_PACKAGE_ENV]: valid });
|
|
146
|
-
assert.equal(viaEnv.version, '0.3.0');
|
|
147
|
-
assert.equal(viaEnv.path, valid);
|
|
148
|
-
assert.equal(viaEnv.origin, `env.${HOST_PACKAGE_ENV}`);
|
|
149
|
-
|
|
150
|
-
const missing = detectHostVersion({}, { hostPackagePath: path.join(dir, 'nope.json') }, {});
|
|
151
|
-
assert.equal(missing.version, null);
|
|
152
|
-
assert.equal(missing.source, null);
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
test('hostPackageCandidates is dependency-free, ordered, and de-duplicated', () => {
|
|
156
|
-
const configPath = path.resolve('C:/fake/config/package.json');
|
|
157
|
-
const envPath = path.resolve('C:/fake/env/package.json');
|
|
158
|
-
const candidates = hostPackageCandidates({
|
|
159
|
-
configPath,
|
|
160
|
-
env: { [HOST_PACKAGE_ENV]: envPath },
|
|
161
|
-
resourcesPath: path.resolve('C:/fake/resources'),
|
|
162
|
-
execPath: path.resolve('C:/fake/install/Harness.exe'),
|
|
163
|
-
});
|
|
164
|
-
const paths = candidates.map((entry) => entry.path);
|
|
165
|
-
assert.equal(paths[0], configPath);
|
|
166
|
-
assert.equal(paths[1], envPath);
|
|
167
|
-
assert.ok(paths.includes(path.resolve('C:/fake/resources/app.asar/dsh/package.json')));
|
|
168
|
-
assert.ok(paths.includes(path.resolve('C:/fake/resources/app.asar/dsh/desktop-runtime.json')));
|
|
169
|
-
assert.ok(paths.includes(path.resolve('C:/fake/install/resources/app.asar/dsh/package.json')));
|
|
170
|
-
assert.equal(new Set(paths).size, paths.length, 'no duplicate candidate paths');
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
test('an unreadable host manifest is unknown, not an exception', () => {
|
|
174
|
-
const detection = detectHostPackageVersion({
|
|
175
|
-
configPath: path.resolve('C:/fake/missing/package.json'),
|
|
176
|
-
env: {},
|
|
177
|
-
resourcesPath: undefined,
|
|
178
|
-
execPath: path.resolve('C:/fake/node.exe'),
|
|
179
|
-
readFile: () => { throw Object.assign(new Error('ENOENT'), { code: 'ENOENT' }); },
|
|
180
|
-
});
|
|
181
|
-
assert.equal(detection, null);
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
// ---------------------------------------------------------------------------
|
|
185
|
-
// apply(): mismatch / match / unknown
|
|
186
|
-
// ---------------------------------------------------------------------------
|
|
187
|
-
|
|
188
|
-
test('mismatch: plugin still registers every tool and writes the panel record', (t) => {
|
|
189
|
-
const run = runApply(t, { hostVersion: '0.1.0' });
|
|
190
|
-
|
|
191
|
-
assert.ok(run.returned, 'apply returned normally');
|
|
192
|
-
assert.ok(run.tools.length >= 20, `expected the full tool table, got ${run.tools.length}`);
|
|
193
|
-
assert.ok(run.tools.some((tool) => tool.name === 'session_truncate'), 'session_truncate is registered');
|
|
194
|
-
assert.ok(run.warnings.some((line) => line.includes('0.1.0') && line.includes(DECLARED_RANGE)),
|
|
195
|
-
`a mismatch warning naming both ends is emitted: ${run.warnings.join(' | ')}`);
|
|
196
|
-
assert.ok(run.warnings.some((line) => line.includes('降级')), 'warning says the plugin degrades');
|
|
197
|
-
|
|
198
|
-
const status = readStatus(run.memoryRoot);
|
|
199
|
-
assert.deepEqual(status.engineMismatch, {
|
|
200
|
-
hostVersion: '0.1.0',
|
|
201
|
-
required: DECLARED_RANGE,
|
|
202
|
-
at: FIXED_NOW,
|
|
203
|
-
source: 'config.hostVersion',
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
const leftovers = fs.readdirSync(path.join(run.memoryRoot, ENGINE_STATUS_DIR))
|
|
207
|
-
.filter((name) => name.includes('.tmp-'));
|
|
208
|
-
assert.deepEqual(leftovers, [], 'no temporary write file is left behind');
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
test('mismatch through the environment uses the env source label', (t) => {
|
|
212
|
-
const run = runApply(t, { env: { DSH_HOST_VERSION: '2.0.0' } });
|
|
213
|
-
|
|
214
|
-
assert.ok(run.tools.length >= 20);
|
|
215
|
-
const status = readStatus(run.memoryRoot);
|
|
216
|
-
assert.equal(status.engineMismatch.hostVersion, '2.0.0');
|
|
217
|
-
assert.equal(status.engineMismatch.source, 'env.DSH_HOST_VERSION');
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
test('match: no record is written', (t) => {
|
|
221
|
-
const run = runApply(t, { hostVersion: '0.9.0' });
|
|
222
|
-
|
|
223
|
-
assert.ok(run.tools.length >= 20);
|
|
224
|
-
assert.equal(fs.existsSync(statusFile(run.memoryRoot)), false, 'a matching host writes nothing');
|
|
225
|
-
assert.equal(run.warnings.some((line) => line.includes('0.9.0')), false, 'no warning on a match');
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
test('match clears a stale engineMismatch but keeps unrelated keys', (t) => {
|
|
229
|
-
const run = runApply(t, { hostVersion: '0.7.0' }, ({ memoryRoot }) => {
|
|
230
|
-
writeStatus(memoryRoot, {
|
|
231
|
-
at: '2026-11-01T00:00:00.000Z',
|
|
232
|
-
ok: true,
|
|
233
|
-
engineMismatch: { hostVersion: '0.1.0', required: DECLARED_RANGE, at: '2026-11-01T00:00:00.000Z' },
|
|
234
|
-
});
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
const status = readStatus(run.memoryRoot);
|
|
238
|
-
assert.equal(status.engineMismatch, undefined);
|
|
239
|
-
assert.equal(status.ok, true);
|
|
240
|
-
assert.equal(status.at, '2026-11-01T00:00:00.000Z');
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
test('match deletes status.json when engineMismatch was its only key', (t) => {
|
|
244
|
-
const run = runApply(t, { hostVersion: '0.7.1' }, ({ memoryRoot }) => {
|
|
245
|
-
writeStatus(memoryRoot, {
|
|
246
|
-
engineMismatch: { hostVersion: '0.1.0', required: DECLARED_RANGE, at: '2026-11-01T00:00:00.000Z' },
|
|
247
|
-
});
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
assert.equal(fs.existsSync(statusFile(run.memoryRoot)), false, 'stale file is removed');
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
test('unknown: an unparseable host version loads, warns about nothing, writes nothing', (t) => {
|
|
254
|
-
const run = runApply(t, { hostVersion: 'not-a-version' });
|
|
255
|
-
|
|
256
|
-
assert.ok(run.tools.length >= 20);
|
|
257
|
-
assert.equal(fs.existsSync(statusFile(run.memoryRoot)), false);
|
|
258
|
-
assert.equal(run.warnings.some((line) => line.includes('not-a-version')), false);
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
test('unknown: a direct verdict leaves an existing record untouched', (t) => {
|
|
262
|
-
const root = tempDir(t);
|
|
263
|
-
writeStatus(root, { engineMismatch: { hostVersion: '0.1.0', required: DECLARED_RANGE, at: FIXED_NOW } });
|
|
264
|
-
|
|
265
|
-
const result = recordEngineStatus(root, {
|
|
266
|
-
compat: { status: 'unknown', version: 'nope', range: DECLARED_RANGE, warning: null },
|
|
267
|
-
now: () => new Date(FIXED_NOW),
|
|
268
|
-
});
|
|
269
|
-
assert.equal(result.ok, true);
|
|
270
|
-
assert.equal(result.action, 'unknown');
|
|
271
|
-
assert.equal(readStatus(root).engineMismatch.hostVersion, '0.1.0');
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
test('a memoryRoot path that is a file warns but never blocks activation', (t) => {
|
|
275
|
-
const temp = tempDir(t);
|
|
276
|
-
const home = path.join(temp, 'home');
|
|
277
|
-
fs.mkdirSync(home, { recursive: true });
|
|
278
|
-
const bogusRoot = path.join(temp, 'not-a-directory');
|
|
279
|
-
fs.writeFileSync(bogusRoot, 'x', 'utf8');
|
|
280
|
-
|
|
281
|
-
const { ctx, tools, warnings } = fakeContext();
|
|
282
|
-
assert.doesNotThrow(() => {
|
|
283
|
-
apply(ctx, {
|
|
284
|
-
home,
|
|
285
|
-
memoryRoot: bogusRoot,
|
|
286
|
-
hostVersion: '0.1.1',
|
|
287
|
-
env: {},
|
|
288
|
-
heartbeatMs: 0,
|
|
289
|
-
recoverOnStart: false,
|
|
290
|
-
filterEnabled: false,
|
|
291
|
-
routerRuntime: 'off',
|
|
292
|
-
defineTool: (definition) => definition,
|
|
293
|
-
});
|
|
294
|
-
});
|
|
295
|
-
assert.ok(tools.length >= 20, 'tools still load when the status file cannot be written');
|
|
296
|
-
assert.ok(warnings.some((line) => line.includes('记忆根目录')), 'the bad root is reported');
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
test('recordEngineStatus with no memoryRoot is a silent no-op', () => {
|
|
300
|
-
assert.equal(engineStatusPath(''), null);
|
|
301
|
-
assert.equal(engineStatusPath(' '), null);
|
|
302
|
-
const result = recordEngineStatus(null, {
|
|
303
|
-
compat: { status: 'mismatch', version: '0.1.0', range: DECLARED_RANGE, warning: 'x' },
|
|
304
|
-
});
|
|
305
|
-
assert.equal(result.ok, false);
|
|
306
|
-
assert.equal(result.action, 'no-memory-root');
|
|
307
|
-
});
|