my-durable 0.0.0-stage → 0.0.2
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/.env.example +7 -0
- package/LICENSE +21 -0
- package/README.md +328 -2
- package/ai_docs/durable_pi/announcement.md +860 -0
- package/ai_docs/durable_pi/changelog.md +51 -0
- package/ai_docs/durable_pi/chord-delta-findings.md +362 -0
- package/ai_docs/durable_pi/coding-agent-integration.md +70 -0
- package/ai_docs/durable_pi/pico-v5-chord-usage.md +391 -0
- package/ai_docs/durable_pi/pico-v5-handoff.md +921 -0
- package/ai_docs/durable_pi/readme.md +617 -0
- package/ai_docs/durable_pi/sources.md +22 -0
- package/ai_docs/durable_pi/spec.md +4696 -0
- package/ai_docs/durable_pi/vacation-planner.md +57 -0
- package/ai_docs/pi/chord.md +268 -0
- package/ai_docs/pi/cli-integration.md +110 -0
- package/ai_docs/pi/cli.md +325 -0
- package/ai_docs/pi/codemode.md +211 -0
- package/ai_docs/pi/compaction.md +467 -0
- package/ai_docs/pi/configuration.md +51 -0
- package/ai_docs/pi/containerization.md +187 -0
- package/ai_docs/pi/custom-provider.md +177 -0
- package/ai_docs/pi/environment-variables.md +102 -0
- package/ai_docs/pi/extensions.md +278 -0
- package/ai_docs/pi/how-pi-works.md +53 -0
- package/ai_docs/pi/index.md +43 -0
- package/ai_docs/pi/json.md +230 -0
- package/ai_docs/pi/keybindings.md +198 -0
- package/ai_docs/pi/llama-cpp.md +118 -0
- package/ai_docs/pi/mcp.md +274 -0
- package/ai_docs/pi/message-types.md +265 -0
- package/ai_docs/pi/models.md +209 -0
- package/ai_docs/pi/overview.md +166 -0
- package/ai_docs/pi/packages.md +133 -0
- package/ai_docs/pi/pi-agent-core.md +568 -0
- package/ai_docs/pi/pi-ai.md +1942 -0
- package/ai_docs/pi/prompt-templates.md +63 -0
- package/ai_docs/pi/providers.md +204 -0
- package/ai_docs/pi/quickstart.md +140 -0
- package/ai_docs/pi/readme.md +99 -0
- package/ai_docs/pi/rpc-commands.md +864 -0
- package/ai_docs/pi/rpc-extension-ui.md +204 -0
- package/ai_docs/pi/rpc.md +197 -0
- package/ai_docs/pi/sdk.md +151 -0
- package/ai_docs/pi/security.md +103 -0
- package/ai_docs/pi/session-format.md +297 -0
- package/ai_docs/pi/sessions.md +70 -0
- package/ai_docs/pi/settings.md +173 -0
- package/ai_docs/pi/shell-aliases.md +97 -0
- package/ai_docs/pi/skills.md +97 -0
- package/ai_docs/pi/slash-commands.md +64 -0
- package/ai_docs/pi/sources.md +57 -0
- package/ai_docs/pi/terminal-setup.md +223 -0
- package/ai_docs/pi/termux.md +121 -0
- package/ai_docs/pi/themes.md +140 -0
- package/ai_docs/pi/tmux.md +59 -0
- package/ai_docs/pi/toolkit.md +168 -0
- package/ai_docs/pi/tui.md +129 -0
- package/ai_docs/pi/usage.md +98 -0
- package/ai_docs/pi/virtual-models.md +118 -0
- package/ai_docs/pi/windows.md +71 -0
- package/apps/dpi-backend/.nvmrc +1 -0
- package/apps/dpi-backend/API.md +99 -0
- package/apps/dpi-backend/README.md +119 -0
- package/apps/dpi-backend/deploy/backend.env.example +9 -0
- package/apps/dpi-backend/deploy/dpi-backend.plist +26 -0
- package/apps/dpi-backend/deploy/dpi-backend.service +22 -0
- package/apps/dpi-backend/package.json +33 -0
- package/apps/dpi-backend/prompts/one_sentence.md +3 -0
- package/apps/dpi-backend/prompts/smart_ass_opus_fix.md +169 -0
- package/apps/dpi-backend/scripts/check-contract.mjs +151 -0
- package/apps/dpi-backend/scripts/migrate-playground.ts +66 -0
- package/apps/dpi-backend/scripts/record-nested-fixture.mts +154 -0
- package/apps/dpi-backend/scripts/token.ts +57 -0
- package/apps/dpi-backend/src/addons.ts +139 -0
- package/apps/dpi-backend/src/auth.ts +20 -0
- package/apps/dpi-backend/src/config.ts +54 -0
- package/apps/dpi-backend/src/contract-check.ts +118 -0
- package/apps/dpi-backend/src/errors.ts +50 -0
- package/apps/dpi-backend/src/extensions.ts +510 -0
- package/apps/dpi-backend/src/faux.ts +80 -0
- package/apps/dpi-backend/src/history.ts +165 -0
- package/apps/dpi-backend/src/idempotency.ts +20 -0
- package/apps/dpi-backend/src/jev.ts +43 -0
- package/apps/dpi-backend/src/jobs.ts +790 -0
- package/apps/dpi-backend/src/main.ts +76 -0
- package/apps/dpi-backend/src/model-catalog.ts +180 -0
- package/apps/dpi-backend/src/pairing-files.ts +142 -0
- package/apps/dpi-backend/src/pairing.ts +459 -0
- package/apps/dpi-backend/src/routes.ts +217 -0
- package/apps/dpi-backend/src/shared-state.ts +85 -0
- package/apps/dpi-backend/src/store.ts +1240 -0
- package/apps/dpi-backend/src/streams.ts +256 -0
- package/apps/dpi-backend/src/tunnel.ts +955 -0
- package/apps/dpi-backend/tsconfig.json +13 -0
- package/apps/dpi-playground/README.md +83 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/assets/index-CFGc7lHT.js +77 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/assets/index-DFdKpwm_.css +1 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/anthropic.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/deepseek.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/durable-pi.svg +14 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/gemini.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/grok.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/kimi.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/lab.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/meta.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/minimax.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/openai.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/qwen.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/xiaomi.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/zai.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/index.html +16 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/index.html +15 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/package.json +5 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/anthropic.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/deepseek.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/durable-pi.svg +14 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/gemini.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/grok.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/kimi.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/lab.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/meta.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/minimax.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/openai.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/qwen.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/xiaomi.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/zai.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/App.vue +180 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/commands.ts +119 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/composables.ts +129 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/hub.ts +40 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/icon-path.ts +7 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/ids.ts +2 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/jobs.ts +80 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/link-policy.ts +16 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/markdown-policy.ts +115 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/markdown.ts +60 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/pair-close.ts +23 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/pair-handoff.ts +56 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/pair.ts +166 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/qrcode.ts +323 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/signature.ts +146 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/store.ts +373 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/stream.ts +183 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/AgentView.vue +342 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/Composer.vue +198 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/ContextBar.vue +254 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/DeviceCredentialsDialog.vue +40 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/DeviceIcon.vue +56 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/DirBrowser.vue +95 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/ExtensionsPanel.vue +96 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/HelpDialog.vue +69 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/Inspector.vue +425 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/JobCard.vue +221 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/MobileNav.vue +39 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/ModelPicker.vue +71 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/NetworkSidebar.vue +236 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/NewSessionDialog.vue +114 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/OfflinePanel.vue +128 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/PairDeviceWizard.vue +433 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/PromptDialog.vue +89 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/StateEditor.vue +179 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/TasksPanel.vue +280 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/Toast.vue +11 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/TokenManager.vue +175 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/TopBar.vue +114 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/TranscriptItem.vue +152 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/TreeRow.vue +195 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/TunnelStatusBar.vue +107 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/extensions.css +105 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/jobs.css +655 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/main.ts +22 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/network.css +675 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/style.css +3203 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/tsconfig.json +16 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/vite.config.ts +14 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/package.json +5 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/audit.ts +406 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/client-ip.ts +72 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/credentials.ts +265 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/guard.ts +43 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/http-errors.ts +156 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/identity.ts +60 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/limiter.ts +165 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/main.ts +460 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/monitor.ts +320 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/mux.ts +277 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/pairing.ts +816 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/proxy.ts +128 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/rotation.ts +583 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/seed.ts +11 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/transport.ts +108 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/tunnel-token.ts +11 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/tunnel-transport.ts +560 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/tunnel.ts +873 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/tsconfig.json +13 -0
- package/apps/dpi-playground/package.json +37 -0
- package/apps/dpi-sdk/README.md +74 -0
- package/apps/dpi-sdk/package.json +20 -0
- package/apps/dpi-sdk/scripts/net.ts +73 -0
- package/apps/dpi-sdk/src/api.ts +631 -0
- package/apps/dpi-sdk/src/app-state.ts +111 -0
- package/apps/dpi-sdk/src/client.ts +330 -0
- package/apps/dpi-sdk/src/errors.ts +16 -0
- package/apps/dpi-sdk/src/jobs.ts +99 -0
- package/apps/dpi-sdk/src/models.ts +472 -0
- package/apps/dpi-sdk/src/node/chunk.ts +488 -0
- package/apps/dpi-sdk/src/node/config.ts +175 -0
- package/apps/dpi-sdk/src/node/drivers.ts +402 -0
- package/apps/dpi-sdk/src/node/ops.ts +114 -0
- package/apps/dpi-sdk/src/node/private-dir.ts +48 -0
- package/apps/dpi-sdk/src/node/registry-migration.ts +549 -0
- package/apps/dpi-sdk/src/node/registry.ts +390 -0
- package/apps/dpi-sdk/src/node/sse-writer.ts +151 -0
- package/apps/dpi-sdk/src/protocol/backoff.ts +31 -0
- package/apps/dpi-sdk/src/protocol/limits.ts +199 -0
- package/apps/dpi-sdk/src/protocol/pairing.ts +311 -0
- package/apps/dpi-sdk/src/protocol/rest-routes.ts +105 -0
- package/apps/dpi-sdk/src/protocol/tunnel.ts +331 -0
- package/apps/dpi-sdk/src/sse.ts +117 -0
- package/apps/dpi-sdk/src/transcript.ts +291 -0
- package/apps/dpi-sdk/tsconfig.json +13 -0
- package/apps/dpi-sdk/w +20 -0
- package/apps/dpi-tui/README.md +54 -0
- package/apps/dpi-tui/bin/dpi-tui.mjs +5 -0
- package/apps/dpi-tui/package.json +20 -0
- package/apps/dpi-tui/src/app.ts +433 -0
- package/apps/dpi-tui/src/commands.ts +151 -0
- package/apps/dpi-tui/src/main.ts +122 -0
- package/apps/dpi-tui/src/pairing.ts +287 -0
- package/apps/dpi-tui/src/pickers.ts +238 -0
- package/apps/dpi-tui/src/render.ts +164 -0
- package/apps/dpi-tui/src/theme.ts +57 -0
- package/apps/dpi-tui/tsconfig.json +14 -0
- package/bin/device.mjs +5 -0
- package/bin/hub.mjs +5 -0
- package/bin/tui.mjs +5 -0
- package/deploy/Caddyfile +120 -0
- package/docs/verification.md +102 -0
- package/dpi-network.example.yaml +62 -0
- package/images/01_durable_agent_network.svg +185 -0
- package/images/02_pi_made_durable.svg +204 -0
- package/images/03_restart_mid_tool.svg +168 -0
- package/images/07_one_api_every_client.svg +123 -0
- package/images/08_device_session_agent.svg +123 -0
- package/images/09_compact_keep_history.svg +143 -0
- package/images/10_shared_app_state.svg +177 -0
- package/images/11_durable_jobs_wait.svg +141 -0
- package/images/12_tools_change_mid_run.svg +231 -0
- package/images/13_hook_blocks_tool.svg +122 -0
- package/images/14_fork_at_any_entry.svg +119 -0
- package/images/15_web_client.png +0 -0
- package/images/16_terminal_client.svg +43 -0
- package/images/17_devices_are_data.svg +182 -0
- package/images/18_should_every_agent_be_durable.svg +118 -0
- package/images/19_sqlite_on_every_device.svg +155 -0
- package/images/20_admission_and_effects.svg +134 -0
- package/justfile +33 -0
- package/package.json +41 -4
- package/scripts/verify.mjs +210 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* scripts/verify.mjs — P2-27 consolidated verification runner.
|
|
4
|
+
*
|
|
5
|
+
* node scripts/verify.mjs --phase P2 # core local suites
|
|
6
|
+
* node scripts/verify.mjs --phase all # core + lint + browser + PTY
|
|
7
|
+
*
|
|
8
|
+
* Contract:
|
|
9
|
+
* - Preflight checks (node version, per-app toolchain, Caddy binary) run first.
|
|
10
|
+
* - Suites run with an explicit cwd (never the repo root) and a fresh env.
|
|
11
|
+
* - Inventory: every case family → suite → report line is printed; a suite
|
|
12
|
+
* that fails OR cannot run makes the whole run exit nonzero.
|
|
13
|
+
* - Output is a summary, not an automatically saved evidence manifest.
|
|
14
|
+
* Failure output is truncated; fixtures mint throwaway credentials.
|
|
15
|
+
* - No deploy or paid models; test servers bind loopback.
|
|
16
|
+
* - NAT/M1–M4 acceptance (P2-29), restore/quarantine (D-4, P3) and
|
|
17
|
+
* Gate A/B approval are not evaluated by this local runner. `--phase all`
|
|
18
|
+
* does run the R-1 recovery timing alone and prints every sample, but that
|
|
19
|
+
* is a local measurement, not the P2-29 acceptance run.
|
|
20
|
+
*/
|
|
21
|
+
import { spawnSync } from "node:child_process";
|
|
22
|
+
import { statSync } from "node:fs";
|
|
23
|
+
import { dirname, join, resolve } from "node:path";
|
|
24
|
+
import { fileURLToPath } from "node:url";
|
|
25
|
+
|
|
26
|
+
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
27
|
+
const args = process.argv.slice(2);
|
|
28
|
+
const phaseIndex = args.indexOf("--phase");
|
|
29
|
+
const phaseFlag = phaseIndex === -1 ? undefined : args[phaseIndex + 1];
|
|
30
|
+
if (phaseIndex !== -1 && (!phaseFlag || phaseFlag.startsWith("--"))) {
|
|
31
|
+
process.stderr.write("--phase requires P0, P1, P2 or all\n");
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
const phase = (phaseFlag ?? "P2").toUpperCase();
|
|
35
|
+
|
|
36
|
+
const ok = (msg) => process.stdout.write(` \x1b[32m✓\x1b[0m ${msg}\n`);
|
|
37
|
+
const bad = (msg) => process.stdout.write(` \x1b[31m✗\x1b[0m ${msg}\n`);
|
|
38
|
+
const info = (msg) => process.stdout.write(` \x1b[2m${msg}\x1b[0m\n`);
|
|
39
|
+
|
|
40
|
+
// ---------------------------------------------------------------- preflight
|
|
41
|
+
|
|
42
|
+
function preflight() {
|
|
43
|
+
const problems = [];
|
|
44
|
+
const major = Number(process.versions.node.split(".")[0]);
|
|
45
|
+
if (major < 22) problems.push(`node ${process.versions.node} — tests need >= 22 (node:sqlite)`);
|
|
46
|
+
else ok(`node ${process.versions.node}`);
|
|
47
|
+
for (const dir of ["apps/dpi-sdk", "apps/dpi-backend", "apps/dpi-playground", "apps/dpi-tui"]) {
|
|
48
|
+
try {
|
|
49
|
+
statSync(join(ROOT, dir, "package.json"));
|
|
50
|
+
statSync(join(ROOT, dir, "node_modules"));
|
|
51
|
+
} catch {
|
|
52
|
+
problems.push(`${dir}: package.json/node_modules missing — run npm install there`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (!problems.some((p) => p.includes("node_modules"))) ok("toolchain: 4 apps installed");
|
|
56
|
+
const caddy = join(ROOT, "tools", "caddy");
|
|
57
|
+
try {
|
|
58
|
+
statSync(caddy);
|
|
59
|
+
ok("tools/caddy present (Caddy deploy tests)");
|
|
60
|
+
} catch {
|
|
61
|
+
info("tools/caddy absent — Caddy deploy tests will fail if the P2 suite includes them");
|
|
62
|
+
}
|
|
63
|
+
if (problems.length) {
|
|
64
|
+
for (const p of problems) bad(p);
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ---------------------------------------------------------------- suites
|
|
70
|
+
|
|
71
|
+
/** Build/type gates (review 2026-10-20 item 5): a green test runner must
|
|
72
|
+
* never again coexist with a broken Web build or a dead compile-negative
|
|
73
|
+
* fixture. These run FIRST so failures fail fast. */
|
|
74
|
+
const GATES = {
|
|
75
|
+
"test:verification": { cwd: ".", cmd: ["node", "--test", "scripts/verify.test.mjs"], title: "verification CLI regressions" },
|
|
76
|
+
"check:sdk": { cwd: "apps/dpi-sdk", cmd: ["npm", "run", "check"], title: "dpi-sdk type-check" },
|
|
77
|
+
"check:backend": { cwd: "apps/dpi-backend", cmd: ["npm", "run", "check"], title: "dpi-backend type-check" },
|
|
78
|
+
"contract:backend": { cwd: "apps/dpi-backend", cmd: ["npm", "run", "check:contract"], title: "compile-negative wire-contract fixture (control + 5 mutations)" },
|
|
79
|
+
"build:playground": { cwd: "apps/dpi-playground", cmd: ["npm", "run", "build"], title: "vue-tsc FE + hub tsc + vite build (Web UI must ship)" },
|
|
80
|
+
"check:tui": { cwd: "apps/dpi-tui", cmd: ["npm", "run", "check"], title: "dpi-tui type-check" },
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const SUITES = {
|
|
84
|
+
sdk: {
|
|
85
|
+
cwd: "apps/dpi-sdk",
|
|
86
|
+
cmd: ["npx", "tsx", "--test", "tests/*.test.ts"],
|
|
87
|
+
title: "dpi-sdk: protocol/limits/chunk/registry/DTO (D-1..D-3, W-2 fixture, W-3 TypeBox runtime)",
|
|
88
|
+
},
|
|
89
|
+
backend: {
|
|
90
|
+
cwd: "apps/dpi-backend",
|
|
91
|
+
cmd: ["npx", "tsx", "--test", "tests/*.test.ts"],
|
|
92
|
+
title: "dpi-backend: pairing files/flows, connector, REST (P-4/P-5/P-13, T-2 partial)",
|
|
93
|
+
},
|
|
94
|
+
"timing:backend": {
|
|
95
|
+
cwd: "apps/dpi-backend",
|
|
96
|
+
cmd: ["npm", "run", "test:timing"],
|
|
97
|
+
title: "R-1/M4 SIGKILL recovery timing, run alone: strict < 2 s from before the kill, every sample reported (this machine only)",
|
|
98
|
+
report: /^# (M4 R-1 (?:pass|fail):.*)$/m,
|
|
99
|
+
},
|
|
100
|
+
playground: {
|
|
101
|
+
cwd: "apps/dpi-playground",
|
|
102
|
+
cmd: ["npm", "test"],
|
|
103
|
+
title:
|
|
104
|
+
"hub+FE integration: tunnel server/REST/readers/pacing, rotation/revoke, Caddy deploy, guards audit, FE pair client, QR cross-validation (P-1/P-6..P-8, S-1..S-12, T-*, W-*)",
|
|
105
|
+
},
|
|
106
|
+
tui: {
|
|
107
|
+
cwd: "apps/dpi-tui",
|
|
108
|
+
cmd: ["npx", "tsx", "--test", "tests/*.test.ts"],
|
|
109
|
+
title: "dpi-tui: render cases + local pairing controller (P-4/P-5/P-10/P-13/P-14 render rules)",
|
|
110
|
+
},
|
|
111
|
+
"lint:playground": {
|
|
112
|
+
cwd: "apps/dpi-playground",
|
|
113
|
+
cmd: ["npm", "run", "lint"],
|
|
114
|
+
title: "frontend, hub and playground tests",
|
|
115
|
+
},
|
|
116
|
+
"lint:core": {
|
|
117
|
+
cwd: "apps/dpi-playground",
|
|
118
|
+
cmd: [
|
|
119
|
+
join(ROOT, "apps/dpi-playground/node_modules/.bin/oxlint"),
|
|
120
|
+
...["apps/dpi-sdk/src", "apps/dpi-sdk/tests", "apps/dpi-backend/src", "apps/dpi-backend/tests", "apps/dpi-tui/src", "apps/dpi-tui/tests", "scripts"].map((path) => join(ROOT, path)),
|
|
121
|
+
],
|
|
122
|
+
title: "SDK, backend, TUI and verification scripts",
|
|
123
|
+
},
|
|
124
|
+
"ui:network": {
|
|
125
|
+
cwd: "apps/dpi-playground",
|
|
126
|
+
cmd: ["node", "tests/network-ui.mjs"],
|
|
127
|
+
title: "real browser network, stream fault and mobile regression",
|
|
128
|
+
},
|
|
129
|
+
"ui:pairing": {
|
|
130
|
+
cwd: "apps/dpi-playground",
|
|
131
|
+
cmd: ["node", "--import", "tsx", "tests/pairing-ui.mjs"],
|
|
132
|
+
title: "real browser pairing and offline credential regression",
|
|
133
|
+
},
|
|
134
|
+
"ui:tui": {
|
|
135
|
+
cwd: "apps/dpi-tui",
|
|
136
|
+
cmd: ["node", "tests/pairing-ui.mjs"],
|
|
137
|
+
title: "real PTY pairing lifecycle and 40/80/200-column resize",
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const PHASE_GATES = ["test:verification", "check:sdk", "check:backend", "contract:backend", "build:playground", "check:tui"];
|
|
142
|
+
const PHASE_SUITES = {
|
|
143
|
+
P0: ["sdk"],
|
|
144
|
+
P1: ["sdk", "playground"],
|
|
145
|
+
P2: ["sdk", "backend", "playground", "tui"],
|
|
146
|
+
ALL: ["sdk", "backend", "timing:backend", "playground", "tui", "lint:playground", "lint:core", "ui:network", "ui:pairing", "ui:tui"],
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
function run(name, suite) {
|
|
150
|
+
const cwd = join(ROOT, suite.cwd);
|
|
151
|
+
process.stdout.write(`\n▶ ${name} — ${suite.title}\n cwd: ${suite.cwd}\n cmd: ${suite.cmd.join(" ")}\n`);
|
|
152
|
+
const t0 = Date.now();
|
|
153
|
+
const r = spawnSync(suite.cmd[0], suite.cmd.slice(1), {
|
|
154
|
+
cwd,
|
|
155
|
+
env: { ...process.env, DPI_TEST: "1", NO_COLOR: "1" },
|
|
156
|
+
encoding: "utf8",
|
|
157
|
+
timeout: 1_800_000,
|
|
158
|
+
maxBuffer: 256 * 1024 * 1024,
|
|
159
|
+
});
|
|
160
|
+
const secs = ((Date.now() - t0) / 1000).toFixed(1);
|
|
161
|
+
const out = `${r.stdout ?? ""}${r.stderr ?? ""}`;
|
|
162
|
+
const tail = out.split("\n").filter(Boolean).slice(-6).join("\n ");
|
|
163
|
+
const report = suite.report && out.match(suite.report)?.[1];
|
|
164
|
+
if (r.status === 0) {
|
|
165
|
+
const pass = out.match(/^# pass (\d+)/m)?.[1];
|
|
166
|
+
// Skipped tests must stay visible: a suite that quietly skips half its cases
|
|
167
|
+
// must not surface as a plain "PASS (n)".
|
|
168
|
+
const skipped = out.match(/^# skip(?:ped)? (\d+)/m)?.[1];
|
|
169
|
+
const skipNote = skipped && skipped !== "0" ? `${skipped} skipped` : "";
|
|
170
|
+
const parts = [pass ? `${pass} tests` : "", skipNote].filter(Boolean);
|
|
171
|
+
ok(`pass in ${secs}s${parts.length ? ` (${parts.join(", ")})` : ""}`);
|
|
172
|
+
if (report) info(` ${report}`);
|
|
173
|
+
return { name, ok: true, detail: [pass, skipNote].filter(Boolean).join(", ") || "ok" };
|
|
174
|
+
}
|
|
175
|
+
bad(`FAILED after ${secs}s (exit ${r.status ?? "signal"})`);
|
|
176
|
+
if (report) info(` ${report}`);
|
|
177
|
+
info(` last output:\n ${tail}`);
|
|
178
|
+
return { name, ok: false, detail: `exit ${r.status}` };
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// ---------------------------------------------------------------- main
|
|
182
|
+
|
|
183
|
+
preflight();
|
|
184
|
+
const list = PHASE_SUITES[phase];
|
|
185
|
+
if (!list) {
|
|
186
|
+
bad(`unknown phase ${phase} — use ${Object.keys(PHASE_SUITES).join(" | ")}`);
|
|
187
|
+
process.exit(1);
|
|
188
|
+
}
|
|
189
|
+
process.stdout.write(`\n== verify phase ${phase} ==\n`);
|
|
190
|
+
info("case families NOT measured here (by design):");
|
|
191
|
+
info(" P2-29 NAT and M1–M4 acceptance targets: NOT_MEASURED");
|
|
192
|
+
if (phase === "ALL") info(" (timing:backend reports local R-1/M4 samples for this machine; it is not the P2-29 acceptance run)");
|
|
193
|
+
info(" D-4 restore/quarantine drill: NOT_MEASURED (P3)");
|
|
194
|
+
info(" Gate A / Gate B: NOT_EVALUATED; local tests do not authorize exposure");
|
|
195
|
+
if (phase !== "ALL") info(" lint/browser/PTY: NOT_RUN in this phase; use --phase all");
|
|
196
|
+
const results = [];
|
|
197
|
+
for (const name of PHASE_GATES) results.push(run(name, GATES[name]));
|
|
198
|
+
if (results.some((r) => !r.ok)) {
|
|
199
|
+
bad("build/type gates failed — skipping test suites (fail fast)");
|
|
200
|
+
process.exit(1);
|
|
201
|
+
}
|
|
202
|
+
for (const name of list) results.push(run(name, SUITES[name]));
|
|
203
|
+
const failed = results.filter((r) => !r.ok);
|
|
204
|
+
process.stdout.write(`\n== summary ==\n`);
|
|
205
|
+
for (const r of results) process.stdout.write(` ${r.ok ? "PASS" : "FAIL"} ${r.name} (${r.detail})\n`);
|
|
206
|
+
if (failed.length) {
|
|
207
|
+
bad(`${failed.length} suite(s) failed: ${failed.map((r) => r.name).join(", ")}`);
|
|
208
|
+
process.exit(1);
|
|
209
|
+
}
|
|
210
|
+
ok(`all ${results.length} suite(s) green (local checks only; no Gate A/B approval)`);
|