@schoolai/shipyard 3.11.0 → 3.11.1
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/dist/{auth-GGM253LQ.js → auth-AUY74PMB.js} +3 -3
- package/dist/capability-detector-worker.js +8 -8
- package/dist/{chunk-R3XQ6W7L.js → chunk-4SYLDZTY.js} +4 -4
- package/dist/{chunk-C6QOTETH.js → chunk-5LWD5W7O.js} +24 -10
- package/dist/chunk-5LWD5W7O.js.map +1 -0
- package/dist/{chunk-IJHF4OM4.js → chunk-5W5N5U2S.js} +2 -2
- package/dist/{chunk-L7ELOV3S.js → chunk-FVZ5BDZS.js} +4 -4
- package/dist/chunk-FVZ5BDZS.js.map +1 -0
- package/dist/{chunk-RW2OTTUA.js → chunk-KYLYGFMH.js} +4 -4
- package/dist/{chunk-QJP7JCIS.js → chunk-LRNGLC4V.js} +41 -3
- package/dist/chunk-LRNGLC4V.js.map +1 -0
- package/dist/{chunk-A2UK6TW2.js → chunk-LZSMNUAI.js} +18 -1
- package/dist/{chunk-A2UK6TW2.js.map → chunk-LZSMNUAI.js.map} +1 -1
- package/dist/{chunk-Z37T5W6S.js → chunk-P2HZDIN7.js} +12 -7
- package/dist/chunk-P2HZDIN7.js.map +1 -0
- package/dist/{chunk-ZRJTZLRF.js → chunk-QKJNVVQ3.js} +4 -4
- package/dist/{chunk-2EQOL57Z.js → chunk-TFRYQDDG.js} +2 -2
- package/dist/{chunk-YXPPZQBJ.js → chunk-VL5RUCRF.js} +164 -37
- package/dist/chunk-VL5RUCRF.js.map +1 -0
- package/dist/{chunk-3WEEGJJN.js → chunk-X5KCX6ZS.js} +2 -2
- package/dist/{chunk-GM6MH4CD.js → chunk-XIEOWUPV.js} +2 -2
- package/dist/{chunk-6LINHACK.js → chunk-Y5UWRARP.js} +47 -24
- package/dist/chunk-Y5UWRARP.js.map +1 -0
- package/dist/cursor-runner.js +88 -62
- package/dist/cursor-runner.js.map +1 -1
- package/dist/electron-utility.js +5 -5
- package/dist/{git-repo-QNGPCJLI.js → git-repo-CTZJS3ER.js} +6 -4
- package/dist/index.js +8 -8
- package/dist/{logger-2F3CBS3V.js → logger-AN7EUK2B.js} +7 -5
- package/dist/{login-U256OVOJ.js → login-YB34LF4L.js} +6 -6
- package/dist/{logout-HY3MPOY5.js → logout-GUXVSWLZ.js} +5 -5
- package/dist/{mcp-servers-ICHOWXZB.js → mcp-servers-OAPQNDA7.js} +4 -4
- package/dist/{roi-YM5OOWHG.js → roi-NXJHL5X2.js} +3 -3
- package/dist/{serve-D5GKV2RU.js → serve-P3U2C5YH.js} +1175 -739
- package/dist/{serve-D5GKV2RU.js.map → serve-P3U2C5YH.js.map} +1 -1
- package/dist/{skills-W2Y6TWHA.js → skills-2UBVHFQ5.js} +2 -2
- package/dist/{start-JY26XC5R.js → start-Y34X3WVF.js} +10 -10
- package/package.json +1 -1
- package/dist/chunk-6LINHACK.js.map +0 -1
- package/dist/chunk-C6QOTETH.js.map +0 -1
- package/dist/chunk-L7ELOV3S.js.map +0 -1
- package/dist/chunk-QJP7JCIS.js.map +0 -1
- package/dist/chunk-YXPPZQBJ.js.map +0 -1
- package/dist/chunk-Z37T5W6S.js.map +0 -1
- /package/dist/{auth-GGM253LQ.js.map → auth-AUY74PMB.js.map} +0 -0
- /package/dist/{chunk-R3XQ6W7L.js.map → chunk-4SYLDZTY.js.map} +0 -0
- /package/dist/{chunk-IJHF4OM4.js.map → chunk-5W5N5U2S.js.map} +0 -0
- /package/dist/{chunk-RW2OTTUA.js.map → chunk-KYLYGFMH.js.map} +0 -0
- /package/dist/{chunk-ZRJTZLRF.js.map → chunk-QKJNVVQ3.js.map} +0 -0
- /package/dist/{chunk-2EQOL57Z.js.map → chunk-TFRYQDDG.js.map} +0 -0
- /package/dist/{chunk-3WEEGJJN.js.map → chunk-X5KCX6ZS.js.map} +0 -0
- /package/dist/{chunk-GM6MH4CD.js.map → chunk-XIEOWUPV.js.map} +0 -0
- /package/dist/{git-repo-QNGPCJLI.js.map → git-repo-CTZJS3ER.js.map} +0 -0
- /package/dist/{logger-2F3CBS3V.js.map → logger-AN7EUK2B.js.map} +0 -0
- /package/dist/{login-U256OVOJ.js.map → login-YB34LF4L.js.map} +0 -0
- /package/dist/{logout-HY3MPOY5.js.map → logout-GUXVSWLZ.js.map} +0 -0
- /package/dist/{mcp-servers-ICHOWXZB.js.map → mcp-servers-OAPQNDA7.js.map} +0 -0
- /package/dist/{roi-YM5OOWHG.js.map → roi-NXJHL5X2.js.map} +0 -0
- /package/dist/{skills-W2Y6TWHA.js.map → skills-2UBVHFQ5.js.map} +0 -0
- /package/dist/{start-JY26XC5R.js.map → start-Y34X3WVF.js.map} +0 -0
|
@@ -37,7 +37,7 @@ var EnvSchema = external_exports.object({
|
|
|
37
37
|
SHIPYARD_DEV: external_exports.enum(["1", "true", "0", "false", ""]).optional().transform((v) => v === "1" || v === "true"),
|
|
38
38
|
SHIPYARD_DAEMON_CHILD: external_exports.enum(["1", "true", "0", "false", ""]).optional().transform((v) => v === "1" || v === "true"),
|
|
39
39
|
SHIPYARD_DATA_DIR: external_exports.string().optional().transform((v) => v ?? `~/${shipyardDirName()}/data`),
|
|
40
|
-
LOG_LEVEL: external_exports.enum(["debug", "info", "warn", "error"]).default("
|
|
40
|
+
LOG_LEVEL: external_exports.enum(["debug", "info", "warn", "error"]).default("info"),
|
|
41
41
|
SHIPYARD_SIGNALING_URL: external_exports.string().url().optional(),
|
|
42
42
|
SHIPYARD_PRODUCTION_SIGNALING_URL: external_exports.string().url().default(DEFAULT_PRODUCTION_SIGNALING_URL),
|
|
43
43
|
SHIPYARD_METRICS_WORKER_URL: external_exports.string().url().default("https://shipyard-metrics.jacob-191.workers.dev"),
|
|
@@ -83,13 +83,18 @@ var EnvSchema = external_exports.object({
|
|
|
83
83
|
SHIPYARD_STALL_PROFILER_ENABLED: external_exports.enum(["1", "true", "0", "false", ""]).optional().transform((v) => v !== "0" && v !== "false"),
|
|
84
84
|
/**
|
|
85
85
|
* Event-loop stall threshold (ms). Once `histogram.max` crosses this,
|
|
86
|
-
* the profiler starts a CPU profile.
|
|
87
|
-
* May 2026
|
|
88
|
-
*
|
|
89
|
-
*
|
|
86
|
+
* the profiler starts a CPU profile. History: raised 250ms → 5000ms in
|
|
87
|
+
* May 2026 because the capture itself amplified the stalls it measured
|
|
88
|
+
* (V8 inspector `post()` consumed ~493ms of an 800ms capture window);
|
|
89
|
+
* lowered 5000ms → 1000ms in Jun 2026 (#4484) because the dominant fleet
|
|
90
|
+
* stall volume is 1–10s jank that 5s never profiled. Amplification is now
|
|
91
|
+
* bounded by the profiler's own guards instead of the threshold: the 5-min
|
|
92
|
+
* SHIPYARD_STALL_PROFILER_MIN_INTERVAL_MS rate limit between captures, a
|
|
93
|
+
* capture-in-progress flag, and the 250ms sample window — worst case 12
|
|
94
|
+
* captures/hour (~3s of profiling per hour).
|
|
90
95
|
* Override via `SHIPYARD_STALL_PROFILER_THRESHOLD_MS`.
|
|
91
96
|
*/
|
|
92
|
-
SHIPYARD_STALL_PROFILER_THRESHOLD_MS: external_exports.coerce.number().int().positive().default(
|
|
97
|
+
SHIPYARD_STALL_PROFILER_THRESHOLD_MS: external_exports.coerce.number().int().positive().default(1e3),
|
|
93
98
|
/**
|
|
94
99
|
* How long to sample the V8 CPU profile after a stall is detected.
|
|
95
100
|
* Default 250ms — long enough for the post-stall queue drain and the
|
|
@@ -220,4 +225,4 @@ export {
|
|
|
220
225
|
validateEnv,
|
|
221
226
|
getStallProfilerConfig
|
|
222
227
|
};
|
|
223
|
-
//# sourceMappingURL=chunk-
|
|
228
|
+
//# sourceMappingURL=chunk-P2HZDIN7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared/env.ts"],"sourcesContent":["import { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { z } from 'zod';\n\n/**\n * Enable fine-grained tool streaming so MCP tool inputs stream token-by-token\n * via input_json_delta events instead of being buffered as complete JSON.\n * Set early so the subprocess inherits it.\n */\nprocess.env.CLAUDE_CODE_ENABLE_FINE_GRAINED_TOOL_STREAMING = '1';\n\n/**\n * Enable the Task system (TaskCreate/TaskGet/TaskList/TaskUpdate) which provides\n * structured task management with dependency tracking (blocks/blockedBy).\n * Replaces TodoWrite — when enabled, CC only has TaskCreate (not TodoWrite).\n */\nprocess.env.CLAUDE_CODE_ENABLE_TASKS = '1';\n\n/**\n * Bootstrap exception: reads `process.env` directly because it feeds the\n * `SHIPYARD_DATA_DIR` schema transform (via `shipyardDirName`). Routing it\n * through `validateEnv()` would recurse (validateEnv → parse → transform →\n * shipyardDirName → isDevMode → validateEnv).\n */\nexport function isDevMode(): boolean {\n return process.env.SHIPYARD_DEV === '1' || process.env.SHIPYARD_DEV === 'true';\n}\n\n/**\n * When enabled, the agent runs with only Shipyard builtins (system prompt,\n * comment + visualize MCP servers) and no user/plugin MCP servers.\n * Useful for testing the harness in isolation without external interference.\n *\n * Set `SHIPYARD_VANILLA_AGENT=1` to activate.\n */\nexport function isVanillaAgentMode(): boolean {\n return validateEnv().SHIPYARD_VANILLA_AGENT;\n}\n\n/**\n * Reuse Claude Code's macOS Keychain item (\"Claude Code-credentials\") as a\n * source for MCP connector OAuth clients/tokens.\n *\n * Default OFF. The daemon is a different binary than Claude Code, so reading\n * that Keychain item triggers a macOS password prompt in a GUI session (or a\n * silent denial when headless) — unacceptable in the connector status path,\n * which runs on every capability refresh. Shipyard's own token store is the\n * source of truth, mirroring how local MCPs work (no prompt). Opt back into\n * the legacy import behavior with `SHIPYARD_MCP_REUSE_CC_KEYCHAIN=1`.\n */\nexport function isClaudeCodeKeychainReadEnabled(): boolean {\n return validateEnv().SHIPYARD_MCP_REUSE_CC_KEYCHAIN;\n}\n\n/**\n * Reuse Codex's macOS Keychain item (\"Codex MCP Credentials\") as a source for\n * per-MCP-connector OAuth clients/tokens (Codex DCRs its own atomic\n * client_id+token pairs, useful for borrowing on connectors Claude Code hasn't\n * registered with).\n *\n * Default OFF for the same reason as {@link isClaudeCodeKeychainReadEnabled}:\n * the daemon is a different binary than Codex, so reading that Keychain item\n * triggers a macOS password prompt in a GUI session (or a silent denial when\n * headless) — unacceptable in the connector status path. The\n * `~/.codex/.credentials.json` file fallback is read regardless. Opt in with\n * `SHIPYARD_MCP_REUSE_CODEX_KEYCHAIN=1`.\n */\nexport function isCodexKeychainReadEnabled(): boolean {\n return validateEnv().SHIPYARD_MCP_REUSE_CODEX_KEYCHAIN;\n}\n\nfunction shipyardDirName(): string {\n return isDevMode() ? '.shipyard-dev' : '.shipyard';\n}\n\n/**\n * The signaling worker is a RENDEZVOUS point: a browser and this daemon only\n * meet if they hit the SAME worker. This MUST equal the web build's\n * `VITE_SESSION_SERVER_URL` (.github/workflows/ci.yml + publish-npm.yml) — all\n * live clients (web next+stable, daemons all channels) point here. Do not make\n * this per-channel; a staging worker is a CI/E2E fixture only. See AGENTS.md\n * Invariant #22 (the #4186 \"install daemon\" incident).\n */\nconst DEFAULT_PRODUCTION_SIGNALING_URL = 'https://shipyard-session-server.jacob-191.workers.dev';\nconst DEFAULT_PRODUCTION_WEB_URL = 'https://shipyard.computer';\n\n/**\n * Bootstrap exception: reads `process.env` directly (not `validateEnv()`)\n * because it computes the electron-utility startup-breadcrumb path BEFORE\n * `validateEnv()` runs — the breadcrumb must still resolve when validateEnv\n * itself throws (see apps/daemon/src/electron-utility.ts).\n */\nexport function getShipyardHome(): string {\n if (process.env.SHIPYARD_HOME) return process.env.SHIPYARD_HOME;\n return join(homedir(), shipyardDirName());\n}\n\n/**\n * The executable to fork JS subprocesses with (cursor-runner, the TS language\n * server, the cursor-hook shim).\n *\n * `child_process.fork`/`spawn` default to `process.execPath`. Inside an\n * Electron *utility* process (how the packaged daemon runs) that does NOT point\n * at the main app binary — it resolves to a per-platform helper executable\n * (e.g. `…/Frameworks/Shipyard Helper.app/Contents/MacOS/Shipyard Helper`) that\n * may not exist on disk in the shipped bundle. Forking it ENOENTs, which (with\n * the cursor-runner pre-warm running at boot) crash-looped the daemon on\n * 2026-06-01 (Dylan's log).\n *\n * The Electron *main* process has a guaranteed-valid `process.execPath` (the\n * main app binary, which also honors `ELECTRON_RUN_AS_NODE=1`) and forwards it\n * as `SHIPYARD_NODE_EXEC_PATH` (see apps/electron/src/main/daemon-host.ts). The\n * CLI daemon and dev leave it unset and fall back to `process.execPath`, which\n * is already correct there. Declared in `EnvSchema` so a malformed value fails\n * at boot. Re-exported from `spawn-as-node.ts` for call-site ergonomics.\n */\nexport function resolveNodeExecPath(): string {\n return validateEnv().SHIPYARD_NODE_EXEC_PATH || process.execPath;\n}\n\nexport const EnvSchema = z.object({\n ANTHROPIC_API_KEY: z.string().min(1).optional(),\n SHIPYARD_DEV: z\n .enum(['1', 'true', '0', 'false', ''])\n .optional()\n .transform((v) => v === '1' || v === 'true'),\n SHIPYARD_DAEMON_CHILD: z\n .enum(['1', 'true', '0', 'false', ''])\n .optional()\n .transform((v) => v === '1' || v === 'true'),\n SHIPYARD_DATA_DIR: z\n .string()\n .optional()\n .transform((v) => v ?? `~/${shipyardDirName()}/data`),\n LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info'),\n SHIPYARD_SIGNALING_URL: z.string().url().optional(),\n SHIPYARD_PRODUCTION_SIGNALING_URL: z.string().url().default(DEFAULT_PRODUCTION_SIGNALING_URL),\n SHIPYARD_METRICS_WORKER_URL: z\n .string()\n .url()\n .default('https://shipyard-metrics.jacob-191.workers.dev'),\n SHIPYARD_TELEMETRY: z\n .enum(['1', 'true', '0', 'false', ''])\n .optional()\n .transform((v) => v !== '0' && v !== 'false'),\n SHIPYARD_USER_TOKEN: z.string().optional(),\n /**\n * Worker URL for the `shipyard roi` report command (distinct from\n * SHIPYARD_METRICS_WORKER_URL, which is the telemetry ingestion endpoint).\n * Falls back to the `--worker-url` CLI flag when unset.\n */\n SHIPYARD_METRICS_URL: z.string().url().optional(),\n SHIPYARD_USER_ID: z.string().optional(),\n SHIPYARD_MACHINE_ID: z.string().optional(),\n SHIPYARD_MACHINE_NAME: z.string().optional(),\n SHIPYARD_USER_DISPLAY_NAME: z.string().optional(),\n SHIPYARD_HOME: z.string().optional(),\n SHIPYARD_WORKTREE_NAME: z.string().optional(),\n /**\n * Electron utility transport mode. Absent for the CLI daemon; set by\n * apps/electron/src/main/daemon-host.ts when the daemon runs as an Electron\n * utility process.\n */\n SHIPYARD_TRANSPORT: z.enum(['electron-port']).optional(),\n /**\n * Build artifact hosting this daemon. Electron disables the daemon's npm\n * self-updater because electron-updater owns app replacement.\n */\n SHIPYARD_ARTIFACT: z.enum(['electron']).optional(),\n SHIPYARD_VANILLA_AGENT: z\n .enum(['1', 'true', '0', 'false', ''])\n .optional()\n .transform((v) => v === '1' || v === 'true'),\n /**\n * Opt in to reusing Claude Code's macOS Keychain credentials for MCP OAuth.\n * Default OFF — see {@link isClaudeCodeKeychainReadEnabled} for why (prompt\n * avoidance). Validated here so a typo fails at boot.\n */\n SHIPYARD_MCP_REUSE_CC_KEYCHAIN: z\n .enum(['1', 'true', '0', 'false', ''])\n .optional()\n .transform((v) => v === '1' || v === 'true'),\n /**\n * Opt in to reusing Codex's macOS Keychain credentials (\"Codex MCP\n * Credentials\") for MCP OAuth. Default OFF — see\n * {@link isCodexKeychainReadEnabled} for why (prompt avoidance). Validated\n * here so a typo fails at boot.\n */\n SHIPYARD_MCP_REUSE_CODEX_KEYCHAIN: z\n .enum(['1', 'true', '0', 'false', ''])\n .optional()\n .transform((v) => v === '1' || v === 'true'),\n SHIPYARD_STALL_PROFILER_ENABLED: z\n .enum(['1', 'true', '0', 'false', ''])\n .optional()\n .transform((v) => v !== '0' && v !== 'false'),\n /**\n * Event-loop stall threshold (ms). Once `histogram.max` crosses this,\n * the profiler starts a CPU profile. History: raised 250ms → 5000ms in\n * May 2026 because the capture itself amplified the stalls it measured\n * (V8 inspector `post()` consumed ~493ms of an 800ms capture window);\n * lowered 5000ms → 1000ms in Jun 2026 (#4484) because the dominant fleet\n * stall volume is 1–10s jank that 5s never profiled. Amplification is now\n * bounded by the profiler's own guards instead of the threshold: the 5-min\n * SHIPYARD_STALL_PROFILER_MIN_INTERVAL_MS rate limit between captures, a\n * capture-in-progress flag, and the 250ms sample window — worst case 12\n * captures/hour (~3s of profiling per hour).\n * Override via `SHIPYARD_STALL_PROFILER_THRESHOLD_MS`.\n */\n SHIPYARD_STALL_PROFILER_THRESHOLD_MS: z.coerce.number().int().positive().default(1_000),\n /**\n * How long to sample the V8 CPU profile after a stall is detected.\n * Default 250ms — long enough for the post-stall queue drain and the\n * cascading sibling stall (if any) to land in the same profile, but\n * short enough that the capture window does not itself amplify the\n * stall on the same event loop. Lowered from 1000 → 250 in May 2026\n * after profile evidence showed `#capture` consumed ~1s of inclusive\n * time inside a 3.5s stall window — the profiler was contributing\n * to the stalls it was trying to measure once #3204 dropped the\n * threshold from 500ms to 250ms.\n */\n SHIPYARD_STALL_PROFILER_PROFILE_DURATION_MS: z.coerce.number().int().positive().default(250),\n /**\n * Cascading-stall suppression window. After one capture, subsequent\n * stalls within this window log `stall_profile_suppressed` instead of\n * starting a new profile. Raised from 30s to 300s (5min) in May 2026\n * to prevent capture storms — at 30s a recurring stall every 60s would\n * trigger 2 captures/min, each adding hundreds of ms of inspector overhead.\n */\n SHIPYARD_STALL_PROFILER_MIN_INTERVAL_MS: z.coerce.number().int().nonnegative().default(300_000),\n /**\n * Supervisor wedge detection: if the daemon child sends no IPC heartbeats\n * for this many ms, the supervisor declares the event loop wedged, sends\n * SIGUSR2 to capture a CPU profile (the inspector runs off the JS loop),\n * waits 2s, then SIGKILLs and respawns via the normal abnormal-exit flow.\n * Generous default — 30s tolerates GC pauses and other legitimate sync\n * blocks well outside human-noticeable territory.\n */\n SHIPYARD_WEDGE_TIMEOUT_MS: z.coerce.number().int().positive().default(30_000),\n /**\n * Daemon child IPC heartbeat interval. Must be smaller than\n * SHIPYARD_WEDGE_TIMEOUT_MS by a comfortable margin so a single missed\n * heartbeat doesn't trip the wedge detector.\n */\n SHIPYARD_HEARTBEAT_INTERVAL_MS: z.coerce.number().int().positive().default(2_000),\n /**\n * When set to `'electron-safe-storage'`, the vault-key-manager wraps the\n * master key via Electron's safeStorage API (macOS Keychain on macOS,\n * Secret Service on Linux). Set by daemon-host.ts in the Electron main\n * process. When absent, the daemon falls back to the existing AES-256-GCM\n * file-based path (CLI daemon path — unchanged).\n */\n SHIPYARD_VAULT_BACKEND: z.enum(['electron-safe-storage']).optional(),\n /**\n * Absolute path to a Node-capable executable for forking JS subprocesses\n * (cursor-runner, the TS language server, the cursor-hook shim). Set by\n * apps/electron/src/main/daemon-host.ts to the Electron MAIN process's\n * `process.execPath` (the main app binary), because the daemon utility\n * process's own `process.execPath` resolves to a helper executable that may\n * not exist in the packaged bundle. Absent for the CLI daemon, which falls\n * back to its own `process.execPath`. See `resolveNodeExecPath()`.\n */\n SHIPYARD_NODE_EXEC_PATH: z.string().optional(),\n /**\n * TTL (ms) for the per-repo worktree list cache. Browser polls at 4-7/sec;\n * this collapses redundant git subprocess invocations to 1 per TTL window.\n * Set to 0 to disable caching (useful for tests that need fresh results).\n */\n SHIPYARD_WORKTREE_LIST_TTL_MS: z.coerce.number().int().min(0).default(30_000),\n /**\n * Override for the web app URL the daemon advertises. Absent → derived from\n * the signaling URL (see `getWebAppUrl`). A malformed value fails at boot\n * rather than propagating into URL concatenation.\n */\n SHIPYARD_WEB_URL: z.string().url().optional(),\n SHIPYARD_PRODUCTION_WEB_URL: z.string().url().default(DEFAULT_PRODUCTION_WEB_URL),\n /**\n * Absolute path override for the Claude Code binary. When set and the file\n * exists, the daemon spawns it instead of the SDK-bundled native binary.\n * See `resolveClaudeCodePath` / `resolveClaudeBinaryPath`.\n */\n CLAUDE_CODE_PATH: z.string().optional(),\n /**\n * Suppress auto-opening the verification URL in the browser during the\n * CLI device-login flow. Default OFF (the browser opens).\n */\n SHIPYARD_NO_OPEN: z\n .enum(['1', 'true', '0', 'false', ''])\n .optional()\n .transform((v) => v === '1' || v === 'true'),\n /**\n * Kill-switch for Loro CRDT recovery on startup. Default OFF (recovery runs).\n */\n SHIPYARD_DISABLE_LORO_RECOVERY: z\n .enum(['1', 'true', '0', 'false', ''])\n .optional()\n .transform((v) => v === '1' || v === 'true'),\n /**\n * Harness HTTP MCP server (Codex's endpoint). Default ON — Codex ships with\n * every daemon and needs it. `SHIPYARD_HARNESS_HTTP=0` is the kill-switch for\n * Codex-disabled deployments.\n */\n SHIPYARD_HARNESS_HTTP: z\n .enum(['1', 'true', '0', 'false', ''])\n .optional()\n .transform((v) => v !== '0' && v !== 'false'),\n /**\n * Use the shared `codex app-server` engine (single token owner — fixes the\n * 401-storm). Default ON. Set to `0`/`false` for the legacy per-process path.\n */\n SHIPYARD_CODEX_SHARED_ENGINE: z\n .enum(['1', 'true', '0', 'false', ''])\n .optional()\n .transform((v) => v !== '0' && v !== 'false'),\n /**\n * Browser-metrics sampling cadence. Kept as a raw string here — clamp /\n * disable (`0`) / invalid-fallback semantics + logging live in\n * `parseBrowserMetricsInterval` (services/metrics/browser-metrics-config.ts),\n * which consumes this validated value.\n */\n SHIPYARD_BROWSER_METRICS_INTERVAL_MS: z.string().optional(),\n /**\n * Max concurrent file watchers before the guard sheds new subscriptions.\n * Absent → default (450). An invalid value fails at boot.\n */\n SHIPYARD_FILE_WATCHER_MAX: z.coerce.number().int().positive().optional(),\n});\n\nexport type Env = z.infer<typeof EnvSchema>;\n\nexport function validateEnv(): Env {\n return EnvSchema.parse(process.env);\n}\n\n/**\n * Resolved profiler tuning derived from the validated env. Re-parses the\n * schema so a typo in one of the *_MS vars (e.g. `THRESHOLD_MS=abc`) fails\n * here too — boot already failed in `validateEnv()` (start.ts / serve.ts\n * call it), this second parse is cheap and keeps the wiring side free of\n * `process.env.X` reads at the call site.\n */\nexport interface StallProfilerConfig {\n enabled: boolean;\n thresholdMs: number;\n captureMs: number;\n rateLimitMs: number;\n}\n\nexport function getStallProfilerConfig(): StallProfilerConfig {\n const env = validateEnv();\n\n /**\n * Default OFF in packaged Electron when `SHIPYARD_STALL_PROFILER_ENABLED`\n * is unset. Rationale: the V8 inspector `post()` blocks the event loop\n * during capture — in a 2,959ms stall, `node:inspector:117 post` consumed\n * 493.5ms of 800ms captured, i.e. the profiler was profiling itself.\n * Trade: lose production stall visibility in packaged builds in exchange\n * for not amplifying stalls for users. Dev sessions and CLI daemon keep\n * profiling enabled by default. Override with `SHIPYARD_STALL_PROFILER_ENABLED=1`.\n *\n * `env.SHIPYARD_STALL_PROFILER_ENABLED` is `true` when the env var is\n * absent (the Zod transform treats missing/empty as truthy). We detect\n * \"explicitly set\" vs \"defaulted\" by reading `process.env` directly here\n * — the schema transform already validated it, so this read is safe.\n */\n const explicitlySet =\n process.env.SHIPYARD_STALL_PROFILER_ENABLED !== undefined &&\n process.env.SHIPYARD_STALL_PROFILER_ENABLED !== '';\n\n const enabled = explicitlySet\n ? env.SHIPYARD_STALL_PROFILER_ENABLED\n : env.SHIPYARD_ARTIFACT !== 'electron';\n\n return {\n enabled,\n thresholdMs: env.SHIPYARD_STALL_PROFILER_THRESHOLD_MS,\n captureMs: env.SHIPYARD_STALL_PROFILER_PROFILE_DURATION_MS,\n rateLimitMs: env.SHIPYARD_STALL_PROFILER_MIN_INTERVAL_MS,\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
validateEnv
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-P2HZDIN7.js";
|
|
5
5
|
import {
|
|
6
6
|
external_exports
|
|
7
7
|
} from "./chunk-CNR7O5YH.js";
|
|
@@ -18,8 +18,8 @@ function getDaemonVersion() {
|
|
|
18
18
|
return cached;
|
|
19
19
|
}
|
|
20
20
|
function readDaemonVersion() {
|
|
21
|
-
if ("3.11.
|
|
22
|
-
return "3.11.
|
|
21
|
+
if ("3.11.1".length > 0) {
|
|
22
|
+
return "3.11.1";
|
|
23
23
|
}
|
|
24
24
|
try {
|
|
25
25
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
@@ -48,4 +48,4 @@ function readDaemonVersion() {
|
|
|
48
48
|
export {
|
|
49
49
|
getDaemonVersion
|
|
50
50
|
};
|
|
51
|
-
//# sourceMappingURL=chunk-
|
|
51
|
+
//# sourceMappingURL=chunk-QKJNVVQ3.js.map
|
|
@@ -233,7 +233,7 @@ async function detectSkills(environments, lastKnown, mirrorEnabled = false) {
|
|
|
233
233
|
try {
|
|
234
234
|
return await detectSkillsInner(environments, mirrorEnabled);
|
|
235
235
|
} catch (err) {
|
|
236
|
-
const { logger } = await import("./logger-
|
|
236
|
+
const { logger } = await import("./logger-AN7EUK2B.js");
|
|
237
237
|
if (lastKnown && lastKnown.length > 0) {
|
|
238
238
|
logger.warn(
|
|
239
239
|
{ err, lastKnownCount: lastKnown.length },
|
|
@@ -406,4 +406,4 @@ export {
|
|
|
406
406
|
detectSkills,
|
|
407
407
|
_resolveBucketForTesting
|
|
408
408
|
};
|
|
409
|
-
//# sourceMappingURL=chunk-
|
|
409
|
+
//# sourceMappingURL=chunk-TFRYQDDG.js.map
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from "./chunk-X3MULCV5.js";
|
|
9
9
|
import {
|
|
10
10
|
logger
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-LRNGLC4V.js";
|
|
12
12
|
import {
|
|
13
13
|
external_exports
|
|
14
14
|
} from "./chunk-CNR7O5YH.js";
|
|
@@ -24,6 +24,7 @@ var PRESENT_TOOL = "present";
|
|
|
24
24
|
var VISUALIZE_READ_ME_QUALIFIED = `mcp__${HARNESS_SERVER_NAME}__${VISUALIZE_READ_ME_TOOL}`;
|
|
25
25
|
var VISUALIZE_TOOL_QUALIFIED = `mcp__${HARNESS_SERVER_NAME}__${VISUALIZE_TOOL}`;
|
|
26
26
|
var PRESENT_TOOL_QUALIFIED = `mcp__${HARNESS_SERVER_NAME}__${PRESENT_TOOL}`;
|
|
27
|
+
var MERMAID_SECURITY_LEVEL = "loose";
|
|
27
28
|
var COMMENT_ADD_TOOL = "add_comment";
|
|
28
29
|
var COMMENT_LIST_TOOL = "list_comments";
|
|
29
30
|
var COMMENT_READ_THREAD_TOOL = "read_comment_thread";
|
|
@@ -17921,6 +17922,12 @@ var CompactionStateSchema = external_exports.discriminatedUnion("kind", [
|
|
|
17921
17922
|
external_exports.object({
|
|
17922
17923
|
kind: external_exports.literal("compacting"),
|
|
17923
17924
|
startedAt: external_exports.number(),
|
|
17925
|
+
/**
|
|
17926
|
+
* Last runtime/subprocess activity observed while compaction was in
|
|
17927
|
+
* flight. Optional for persisted states written before the liveness
|
|
17928
|
+
* watchdog existed; transition code falls back to `startedAt`.
|
|
17929
|
+
*/
|
|
17930
|
+
lastActivityAt: external_exports.number().optional(),
|
|
17924
17931
|
trigger: triggerSchema
|
|
17925
17932
|
}),
|
|
17926
17933
|
external_exports.object({
|
|
@@ -17937,11 +17944,12 @@ var CompactionStateSchema = external_exports.discriminatedUnion("kind", [
|
|
|
17937
17944
|
trigger: triggerSchema,
|
|
17938
17945
|
/**
|
|
17939
17946
|
* Discriminates an ordinary failure (provider error text, subprocess
|
|
17940
|
-
* sdk_error) from a watchdog
|
|
17941
|
-
*
|
|
17942
|
-
* reflects the actual
|
|
17947
|
+
* sdk_error) from a liveness watchdog failure where the runtime produced
|
|
17948
|
+
* no activity while compaction was in flight. Persisted so the browser
|
|
17949
|
+
* banner can render copy that reflects the actual cause after daemon
|
|
17950
|
+
* restart. `timeout` is kept for persisted pre-liveness states.
|
|
17943
17951
|
*/
|
|
17944
|
-
reason: external_exports.enum(["error", "timeout"]).optional(),
|
|
17952
|
+
reason: external_exports.enum(["error", "timeout", "runtime_silent"]).optional(),
|
|
17945
17953
|
/**
|
|
17946
17954
|
* The original `compacting.startedAt` carried forward across the
|
|
17947
17955
|
* `compacting → failed` transition. Without it, a late `compact_complete`
|
|
@@ -17959,7 +17967,8 @@ var CompactionStateSchema = external_exports.discriminatedUnion("kind", [
|
|
|
17959
17967
|
]);
|
|
17960
17968
|
var PRE_WARN_DURATION_MS = 5e3;
|
|
17961
17969
|
var POST_FLASH_DURATION_MS = 2e3;
|
|
17962
|
-
var
|
|
17970
|
+
var COMPACTION_SILENCE_TIMEOUT_MS = 3e5;
|
|
17971
|
+
var COMPACTION_ACTIVITY_RESET_MIN_INTERVAL_MS = 3e4;
|
|
17963
17972
|
function transition(state, event) {
|
|
17964
17973
|
switch (state.kind) {
|
|
17965
17974
|
case "idle":
|
|
@@ -17995,12 +18004,21 @@ function transitionIdle(event) {
|
|
|
17995
18004
|
}
|
|
17996
18005
|
case "user_compact": {
|
|
17997
18006
|
return {
|
|
17998
|
-
newState: {
|
|
18007
|
+
newState: {
|
|
18008
|
+
kind: "compacting",
|
|
18009
|
+
startedAt: event.now,
|
|
18010
|
+
lastActivityAt: event.now,
|
|
18011
|
+
trigger: "manual"
|
|
18012
|
+
},
|
|
17999
18013
|
effects: [
|
|
18000
18014
|
{ kind: "RunPreCompactHook", trigger: "manual" },
|
|
18001
18015
|
{ kind: "BroadcastStatus", status: "compacting" },
|
|
18002
18016
|
{ kind: "CallProfileForceCompact", instructions: event.instructions },
|
|
18003
|
-
{
|
|
18017
|
+
{
|
|
18018
|
+
kind: "SetTimer",
|
|
18019
|
+
timerKind: "compact-silence",
|
|
18020
|
+
durationMs: COMPACTION_SILENCE_TIMEOUT_MS
|
|
18021
|
+
},
|
|
18004
18022
|
{
|
|
18005
18023
|
kind: "EmitTelemetry",
|
|
18006
18024
|
event: {
|
|
@@ -18014,11 +18032,20 @@ function transitionIdle(event) {
|
|
|
18014
18032
|
}
|
|
18015
18033
|
case "compact_started": {
|
|
18016
18034
|
return {
|
|
18017
|
-
newState: {
|
|
18035
|
+
newState: {
|
|
18036
|
+
kind: "compacting",
|
|
18037
|
+
startedAt: event.now,
|
|
18038
|
+
lastActivityAt: event.now,
|
|
18039
|
+
trigger: "auto"
|
|
18040
|
+
},
|
|
18018
18041
|
effects: [
|
|
18019
18042
|
{ kind: "RunPreCompactHook", trigger: "auto" },
|
|
18020
18043
|
{ kind: "BroadcastStatus", status: "compacting" },
|
|
18021
|
-
{
|
|
18044
|
+
{
|
|
18045
|
+
kind: "SetTimer",
|
|
18046
|
+
timerKind: "compact-silence",
|
|
18047
|
+
durationMs: COMPACTION_SILENCE_TIMEOUT_MS
|
|
18048
|
+
},
|
|
18022
18049
|
{
|
|
18023
18050
|
kind: "EmitTelemetry",
|
|
18024
18051
|
event: {
|
|
@@ -18068,13 +18095,14 @@ function transitionIdle(event) {
|
|
|
18068
18095
|
case "pre_warn_timer_elapsed":
|
|
18069
18096
|
case "pre_warn_cancelled":
|
|
18070
18097
|
case "compact_failed":
|
|
18098
|
+
case "compact_activity":
|
|
18071
18099
|
case "subprocess_died":
|
|
18072
18100
|
case "orchestrator_restart_complete":
|
|
18073
18101
|
case "flash_timer_elapsed":
|
|
18074
18102
|
case "user_dismiss_failure":
|
|
18075
18103
|
case "dismiss_compaction_failure":
|
|
18076
18104
|
case "user_message_after_failure":
|
|
18077
|
-
case "
|
|
18105
|
+
case "compact_silence_timeout":
|
|
18078
18106
|
return { newState: state_idle, effects: [] };
|
|
18079
18107
|
default:
|
|
18080
18108
|
return assertNever2(event);
|
|
@@ -18092,7 +18120,12 @@ function transitionPreWarn(state, event) {
|
|
|
18092
18120
|
case "user_compact": {
|
|
18093
18121
|
const trigger = event.kind === "user_compact" ? "manual" : "auto";
|
|
18094
18122
|
return {
|
|
18095
|
-
newState: {
|
|
18123
|
+
newState: {
|
|
18124
|
+
kind: "compacting",
|
|
18125
|
+
startedAt: event.now,
|
|
18126
|
+
lastActivityAt: event.now,
|
|
18127
|
+
trigger
|
|
18128
|
+
},
|
|
18096
18129
|
effects: [
|
|
18097
18130
|
{ kind: "ClearTimer", timerKind: "pre-warn" },
|
|
18098
18131
|
{ kind: "RunPreCompactHook", trigger },
|
|
@@ -18101,7 +18134,11 @@ function transitionPreWarn(state, event) {
|
|
|
18101
18134
|
kind: "CallProfileForceCompact",
|
|
18102
18135
|
instructions: event.kind === "user_compact" ? event.instructions : void 0
|
|
18103
18136
|
},
|
|
18104
|
-
{
|
|
18137
|
+
{
|
|
18138
|
+
kind: "SetTimer",
|
|
18139
|
+
timerKind: "compact-silence",
|
|
18140
|
+
durationMs: COMPACTION_SILENCE_TIMEOUT_MS
|
|
18141
|
+
},
|
|
18105
18142
|
{
|
|
18106
18143
|
kind: "EmitTelemetry",
|
|
18107
18144
|
event: {
|
|
@@ -18117,13 +18154,14 @@ function transitionPreWarn(state, event) {
|
|
|
18117
18154
|
case "compact_started":
|
|
18118
18155
|
case "compact_complete":
|
|
18119
18156
|
case "compact_failed":
|
|
18157
|
+
case "compact_activity":
|
|
18120
18158
|
case "subprocess_died":
|
|
18121
18159
|
case "orchestrator_restart_complete":
|
|
18122
18160
|
case "flash_timer_elapsed":
|
|
18123
18161
|
case "user_dismiss_failure":
|
|
18124
18162
|
case "dismiss_compaction_failure":
|
|
18125
18163
|
case "user_message_after_failure":
|
|
18126
|
-
case "
|
|
18164
|
+
case "compact_silence_timeout":
|
|
18127
18165
|
return { newState: state, effects: [] };
|
|
18128
18166
|
default:
|
|
18129
18167
|
return assertNever2(event);
|
|
@@ -18133,8 +18171,31 @@ function transitionCompacting(state, event) {
|
|
|
18133
18171
|
switch (event.kind) {
|
|
18134
18172
|
case "compact_started": {
|
|
18135
18173
|
return {
|
|
18136
|
-
newState: state,
|
|
18137
|
-
effects: [
|
|
18174
|
+
newState: { ...state, lastActivityAt: event.now },
|
|
18175
|
+
effects: [
|
|
18176
|
+
{ kind: "BroadcastStatus", status: "compacting" },
|
|
18177
|
+
{
|
|
18178
|
+
kind: "SetTimer",
|
|
18179
|
+
timerKind: "compact-silence",
|
|
18180
|
+
durationMs: COMPACTION_SILENCE_TIMEOUT_MS
|
|
18181
|
+
}
|
|
18182
|
+
]
|
|
18183
|
+
};
|
|
18184
|
+
}
|
|
18185
|
+
case "compact_activity": {
|
|
18186
|
+
const lastActivityAt = state.lastActivityAt ?? state.startedAt;
|
|
18187
|
+
if (event.now - lastActivityAt < COMPACTION_ACTIVITY_RESET_MIN_INTERVAL_MS) {
|
|
18188
|
+
return { newState: state, effects: [] };
|
|
18189
|
+
}
|
|
18190
|
+
return {
|
|
18191
|
+
newState: { ...state, lastActivityAt: event.now },
|
|
18192
|
+
effects: [
|
|
18193
|
+
{
|
|
18194
|
+
kind: "SetTimer",
|
|
18195
|
+
timerKind: "compact-silence",
|
|
18196
|
+
durationMs: COMPACTION_SILENCE_TIMEOUT_MS
|
|
18197
|
+
}
|
|
18198
|
+
]
|
|
18138
18199
|
};
|
|
18139
18200
|
}
|
|
18140
18201
|
case "compact_complete": {
|
|
@@ -18148,7 +18209,7 @@ function transitionCompacting(state, event) {
|
|
|
18148
18209
|
trigger
|
|
18149
18210
|
},
|
|
18150
18211
|
effects: [
|
|
18151
|
-
{ kind: "ClearTimer", timerKind: "compact-
|
|
18212
|
+
{ kind: "ClearTimer", timerKind: "compact-silence" },
|
|
18152
18213
|
{
|
|
18153
18214
|
kind: "EmitBoundaryBlock",
|
|
18154
18215
|
preTokens: event.preTokens,
|
|
@@ -18191,7 +18252,7 @@ function transitionCompacting(state, event) {
|
|
|
18191
18252
|
startedAt: state.startedAt
|
|
18192
18253
|
},
|
|
18193
18254
|
effects: [
|
|
18194
|
-
{ kind: "ClearTimer", timerKind: "compact-
|
|
18255
|
+
{ kind: "ClearTimer", timerKind: "compact-silence" },
|
|
18195
18256
|
/*
|
|
18196
18257
|
* G-1: a hard/terminal error (subprocess died, real provider error)
|
|
18197
18258
|
* — no recovery is expected, so write the boundary CARD with a
|
|
@@ -18225,28 +18286,30 @@ function transitionCompacting(state, event) {
|
|
|
18225
18286
|
]
|
|
18226
18287
|
};
|
|
18227
18288
|
}
|
|
18228
|
-
case "
|
|
18229
|
-
const
|
|
18289
|
+
case "compact_silence_timeout": {
|
|
18290
|
+
const lastActivityAt = state.lastActivityAt ?? state.startedAt;
|
|
18291
|
+
const silenceMs = Math.max(0, event.now - lastActivityAt);
|
|
18292
|
+
const runtimeSilentMessage = "Compaction stalled \u2014 the runtime produced no activity and may be unresponsive.";
|
|
18230
18293
|
return {
|
|
18231
18294
|
newState: {
|
|
18232
18295
|
kind: "failed",
|
|
18233
18296
|
failedAt: event.now,
|
|
18234
|
-
error:
|
|
18297
|
+
error: runtimeSilentMessage,
|
|
18235
18298
|
trigger: state.trigger,
|
|
18236
|
-
reason: "
|
|
18299
|
+
reason: "runtime_silent",
|
|
18237
18300
|
startedAt: state.startedAt
|
|
18238
18301
|
},
|
|
18239
18302
|
effects: [
|
|
18240
|
-
{ kind: "ClearTimer", timerKind: "compact-
|
|
18303
|
+
{ kind: "ClearTimer", timerKind: "compact-silence" },
|
|
18241
18304
|
/*
|
|
18242
|
-
*
|
|
18305
|
+
* A silence-watchdog failure is NOT terminal — the runtime
|
|
18243
18306
|
* (Codex/Cursor slow case) MAY still land a late `compact_complete`.
|
|
18244
18307
|
* Do NOT write a boundary CARD here: keep `#pendingBoundaryBlock`
|
|
18245
18308
|
* so a late `compact_complete` (G-6: `failed → post-flash`) can
|
|
18246
|
-
* write the `completed` card once. The durable failed BANNER
|
|
18247
|
-
*
|
|
18248
|
-
*
|
|
18249
|
-
*
|
|
18309
|
+
* write the `completed` card once. The durable failed BANNER is what
|
|
18310
|
+
* tells the user the runtime went silent; the card is reserved for a
|
|
18311
|
+
* real outcome. `ClearPendingStats` clears only the post-compact
|
|
18312
|
+
* STATS slots and leaves the boundary block intact.
|
|
18250
18313
|
*/
|
|
18251
18314
|
{ kind: "ClearPendingStats" },
|
|
18252
18315
|
{ kind: "EmitBanner", variant: "failed" },
|
|
@@ -18258,8 +18321,9 @@ function transitionCompacting(state, event) {
|
|
|
18258
18321
|
timestamp: event.now,
|
|
18259
18322
|
trigger: state.trigger,
|
|
18260
18323
|
durationMs: event.now - state.startedAt,
|
|
18261
|
-
reason: "
|
|
18262
|
-
error:
|
|
18324
|
+
reason: "runtime_silent",
|
|
18325
|
+
error: runtimeSilentMessage,
|
|
18326
|
+
silenceMs
|
|
18263
18327
|
}
|
|
18264
18328
|
}
|
|
18265
18329
|
]
|
|
@@ -18269,7 +18333,7 @@ function transitionCompacting(state, event) {
|
|
|
18269
18333
|
return {
|
|
18270
18334
|
newState: { kind: "recovering", recoveryStartedAt: event.now },
|
|
18271
18335
|
effects: [
|
|
18272
|
-
{ kind: "ClearTimer", timerKind: "compact-
|
|
18336
|
+
{ kind: "ClearTimer", timerKind: "compact-silence" },
|
|
18273
18337
|
{
|
|
18274
18338
|
kind: "EmitTelemetry",
|
|
18275
18339
|
event: {
|
|
@@ -18311,12 +18375,13 @@ function transitionPostFlash(state, event) {
|
|
|
18311
18375
|
case "compact_started":
|
|
18312
18376
|
case "compact_complete":
|
|
18313
18377
|
case "compact_failed":
|
|
18378
|
+
case "compact_activity":
|
|
18314
18379
|
case "subprocess_died":
|
|
18315
18380
|
case "orchestrator_restart_complete":
|
|
18316
18381
|
case "user_dismiss_failure":
|
|
18317
18382
|
case "dismiss_compaction_failure":
|
|
18318
18383
|
case "user_message_after_failure":
|
|
18319
|
-
case "
|
|
18384
|
+
case "compact_silence_timeout":
|
|
18320
18385
|
return { newState: state, effects: [] };
|
|
18321
18386
|
default:
|
|
18322
18387
|
return assertNever2(event);
|
|
@@ -18364,7 +18429,7 @@ function transitionFailed(state, event) {
|
|
|
18364
18429
|
trigger
|
|
18365
18430
|
},
|
|
18366
18431
|
effects: [
|
|
18367
|
-
{ kind: "ClearTimer", timerKind: "compact-
|
|
18432
|
+
{ kind: "ClearTimer", timerKind: "compact-silence" },
|
|
18368
18433
|
{
|
|
18369
18434
|
kind: "EmitBoundaryBlock",
|
|
18370
18435
|
preTokens: event.preTokens,
|
|
@@ -18402,9 +18467,10 @@ function transitionFailed(state, event) {
|
|
|
18402
18467
|
case "pre_warn_cancelled":
|
|
18403
18468
|
case "compact_started":
|
|
18404
18469
|
case "compact_failed":
|
|
18470
|
+
case "compact_activity":
|
|
18405
18471
|
case "subprocess_died":
|
|
18406
18472
|
case "flash_timer_elapsed":
|
|
18407
|
-
case "
|
|
18473
|
+
case "compact_silence_timeout":
|
|
18408
18474
|
return { newState: state, effects: [] };
|
|
18409
18475
|
default:
|
|
18410
18476
|
return assertNever2(event);
|
|
@@ -18425,12 +18491,13 @@ function transitionRecovering(state, event) {
|
|
|
18425
18491
|
case "compact_started":
|
|
18426
18492
|
case "compact_complete":
|
|
18427
18493
|
case "compact_failed":
|
|
18494
|
+
case "compact_activity":
|
|
18428
18495
|
case "subprocess_died":
|
|
18429
18496
|
case "flash_timer_elapsed":
|
|
18430
18497
|
case "user_dismiss_failure":
|
|
18431
18498
|
case "dismiss_compaction_failure":
|
|
18432
18499
|
case "user_message_after_failure":
|
|
18433
|
-
case "
|
|
18500
|
+
case "compact_silence_timeout":
|
|
18434
18501
|
return { newState: state, effects: [] };
|
|
18435
18502
|
default:
|
|
18436
18503
|
return assertNever2(event);
|
|
@@ -25364,6 +25431,15 @@ function controlChannelOutboxChannel(side, sourceId) {
|
|
|
25364
25431
|
return side === "daemon" ? `daemon-control-${sourceId}` : `control-${sourceId}`;
|
|
25365
25432
|
}
|
|
25366
25433
|
|
|
25434
|
+
// ../../packages/loro-schema/src/transport/at-least-once/health.ts
|
|
25435
|
+
function shouldEmitHealthSummary(lastEmitMs, now, intervalMs) {
|
|
25436
|
+
return now - lastEmitMs >= intervalMs;
|
|
25437
|
+
}
|
|
25438
|
+
function buildAloHealthPayload(counters) {
|
|
25439
|
+
if (counters.resendsInWindow === 0 && counters.retryStateSize === 0) return null;
|
|
25440
|
+
return { event: "alo_health", ...counters };
|
|
25441
|
+
}
|
|
25442
|
+
|
|
25367
25443
|
// ../../packages/loro-schema/src/transport/at-least-once/outbox.ts
|
|
25368
25444
|
var InMemoryOutbox = class {
|
|
25369
25445
|
#entries = [];
|
|
@@ -25423,6 +25499,7 @@ var MAX_DELIVER = 8;
|
|
|
25423
25499
|
var DEFAULT_RESEND_TICK_MS = 250;
|
|
25424
25500
|
var DEFAULT_MAX_RESENDS_PER_TICK = 32;
|
|
25425
25501
|
var DEFAULT_ORPHAN_THRESHOLD_MS = 5 * 6e4;
|
|
25502
|
+
var DEFAULT_HEALTH_SUMMARY_INTERVAL_MS = 3e4;
|
|
25426
25503
|
function nextAttemptAtMs(attempt, nowMs, backoffMs = RESEND_BACKOFF_MS) {
|
|
25427
25504
|
if (backoffMs.length === 0) return nowMs;
|
|
25428
25505
|
const idx = Math.min(Math.max(attempt - 1, 0), backoffMs.length - 1);
|
|
@@ -25753,6 +25830,11 @@ var AtLeastOnceShell = class {
|
|
|
25753
25830
|
* is reaped after `orphanThresholdMs` rather than waiting forever.
|
|
25754
25831
|
*/
|
|
25755
25832
|
#lastAckAtMs;
|
|
25833
|
+
/** Resend count since the last `alo_health` emission; reset each interval. */
|
|
25834
|
+
#resendsInWindow = 0;
|
|
25835
|
+
/** When the last `alo_health` summary was emitted. Seeded at construction so the first summary fires after one full interval, not immediately. */
|
|
25836
|
+
#lastHealthSummaryAtMs;
|
|
25837
|
+
#healthSummaryIntervalMs;
|
|
25756
25838
|
#tickIntervalMs;
|
|
25757
25839
|
#backoffMs;
|
|
25758
25840
|
#maxDeliver;
|
|
@@ -25769,9 +25851,11 @@ var AtLeastOnceShell = class {
|
|
|
25769
25851
|
this.#maxDeliver = deps.maxDeliver ?? MAX_DELIVER;
|
|
25770
25852
|
this.#orphanThresholdMs = deps.orphanThresholdMs ?? DEFAULT_ORPHAN_THRESHOLD_MS;
|
|
25771
25853
|
this.#maxResendsPerTick = deps.maxResendsPerTick ?? DEFAULT_MAX_RESENDS_PER_TICK;
|
|
25854
|
+
this.#healthSummaryIntervalMs = deps.healthSummaryIntervalMs ?? DEFAULT_HEALTH_SUMMARY_INTERVAL_MS;
|
|
25772
25855
|
this.#setInterval = deps.setInterval ?? ((fn, ms) => setInterval(fn, ms));
|
|
25773
25856
|
this.#clearInterval = deps.clearInterval ?? ((handle) => clearInterval(handle));
|
|
25774
25857
|
this.#lastAckAtMs = this.#now();
|
|
25858
|
+
this.#lastHealthSummaryAtMs = this.#now();
|
|
25775
25859
|
deps.log?.({ event: "alo_shell_created", streamId: deps.streamId });
|
|
25776
25860
|
}
|
|
25777
25861
|
/**
|
|
@@ -25840,6 +25924,10 @@ var AtLeastOnceShell = class {
|
|
|
25840
25924
|
}
|
|
25841
25925
|
async setConnected(connected) {
|
|
25842
25926
|
if (this.#disposed) return;
|
|
25927
|
+
const wasConnected = this.#sendState.connected;
|
|
25928
|
+
if (connected && !wasConnected) {
|
|
25929
|
+
this.#retryState.clear();
|
|
25930
|
+
}
|
|
25843
25931
|
const sendStep = nextSendState(this.#sendState, {
|
|
25844
25932
|
kind: "connection_state_change",
|
|
25845
25933
|
connected
|
|
@@ -26260,10 +26348,38 @@ var AtLeastOnceShell = class {
|
|
|
26260
26348
|
for (const re of capped) {
|
|
26261
26349
|
this.#processResend(re, now);
|
|
26262
26350
|
}
|
|
26351
|
+
this.#emitHealthSummary(now);
|
|
26263
26352
|
} finally {
|
|
26264
26353
|
this.#tickInFlight = false;
|
|
26265
26354
|
}
|
|
26266
26355
|
}
|
|
26356
|
+
/**
|
|
26357
|
+
* Emit a periodic `alo_health` warn log if the summary interval has elapsed.
|
|
26358
|
+
* Delegates to `shouldEmitHealthSummary`/`buildAloHealthPayload` in `health.ts`.
|
|
26359
|
+
* `#disposed` guard: skip log callbacks after external `dispose()` during a
|
|
26360
|
+
* `#processDeadLetter` await. Extracted from `#tick` for complexity budget.
|
|
26361
|
+
*/
|
|
26362
|
+
#emitHealthSummary(now) {
|
|
26363
|
+
if (this.#disposed) return;
|
|
26364
|
+
if (!shouldEmitHealthSummary(this.#lastHealthSummaryAtMs, now, this.#healthSummaryIntervalMs))
|
|
26365
|
+
return;
|
|
26366
|
+
let oldestMessageAgeMs = 0;
|
|
26367
|
+
for (const re of this.#retryState.values()) {
|
|
26368
|
+
const age = now - re.entry.ts;
|
|
26369
|
+
if (age > oldestMessageAgeMs) oldestMessageAgeMs = age;
|
|
26370
|
+
}
|
|
26371
|
+
const payload = buildAloHealthPayload({
|
|
26372
|
+
streamId: this.#deps.streamId,
|
|
26373
|
+
resendsInWindow: this.#resendsInWindow,
|
|
26374
|
+
retryStateSize: this.#retryState.size,
|
|
26375
|
+
dropsInWindow: this.#dropsCounter.count(now),
|
|
26376
|
+
oldestMessageAgeMs,
|
|
26377
|
+
msSinceLastAck: now - this.#lastAckAtMs
|
|
26378
|
+
});
|
|
26379
|
+
if (payload !== null) this.#deps.log?.(payload);
|
|
26380
|
+
this.#resendsInWindow = 0;
|
|
26381
|
+
this.#lastHealthSummaryAtMs = now;
|
|
26382
|
+
}
|
|
26267
26383
|
/**
|
|
26268
26384
|
* Pure orphan predicate. Reaps when retry state has accumulated and the
|
|
26269
26385
|
* idle timer has elapsed; an empty retry state means there is nothing
|
|
@@ -26298,6 +26414,14 @@ var AtLeastOnceShell = class {
|
|
|
26298
26414
|
msgId: re.entry.msgId,
|
|
26299
26415
|
attempts: re.attempt
|
|
26300
26416
|
});
|
|
26417
|
+
this.#deps.log?.({
|
|
26418
|
+
event: "alo_resend_exhausted",
|
|
26419
|
+
level: "error",
|
|
26420
|
+
streamId: this.#deps.streamId,
|
|
26421
|
+
seqNo: re.entry.seqNo,
|
|
26422
|
+
msgId: re.entry.msgId,
|
|
26423
|
+
attempts: re.attempt
|
|
26424
|
+
});
|
|
26301
26425
|
if (this.#deps.onDeadLetter) {
|
|
26302
26426
|
try {
|
|
26303
26427
|
this.#deps.onDeadLetter(re.entry, re.attempt);
|
|
@@ -26349,8 +26473,10 @@ var AtLeastOnceShell = class {
|
|
|
26349
26473
|
re.consecutiveDrainPendingCount = 0;
|
|
26350
26474
|
re.attempt = nextAttempt;
|
|
26351
26475
|
re.nextAttemptAtMs = nextAttemptAtMs(re.attempt, now, this.#backoffMs);
|
|
26476
|
+
this.#resendsInWindow += 1;
|
|
26352
26477
|
this.#deps.log?.({
|
|
26353
26478
|
event: "alo_resend",
|
|
26479
|
+
level: "debug",
|
|
26354
26480
|
streamId: this.#deps.streamId,
|
|
26355
26481
|
seqNo: re.entry.seqNo,
|
|
26356
26482
|
msgId: re.entry.msgId,
|
|
@@ -27755,6 +27881,7 @@ export {
|
|
|
27755
27881
|
VISUALIZE_READ_ME_TOOL,
|
|
27756
27882
|
VISUALIZE_TOOL,
|
|
27757
27883
|
PRESENT_TOOL,
|
|
27884
|
+
MERMAID_SECURITY_LEVEL,
|
|
27758
27885
|
COMMENT_ADD_TOOL,
|
|
27759
27886
|
COMMENT_LIST_TOOL,
|
|
27760
27887
|
COMMENT_READ_THREAD_TOOL,
|
|
@@ -27816,7 +27943,7 @@ export {
|
|
|
27816
27943
|
ScheduleRecordSchema,
|
|
27817
27944
|
SCHEDULE_STORE_VERSION,
|
|
27818
27945
|
migrateScheduleStore,
|
|
27819
|
-
|
|
27946
|
+
COMPACTION_SILENCE_TIMEOUT_MS,
|
|
27820
27947
|
transition,
|
|
27821
27948
|
taskStatuses,
|
|
27822
27949
|
structuredTaskStatuses,
|
|
@@ -27930,4 +28057,4 @@ export {
|
|
|
27930
28057
|
toRecord,
|
|
27931
28058
|
buildCursorUserPrompt
|
|
27932
28059
|
};
|
|
27933
|
-
//# sourceMappingURL=chunk-
|
|
28060
|
+
//# sourceMappingURL=chunk-VL5RUCRF.js.map
|