@schoolai/shipyard 3.35.0-rc.20260928.0 → 3.35.0-rc.20260928.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.
Files changed (57) hide show
  1. package/dist/{auth-73BYXHRC.js → auth-C4IBDTRR.js} +3 -3
  2. package/dist/capability-detector-worker.js +8 -8
  3. package/dist/{chunk-EZB7DECI.js → chunk-34SZI5Y5.js} +2 -2
  4. package/dist/{chunk-ZFGZC3E7.js → chunk-3LHRL5TY.js} +2 -2
  5. package/dist/{chunk-OECIR7LF.js → chunk-4IHDLC7O.js} +2 -2
  6. package/dist/{chunk-NGYXPJNZ.js → chunk-7OGQMUMK.js} +4 -4
  7. package/dist/{chunk-KISM2QTF.js → chunk-DFNVIVTY.js} +3 -3
  8. package/dist/{chunk-ZHCAMXMY.js → chunk-JJY5B4WV.js} +7 -7
  9. package/dist/{chunk-ADA356RE.js → chunk-L6NBPGYD.js} +4 -4
  10. package/dist/{chunk-VVIYOSC5.js → chunk-M2IAM45B.js} +4 -4
  11. package/dist/{chunk-DW37ERDU.js → chunk-M6GEFRHT.js} +2 -2
  12. package/dist/{chunk-MN4VLZCP.js → chunk-MDCJP6SD.js} +2 -2
  13. package/dist/{chunk-Z2J6XY4S.js → chunk-MEUZTHVZ.js} +2 -2
  14. package/dist/{chunk-WXTKIUWA.js → chunk-PIMAR46W.js} +2 -2
  15. package/dist/{chunk-DPUTHTSI.js → chunk-PUPBVZTF.js} +9 -9
  16. package/dist/{chunk-DPUTHTSI.js.map → chunk-PUPBVZTF.js.map} +1 -1
  17. package/dist/{chunk-3SBYNPEE.js → chunk-RBFSBLIB.js} +2 -2
  18. package/dist/{chunk-KP7QKDRI.js → chunk-TYTKRNCP.js} +6 -6
  19. package/dist/cursor-runner.js +3 -3
  20. package/dist/electron-utility.js +6 -6
  21. package/dist/{git-repo-4RK3V42K.js → git-repo-UXTZVQ7G.js} +4 -4
  22. package/dist/index.js +10 -10
  23. package/dist/{logger-LBZ72MWP.js → logger-OFEJM3NC.js} +3 -3
  24. package/dist/{login-BJPXJV4X.js → login-QHE6DLBD.js} +6 -6
  25. package/dist/{logout-I2ZZKIBU.js → logout-QOYFTCFC.js} +5 -5
  26. package/dist/{mcp-servers-LANTUZHL.js → mcp-servers-HV54T2SZ.js} +4 -4
  27. package/dist/{plan-backfill-RD2N65JU.js → plan-backfill-VBGXJ77F.js} +4 -4
  28. package/dist/{roi-VMVY5UYA.js → roi-BT64XWGE.js} +3 -3
  29. package/dist/{serve-6R3OWK2F.js → serve-FI5KNQA2.js} +1858 -644
  30. package/dist/{serve-6R3OWK2F.js.map → serve-FI5KNQA2.js.map} +1 -1
  31. package/dist/{skills-ZGQWLLUG.js → skills-JEM5KQKR.js} +2 -2
  32. package/dist/{start-7UMZSO2D.js → start-PVWQLLNL.js} +10 -10
  33. package/package.json +1 -1
  34. /package/dist/{auth-73BYXHRC.js.map → auth-C4IBDTRR.js.map} +0 -0
  35. /package/dist/{chunk-EZB7DECI.js.map → chunk-34SZI5Y5.js.map} +0 -0
  36. /package/dist/{chunk-ZFGZC3E7.js.map → chunk-3LHRL5TY.js.map} +0 -0
  37. /package/dist/{chunk-OECIR7LF.js.map → chunk-4IHDLC7O.js.map} +0 -0
  38. /package/dist/{chunk-NGYXPJNZ.js.map → chunk-7OGQMUMK.js.map} +0 -0
  39. /package/dist/{chunk-KISM2QTF.js.map → chunk-DFNVIVTY.js.map} +0 -0
  40. /package/dist/{chunk-ZHCAMXMY.js.map → chunk-JJY5B4WV.js.map} +0 -0
  41. /package/dist/{chunk-ADA356RE.js.map → chunk-L6NBPGYD.js.map} +0 -0
  42. /package/dist/{chunk-VVIYOSC5.js.map → chunk-M2IAM45B.js.map} +0 -0
  43. /package/dist/{chunk-DW37ERDU.js.map → chunk-M6GEFRHT.js.map} +0 -0
  44. /package/dist/{chunk-MN4VLZCP.js.map → chunk-MDCJP6SD.js.map} +0 -0
  45. /package/dist/{chunk-Z2J6XY4S.js.map → chunk-MEUZTHVZ.js.map} +0 -0
  46. /package/dist/{chunk-WXTKIUWA.js.map → chunk-PIMAR46W.js.map} +0 -0
  47. /package/dist/{chunk-3SBYNPEE.js.map → chunk-RBFSBLIB.js.map} +0 -0
  48. /package/dist/{chunk-KP7QKDRI.js.map → chunk-TYTKRNCP.js.map} +0 -0
  49. /package/dist/{git-repo-4RK3V42K.js.map → git-repo-UXTZVQ7G.js.map} +0 -0
  50. /package/dist/{logger-LBZ72MWP.js.map → logger-OFEJM3NC.js.map} +0 -0
  51. /package/dist/{login-BJPXJV4X.js.map → login-QHE6DLBD.js.map} +0 -0
  52. /package/dist/{logout-I2ZZKIBU.js.map → logout-QOYFTCFC.js.map} +0 -0
  53. /package/dist/{mcp-servers-LANTUZHL.js.map → mcp-servers-HV54T2SZ.js.map} +0 -0
  54. /package/dist/{plan-backfill-RD2N65JU.js.map → plan-backfill-VBGXJ77F.js.map} +0 -0
  55. /package/dist/{roi-VMVY5UYA.js.map → roi-BT64XWGE.js.map} +0 -0
  56. /package/dist/{skills-ZGQWLLUG.js.map → skills-JEM5KQKR.js.map} +0 -0
  57. /package/dist/{start-7UMZSO2D.js.map → start-PVWQLLNL.js.map} +0 -0
@@ -5,8 +5,8 @@ import {
5
5
  loadAuthToken,
6
6
  readConfig,
7
7
  writeConfig
8
- } from "./chunk-ZFGZC3E7.js";
9
- import "./chunk-DPUTHTSI.js";
8
+ } from "./chunk-3LHRL5TY.js";
9
+ import "./chunk-PUPBVZTF.js";
10
10
  import "./chunk-XVW6VCKW.js";
11
11
  import "./chunk-2H7UOFLK.js";
12
12
  export {
@@ -16,4 +16,4 @@ export {
16
16
  readConfig,
17
17
  writeConfig
18
18
  };
19
- //# sourceMappingURL=auth-73BYXHRC.js.map
19
+ //# sourceMappingURL=auth-C4IBDTRR.js.map
@@ -3,28 +3,28 @@ import {
3
3
  detectCapabilities,
4
4
  refreshMcpServers,
5
5
  registerBuiltInProfiles
6
- } from "./chunk-ZHCAMXMY.js";
7
- import "./chunk-WXTKIUWA.js";
8
- import "./chunk-Z2J6XY4S.js";
6
+ } from "./chunk-JJY5B4WV.js";
7
+ import "./chunk-PIMAR46W.js";
8
+ import "./chunk-MEUZTHVZ.js";
9
9
  import "./chunk-OZVA4QIX.js";
10
10
  import {
11
11
  getRepoMetadata
12
- } from "./chunk-KP7QKDRI.js";
12
+ } from "./chunk-TYTKRNCP.js";
13
13
  import "./chunk-4T2OQAVL.js";
14
14
  import {
15
15
  MCPTokenStore
16
- } from "./chunk-NGYXPJNZ.js";
16
+ } from "./chunk-7OGQMUMK.js";
17
17
  import "./chunk-VHPNDDB5.js";
18
18
  import "./chunk-ZFKJAYAN.js";
19
- import "./chunk-OECIR7LF.js";
19
+ import "./chunk-4IHDLC7O.js";
20
20
  import "./chunk-Z5PJ2F56.js";
21
21
  import "./chunk-TIW46SCK.js";
22
22
  import "./chunk-EHQITHQX.js";
23
23
  import {
24
24
  flushLogger,
25
25
  logger
26
- } from "./chunk-3SBYNPEE.js";
27
- import "./chunk-DPUTHTSI.js";
26
+ } from "./chunk-RBFSBLIB.js";
27
+ import "./chunk-PUPBVZTF.js";
28
28
  import "./chunk-X3MULCV5.js";
29
29
  import "./chunk-XVW6VCKW.js";
30
30
  import "./chunk-2H7UOFLK.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  validateEnv
4
- } from "./chunk-DPUTHTSI.js";
4
+ } from "./chunk-PUPBVZTF.js";
5
5
  import {
6
6
  external_exports
7
7
  } from "./chunk-XVW6VCKW.js";
@@ -48,4 +48,4 @@ function readDaemonVersion() {
48
48
  export {
49
49
  getDaemonVersion
50
50
  };
51
- //# sourceMappingURL=chunk-EZB7DECI.js.map
51
+ //# sourceMappingURL=chunk-34SZI5Y5.js.map
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  getShipyardHome
4
- } from "./chunk-DPUTHTSI.js";
4
+ } from "./chunk-PUPBVZTF.js";
5
5
  import {
6
6
  external_exports
7
7
  } from "./chunk-XVW6VCKW.js";
@@ -90,4 +90,4 @@ export {
90
90
  deleteConfig,
91
91
  loadAuthToken
92
92
  };
93
- //# sourceMappingURL=chunk-ZFGZC3E7.js.map
93
+ //# sourceMappingURL=chunk-3LHRL5TY.js.map
@@ -5,7 +5,7 @@ import {
5
5
  } from "./chunk-Z5PJ2F56.js";
6
6
  import {
7
7
  logger
8
- } from "./chunk-3SBYNPEE.js";
8
+ } from "./chunk-RBFSBLIB.js";
9
9
  import {
10
10
  assertNever
11
11
  } from "./chunk-X3MULCV5.js";
@@ -588,4 +588,4 @@ export {
588
588
  toRecord,
589
589
  buildCursorUserPrompt
590
590
  };
591
- //# sourceMappingURL=chunk-OECIR7LF.js.map
591
+ //# sourceMappingURL=chunk-4IHDLC7O.js.map
@@ -5,10 +5,10 @@ import {
5
5
  } from "./chunk-VHPNDDB5.js";
6
6
  import {
7
7
  logger
8
- } from "./chunk-3SBYNPEE.js";
8
+ } from "./chunk-RBFSBLIB.js";
9
9
  import {
10
10
  isClaudeCodeKeychainReadEnabled
11
- } from "./chunk-DPUTHTSI.js";
11
+ } from "./chunk-PUPBVZTF.js";
12
12
  import {
13
13
  external_exports
14
14
  } from "./chunk-XVW6VCKW.js";
@@ -1632,7 +1632,7 @@ async function detectMCPServers(environments, tokenStore, log, lastKnown, prefer
1632
1632
  lastKnown
1633
1633
  );
1634
1634
  } catch (err) {
1635
- const { logger: logger2 } = await import("./logger-LBZ72MWP.js");
1635
+ const { logger: logger2 } = await import("./logger-OFEJM3NC.js");
1636
1636
  if (lastKnown && lastKnown.length > 0) {
1637
1637
  logger2.warn(
1638
1638
  { err, lastKnownCount: lastKnown.length },
@@ -1838,4 +1838,4 @@ export {
1838
1838
  resolveAuthStatuses,
1839
1839
  detectMCPServers
1840
1840
  };
1841
- //# sourceMappingURL=chunk-NGYXPJNZ.js.map
1841
+ //# sourceMappingURL=chunk-7OGQMUMK.js.map
@@ -37,11 +37,11 @@ import {
37
37
  } from "./chunk-Z5PJ2F56.js";
38
38
  import {
39
39
  logger
40
- } from "./chunk-3SBYNPEE.js";
40
+ } from "./chunk-RBFSBLIB.js";
41
41
  import {
42
42
  getPlanBackfillMode,
43
43
  getShipyardHome
44
- } from "./chunk-DPUTHTSI.js";
44
+ } from "./chunk-PUPBVZTF.js";
45
45
  import {
46
46
  assertNever
47
47
  } from "./chunk-X3MULCV5.js";
@@ -35361,4 +35361,4 @@ export {
35361
35361
  runPlanBackfill,
35362
35362
  buildTaskStateStore
35363
35363
  };
35364
- //# sourceMappingURL=chunk-KISM2QTF.js.map
35364
+ //# sourceMappingURL=chunk-DFNVIVTY.js.map
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  detectSkills
4
- } from "./chunk-WXTKIUWA.js";
4
+ } from "./chunk-PIMAR46W.js";
5
5
  import {
6
6
  withLabelAsync
7
7
  } from "./chunk-OZVA4QIX.js";
@@ -16,7 +16,7 @@ import {
16
16
  run,
17
17
  runWithTimeout,
18
18
  truncateDiff
19
- } from "./chunk-KP7QKDRI.js";
19
+ } from "./chunk-TYTKRNCP.js";
20
20
  import {
21
21
  gitExecSafe
22
22
  } from "./chunk-4T2OQAVL.js";
@@ -26,7 +26,7 @@ import {
26
26
  CURSOR_RUNTIME_ID,
27
27
  DEVIN_RUNTIME_ID,
28
28
  detectMCPServers
29
- } from "./chunk-NGYXPJNZ.js";
29
+ } from "./chunk-7OGQMUMK.js";
30
30
  import {
31
31
  isEnoent
32
32
  } from "./chunk-VHPNDDB5.js";
@@ -42,7 +42,7 @@ import {
42
42
  formatTaskFeedback,
43
43
  toRecord,
44
44
  toSdkContent
45
- } from "./chunk-OECIR7LF.js";
45
+ } from "./chunk-4IHDLC7O.js";
46
46
  import {
47
47
  AGENT_IDS,
48
48
  AGENT_SYSTEM_CLAUDE_CODE,
@@ -69,12 +69,12 @@ import {
69
69
  } from "./chunk-TIW46SCK.js";
70
70
  import {
71
71
  logger
72
- } from "./chunk-3SBYNPEE.js";
72
+ } from "./chunk-RBFSBLIB.js";
73
73
  import {
74
74
  getShipyardHome,
75
75
  resolveNodeExecPath,
76
76
  validateEnv
77
- } from "./chunk-DPUTHTSI.js";
77
+ } from "./chunk-PUPBVZTF.js";
78
78
  import {
79
79
  external_exports
80
80
  } from "./chunk-XVW6VCKW.js";
@@ -8964,4 +8964,4 @@ export {
8964
8964
  refreshCodexAuthSlice,
8965
8965
  refreshAnthropicAuthSlice
8966
8966
  };
8967
- //# sourceMappingURL=chunk-ZHCAMXMY.js.map
8967
+ //# sourceMappingURL=chunk-JJY5B4WV.js.map
@@ -2,13 +2,13 @@
2
2
  import {
3
3
  print,
4
4
  printError
5
- } from "./chunk-DW37ERDU.js";
5
+ } from "./chunk-M6GEFRHT.js";
6
6
  import {
7
7
  getConfigPath,
8
8
  loadAuthToken,
9
9
  readConfig,
10
10
  writeConfig
11
- } from "./chunk-ZFGZC3E7.js";
11
+ } from "./chunk-3LHRL5TY.js";
12
12
  import {
13
13
  DeviceExchangeCodeResponseSchema,
14
14
  DevicePollPendingSchema,
@@ -19,7 +19,7 @@ import {
19
19
  import {
20
20
  isDevMode,
21
21
  validateEnv
22
- } from "./chunk-DPUTHTSI.js";
22
+ } from "./chunk-PUPBVZTF.js";
23
23
  import {
24
24
  external_exports
25
25
  } from "./chunk-XVW6VCKW.js";
@@ -223,4 +223,4 @@ export {
223
223
  ensureAuthenticated,
224
224
  loginCommand
225
225
  };
226
- //# sourceMappingURL=chunk-ADA356RE.js.map
226
+ //# sourceMappingURL=chunk-L6NBPGYD.js.map
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  getDaemonVersion
4
- } from "./chunk-EZB7DECI.js";
4
+ } from "./chunk-34SZI5Y5.js";
5
5
  import {
6
6
  WorkerCommandCodec,
7
7
  WorkerReplyCodec
8
8
  } from "./chunk-EIWGZUA2.js";
9
9
  import {
10
10
  buildNodeSpawnEnv
11
- } from "./chunk-Z2J6XY4S.js";
11
+ } from "./chunk-MEUZTHVZ.js";
12
12
  import {
13
13
  createServiceSupervisor
14
14
  } from "./chunk-ZFKJAYAN.js";
@@ -16,7 +16,7 @@ import {
16
16
  getShipyardHome,
17
17
  resolveNodeExecPath,
18
18
  validateEnv
19
- } from "./chunk-DPUTHTSI.js";
19
+ } from "./chunk-PUPBVZTF.js";
20
20
  import {
21
21
  assertNever
22
22
  } from "./chunk-X3MULCV5.js";
@@ -1116,4 +1116,4 @@ export {
1116
1116
  shutdownFileWatcherGuard,
1117
1117
  guardedSubscribe
1118
1118
  };
1119
- //# sourceMappingURL=chunk-VVIYOSC5.js.map
1119
+ //# sourceMappingURL=chunk-M2IAM45B.js.map
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  getLogFilePath
4
- } from "./chunk-3SBYNPEE.js";
4
+ } from "./chunk-RBFSBLIB.js";
5
5
 
6
6
  // src/shared/commands/output.ts
7
7
  import { appendFileSync } from "fs";
@@ -40,4 +40,4 @@ export {
40
40
  print,
41
41
  printError
42
42
  };
43
- //# sourceMappingURL=chunk-DW37ERDU.js.map
43
+ //# sourceMappingURL=chunk-M6GEFRHT.js.map
@@ -5,7 +5,7 @@ import {
5
5
  import {
6
6
  getShipyardHome,
7
7
  validateEnv
8
- } from "./chunk-DPUTHTSI.js";
8
+ } from "./chunk-PUPBVZTF.js";
9
9
 
10
10
  // src/services/bootstrap/native-crash-report.ts
11
11
  import { mkdirSync } from "fs";
@@ -59,4 +59,4 @@ function setOptionalFlag(report, flag) {
59
59
  export {
60
60
  enableNativeCrashReports
61
61
  };
62
- //# sourceMappingURL=chunk-MN4VLZCP.js.map
62
+ //# sourceMappingURL=chunk-MDCJP6SD.js.map
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  resolveNodeExecPath
4
- } from "./chunk-DPUTHTSI.js";
4
+ } from "./chunk-PUPBVZTF.js";
5
5
 
6
6
  // src/shared/spawn-as-node.ts
7
7
  var isElectronOverride = null;
@@ -34,4 +34,4 @@ export {
34
34
  buildNodeSpawnEnv,
35
35
  rewriteElectronNodeScriptSpawn
36
36
  };
37
- //# sourceMappingURL=chunk-Z2J6XY4S.js.map
37
+ //# sourceMappingURL=chunk-MEUZTHVZ.js.map
@@ -365,7 +365,7 @@ async function runSkillScan({
365
365
  try {
366
366
  return await detectSkillsInner(scanPaths, mirrorEnabled);
367
367
  } catch (err) {
368
- const { logger } = await import("./logger-LBZ72MWP.js");
368
+ const { logger } = await import("./logger-OFEJM3NC.js");
369
369
  if (lastKnown && lastKnown.length > 0) {
370
370
  logger.warn(
371
371
  { err, lastKnownCount: lastKnown.length },
@@ -582,4 +582,4 @@ export {
582
582
  scopeEnvironmentsToActiveRepo,
583
583
  _resolveBucketForTesting
584
584
  };
585
- //# sourceMappingURL=chunk-WXTKIUWA.js.map
585
+ //# sourceMappingURL=chunk-PIMAR46W.js.map
@@ -268,17 +268,17 @@ var EnvSchema = external_exports.object({
268
268
  */
269
269
  SHIPYARD_DAEMON_MAX_OLD_SPACE_MB: external_exports.coerce.number().int().positive().optional(),
270
270
  /**
271
- * Auto-continue tasks whose turn was interrupted by an unintended daemon
272
- * kill (SIGKILL/crash/wedge-kill) rather than leaving them stuck at
273
- * `input_required` forever. Default OFF — the auto-continue policy is not
274
- * yet decided; while off, the boot phase still computes and logs what
275
- * WOULD have resumed (`interrupted_resume_disabled`) so the decision can
276
- * be made from real data. See `services/bootstrap/interrupted-turn-resume.ts`.
271
+ * Auto-continue tasks whose turn was interrupted by a crash, wedge-kill,
272
+ * app update or user restart (never Cmd+Q) rather than leaving them stuck
273
+ * at `input_required`. Default OFF; while off, the boot phase still
274
+ * computes and logs what WOULD have resumed (`interrupted_resume_disabled`).
275
+ * See `services/bootstrap/interrupted-turn-resume.ts`.
277
276
  */
278
277
  /**
279
278
  * Why this daemon process was started, set by Electron main per spawn
280
- * (daemon-host.ts). Auto-resume of interrupted turns only acts after a
281
- * crash/wedge respawn — see interrupted-turn-resume.ts. Unset under the CLI.
279
+ * (daemon-host.ts). A crash/wedge respawn always permits auto-resume; a
280
+ * plain `launch` defers to the shutdown-reason marker
281
+ * (`services/bootstrap/shutdown-reason.ts`). Unset under the CLI.
282
282
  */
283
283
  SHIPYARD_DAEMON_START_REASON: external_exports.enum(["launch", "respawn_after_crash", "respawn_after_wedge", "respawn_after_clean", "probe"]).optional(),
284
284
  SHIPYARD_AUTO_RESUME_INTERRUPTED: external_exports.enum(["1", "true", "0", "false", ""]).default("").transform((v) => v === "1" || v === "true"),
@@ -319,4 +319,4 @@ export {
319
319
  validateEnv,
320
320
  getStallProfilerConfig
321
321
  };
322
- //# sourceMappingURL=chunk-DPUTHTSI.js.map
322
+ //# sourceMappingURL=chunk-PUPBVZTF.js.map
@@ -1 +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 * Agent SDK 0.3.233 dropped the Task/Todo tools from the DEFAULT tool surface on\n * Opus 4.8, Sonnet 5, Fable 5, Mythos 5 \"and newer\" — which now includes Fable 5.1.\n * `CLAUDE_CODE_ENABLE_TASKS` alone is no longer sufficient: the 0.3.259 gate is\n * `enableTasks() && (modelNotGated || CLAUDE_CODE_ENABLE_TODO_TOOLS)`, and Shipyard\n * passes no `allowedTools`, so without this the tools silently vanish on exactly our\n * frontier models and `packages/loro-schema/src/todo-helpers.ts` extracts nothing.\n * Failure mode is silent — no type error, no test failure, just an empty todo list.\n */\nprocess.env.CLAUDE_CODE_ENABLE_TODO_TOOLS = '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\nexport function getSpawningStallTimeoutOverrideMs(): number | undefined {\n return validateEnv().SHIPYARD_SPAWNING_STALL_TIMEOUT_MS;\n}\n\nexport function getPreSpawnTimeoutMs(): number {\n return validateEnv().SHIPYARD_PRE_SPAWN_TIMEOUT_MS;\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\nexport function getTaskControlOwnershipMode(): 'enforce' | 'log_only' {\n return validateEnv().SHIPYARD_TASK_CONTROL_OWNERSHIP;\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\n/**\n * Resolved one-time plan-backfill mode (boot). Unset/default ⇒ `auto`: the\n * daemon rebuilds missing plan CRDTs write-once on boot, gated only by the\n * marker's `completed` flag (a no-op on every later boot). The env var is an\n * OPTIONAL OVERRIDE, not the gate: `dry-run` forces a read-only fleet-telemetry\n * pass that writes nothing; `off` disables the scan entirely (escape hatch);\n * `write` forces a write pass that bypasses the completion gate (manual re-run /\n * testing).\n */\nexport function getPlanBackfillMode(): 'off' | 'auto' | 'dry-run' | 'write' {\n return validateEnv().SHIPYARD_PLAN_BACKFILL_MODE;\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 * One-time plan-CRDT backfill mode (auto-on-boot). Empty/absent → `auto`:\n * every daemon rebuilds its missing plan CRDTs write-once on boot, gated ONLY\n * by the `~/.shipyard/data/plan-backfill-v1.json` marker's `completed` flag, so\n * it runs once per machine and is a no-op on every subsequent boot — no manual\n * action required. The env var is an OPTIONAL OVERRIDE, not the gate:\n * - `dry-run` → force a READ-ONLY pass that emits `plan_backfill_dryrun` fleet\n * telemetry and writes nothing (testing / observability).\n * - `off` → disable the scan entirely (escape hatch).\n * - `write` → force a write pass that bypasses the completion gate (manual\n * re-run / testing); still per-task idempotent via the marker.\n */\n SHIPYARD_PLAN_BACKFILL_MODE: z\n .enum(['off', 'auto', 'dry-run', 'write', ''])\n .optional()\n .transform((v) => (v === undefined || v === '' ? 'auto' : v)),\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 * Master kill-switch for native-crash evidence capture: the supervisor exit\n * record, `process.report` fatal-error diagnostic reports, and the supervisor\n * stderr tail. Default ON. Telemetry of the distilled summary is separately\n * gated by `SHIPYARD_TELEMETRY`; this only controls the local on-disk capture.\n */\n SHIPYARD_CRASH_EVIDENCE: 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 * Manual-repro hook for wedge supervision: N ms after boot, spin the JS loop\n * forever. Inert unless `{dataDir}/debug-wedge.armed` also exists; the file\n * is consumed on fire so the respawned daemon boots normally.\n */\n SHIPYARD_DEBUG_WEDGE_AFTER_MS: z.coerce.number().int().nonnegative().optional(),\n /**\n * Always-on V8 sampling heap profiler that dumps a `.heapprofile` to\n * `{dataDir}/diagnostics` at 60/75/90% of the heap limit\n * (heap-pressure-profiler.ts). Default ON; set 0 to disable.\n */\n SHIPYARD_HEAP_PROFILER: z\n .enum(['1', 'true', '0', 'false', ''])\n .default('')\n .transform((v) => v !== '0' && v !== 'false'),\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 * Overrides the `spawning`-state stall budget for agent profiles that\n * declare one (Claude: 600 000 ms). Unset keeps each profile's default.\n */\n SHIPYARD_SPAWNING_STALL_TIMEOUT_MS: z.coerce.number().int().positive().optional(),\n /**\n * Wall-clock bound on a spawn's pre-spawn prep (hydration, resource\n * resolution, system-prompt assembly). Expiry fails the spawn. Keep it\n * below the spawning stall budget so this bound, not the watchdog, ends a\n * hung prep.\n */\n SHIPYARD_PRE_SPAWN_TIMEOUT_MS: z.coerce.number().int().positive().default(180_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 * Override the daemon's own --max-old-space-size (MB). When absent, the\n * value is auto-derived from os.totalmem() × 25 %, clamped to [2048, 8192].\n * An explicit value is honored as-is (clamped to 65536 to catch typos) and\n * passed to --max-old-space-size at BOTH spawn sites: the outer CLI\n * supervisor (start-supervisor.ts) and the Electron utility-process fork\n * (daemon-host.ts). See apps/daemon/src/shared/daemon-heap-limit.ts. The\n * Electron path also honors a `daemon.maxHeapGb` config.json setting below\n * this env var in precedence — see daemon-heap-limit-config.ts.\n */\n SHIPYARD_DAEMON_MAX_OLD_SPACE_MB: z.coerce.number().int().positive().optional(),\n /**\n * Auto-continue tasks whose turn was interrupted by an unintended daemon\n * kill (SIGKILL/crash/wedge-kill) rather than leaving them stuck at\n * `input_required` forever. Default OFF — the auto-continue policy is not\n * yet decided; while off, the boot phase still computes and logs what\n * WOULD have resumed (`interrupted_resume_disabled`) so the decision can\n * be made from real data. See `services/bootstrap/interrupted-turn-resume.ts`.\n */\n /**\n * Why this daemon process was started, set by Electron main per spawn\n * (daemon-host.ts). Auto-resume of interrupted turns only acts after a\n * crash/wedge respawn — see interrupted-turn-resume.ts. Unset under the CLI.\n */\n SHIPYARD_DAEMON_START_REASON: z\n .enum(['launch', 'respawn_after_crash', 'respawn_after_wedge', 'respawn_after_clean', 'probe'])\n .optional(),\n SHIPYARD_AUTO_RESUME_INTERRUPTED: z\n .enum(['1', 'true', '0', 'false', ''])\n .default('')\n .transform((v) => v === '1' || v === 'true'),\n /**\n * Whether the harness `task` tool REFUSES a cross-tree `cancel`/`complete`\n * from a spawned, non-automation task (`enforce`) or only logs\n * `task_control_ownership_violation` (`log_only`). See\n * `services/harness/task-control-ownership.ts`.\n */\n SHIPYARD_TASK_CONTROL_OWNERSHIP: z.enum(['enforce', 'log_only']).default('enforce'),\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
+ {"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 * Agent SDK 0.3.233 dropped the Task/Todo tools from the DEFAULT tool surface on\n * Opus 4.8, Sonnet 5, Fable 5, Mythos 5 \"and newer\" — which now includes Fable 5.1.\n * `CLAUDE_CODE_ENABLE_TASKS` alone is no longer sufficient: the 0.3.259 gate is\n * `enableTasks() && (modelNotGated || CLAUDE_CODE_ENABLE_TODO_TOOLS)`, and Shipyard\n * passes no `allowedTools`, so without this the tools silently vanish on exactly our\n * frontier models and `packages/loro-schema/src/todo-helpers.ts` extracts nothing.\n * Failure mode is silent — no type error, no test failure, just an empty todo list.\n */\nprocess.env.CLAUDE_CODE_ENABLE_TODO_TOOLS = '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\nexport function getSpawningStallTimeoutOverrideMs(): number | undefined {\n return validateEnv().SHIPYARD_SPAWNING_STALL_TIMEOUT_MS;\n}\n\nexport function getPreSpawnTimeoutMs(): number {\n return validateEnv().SHIPYARD_PRE_SPAWN_TIMEOUT_MS;\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\nexport function getTaskControlOwnershipMode(): 'enforce' | 'log_only' {\n return validateEnv().SHIPYARD_TASK_CONTROL_OWNERSHIP;\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\n/**\n * Resolved one-time plan-backfill mode (boot). Unset/default ⇒ `auto`: the\n * daemon rebuilds missing plan CRDTs write-once on boot, gated only by the\n * marker's `completed` flag (a no-op on every later boot). The env var is an\n * OPTIONAL OVERRIDE, not the gate: `dry-run` forces a read-only fleet-telemetry\n * pass that writes nothing; `off` disables the scan entirely (escape hatch);\n * `write` forces a write pass that bypasses the completion gate (manual re-run /\n * testing).\n */\nexport function getPlanBackfillMode(): 'off' | 'auto' | 'dry-run' | 'write' {\n return validateEnv().SHIPYARD_PLAN_BACKFILL_MODE;\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 * One-time plan-CRDT backfill mode (auto-on-boot). Empty/absent → `auto`:\n * every daemon rebuilds its missing plan CRDTs write-once on boot, gated ONLY\n * by the `~/.shipyard/data/plan-backfill-v1.json` marker's `completed` flag, so\n * it runs once per machine and is a no-op on every subsequent boot — no manual\n * action required. The env var is an OPTIONAL OVERRIDE, not the gate:\n * - `dry-run` → force a READ-ONLY pass that emits `plan_backfill_dryrun` fleet\n * telemetry and writes nothing (testing / observability).\n * - `off` → disable the scan entirely (escape hatch).\n * - `write` → force a write pass that bypasses the completion gate (manual\n * re-run / testing); still per-task idempotent via the marker.\n */\n SHIPYARD_PLAN_BACKFILL_MODE: z\n .enum(['off', 'auto', 'dry-run', 'write', ''])\n .optional()\n .transform((v) => (v === undefined || v === '' ? 'auto' : v)),\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 * Master kill-switch for native-crash evidence capture: the supervisor exit\n * record, `process.report` fatal-error diagnostic reports, and the supervisor\n * stderr tail. Default ON. Telemetry of the distilled summary is separately\n * gated by `SHIPYARD_TELEMETRY`; this only controls the local on-disk capture.\n */\n SHIPYARD_CRASH_EVIDENCE: 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 * Manual-repro hook for wedge supervision: N ms after boot, spin the JS loop\n * forever. Inert unless `{dataDir}/debug-wedge.armed` also exists; the file\n * is consumed on fire so the respawned daemon boots normally.\n */\n SHIPYARD_DEBUG_WEDGE_AFTER_MS: z.coerce.number().int().nonnegative().optional(),\n /**\n * Always-on V8 sampling heap profiler that dumps a `.heapprofile` to\n * `{dataDir}/diagnostics` at 60/75/90% of the heap limit\n * (heap-pressure-profiler.ts). Default ON; set 0 to disable.\n */\n SHIPYARD_HEAP_PROFILER: z\n .enum(['1', 'true', '0', 'false', ''])\n .default('')\n .transform((v) => v !== '0' && v !== 'false'),\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 * Overrides the `spawning`-state stall budget for agent profiles that\n * declare one (Claude: 600 000 ms). Unset keeps each profile's default.\n */\n SHIPYARD_SPAWNING_STALL_TIMEOUT_MS: z.coerce.number().int().positive().optional(),\n /**\n * Wall-clock bound on a spawn's pre-spawn prep (hydration, resource\n * resolution, system-prompt assembly). Expiry fails the spawn. Keep it\n * below the spawning stall budget so this bound, not the watchdog, ends a\n * hung prep.\n */\n SHIPYARD_PRE_SPAWN_TIMEOUT_MS: z.coerce.number().int().positive().default(180_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 * Override the daemon's own --max-old-space-size (MB). When absent, the\n * value is auto-derived from os.totalmem() × 25 %, clamped to [2048, 8192].\n * An explicit value is honored as-is (clamped to 65536 to catch typos) and\n * passed to --max-old-space-size at BOTH spawn sites: the outer CLI\n * supervisor (start-supervisor.ts) and the Electron utility-process fork\n * (daemon-host.ts). See apps/daemon/src/shared/daemon-heap-limit.ts. The\n * Electron path also honors a `daemon.maxHeapGb` config.json setting below\n * this env var in precedence — see daemon-heap-limit-config.ts.\n */\n SHIPYARD_DAEMON_MAX_OLD_SPACE_MB: z.coerce.number().int().positive().optional(),\n /**\n * Auto-continue tasks whose turn was interrupted by a crash, wedge-kill,\n * app update or user restart (never Cmd+Q) rather than leaving them stuck\n * at `input_required`. Default OFF; while off, the boot phase still\n * computes and logs what WOULD have resumed (`interrupted_resume_disabled`).\n * See `services/bootstrap/interrupted-turn-resume.ts`.\n */\n /**\n * Why this daemon process was started, set by Electron main per spawn\n * (daemon-host.ts). A crash/wedge respawn always permits auto-resume; a\n * plain `launch` defers to the shutdown-reason marker\n * (`services/bootstrap/shutdown-reason.ts`). Unset under the CLI.\n */\n SHIPYARD_DAEMON_START_REASON: z\n .enum(['launch', 'respawn_after_crash', 'respawn_after_wedge', 'respawn_after_clean', 'probe'])\n .optional(),\n SHIPYARD_AUTO_RESUME_INTERRUPTED: z\n .enum(['1', 'true', '0', 'false', ''])\n .default('')\n .transform((v) => v === '1' || v === 'true'),\n /**\n * Whether the harness `task` tool REFUSES a cross-tree `cancel`/`complete`\n * from a spawned, non-automation task (`enforce`) or only logs\n * `task_control_ownership_violation` (`log_only`). See\n * `services/harness/task-control-ownership.ts`.\n */\n SHIPYARD_TASK_CONTROL_OWNERSHIP: z.enum(['enforce', 'log_only']).default('enforce'),\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":[]}
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  getShipyardHome,
4
4
  validateEnv
5
- } from "./chunk-DPUTHTSI.js";
5
+ } from "./chunk-PUPBVZTF.js";
6
6
 
7
7
  // src/shared/logger.ts
8
8
  import { mkdirSync } from "fs";
@@ -145,4 +145,4 @@ export {
145
145
  createChildLogger,
146
146
  flushLogger
147
147
  };
148
- //# sourceMappingURL=chunk-3SBYNPEE.js.map
148
+ //# sourceMappingURL=chunk-RBFSBLIB.js.map
@@ -7,10 +7,10 @@ import {
7
7
  } from "./chunk-VHPNDDB5.js";
8
8
  import {
9
9
  logger
10
- } from "./chunk-3SBYNPEE.js";
10
+ } from "./chunk-RBFSBLIB.js";
11
11
  import {
12
12
  getShipyardHome
13
- } from "./chunk-DPUTHTSI.js";
13
+ } from "./chunk-PUPBVZTF.js";
14
14
  import {
15
15
  external_exports
16
16
  } from "./chunk-XVW6VCKW.js";
@@ -287,7 +287,7 @@ async function refreshRepoPathsInBackground(log) {
287
287
  const startGen = cacheGeneration;
288
288
  const start = Date.now();
289
289
  try {
290
- const { findGitRepos: findGitRepos2, discoverWorktrees: discoverWorktrees2 } = await import("./git-repo-4RK3V42K.js");
290
+ const { findGitRepos: findGitRepos2, discoverWorktrees: discoverWorktrees2 } = await import("./git-repo-UXTZVQ7G.js");
291
291
  const { homedir: homedir2 } = await import("os");
292
292
  const repos = await findGitRepos2(homedir2());
293
293
  const worktrees = await discoverWorktrees2(repos);
@@ -679,7 +679,7 @@ async function runDetectEnvironments(lastKnown) {
679
679
  repoPaths = await findGitRepos(homedir2());
680
680
  } catch (err) {
681
681
  if (lastKnown && lastKnown.length > 0) {
682
- const { logger: logger2 } = await import("./logger-LBZ72MWP.js");
682
+ const { logger: logger2 } = await import("./logger-OFEJM3NC.js");
683
683
  logger2.warn(
684
684
  { err, lastKnownCount: lastKnown.length },
685
685
  "detectEnvironments findGitRepos threw \u2014 preserving lastKnown"
@@ -689,7 +689,7 @@ async function runDetectEnvironments(lastKnown) {
689
689
  return [];
690
690
  }
691
691
  if (repoPaths.length === 0 && lastKnown && lastKnown.length > 0) {
692
- const { logger: logger2 } = await import("./logger-LBZ72MWP.js");
692
+ const { logger: logger2 } = await import("./logger-OFEJM3NC.js");
693
693
  logger2.warn(
694
694
  { lastKnownCount: lastKnown.length },
695
695
  "detectEnvironments walk empty but lastKnown non-empty \u2014 preserving lastKnown"
@@ -822,4 +822,4 @@ export {
822
822
  discoverWorktrees,
823
823
  _testing
824
824
  };
825
- //# sourceMappingURL=chunk-KP7QKDRI.js.map
825
+ //# sourceMappingURL=chunk-TYTKRNCP.js.map
@@ -7,15 +7,15 @@ import {
7
7
  } from "./chunk-FWL2ZIEL.js";
8
8
  import {
9
9
  buildCursorUserPrompt
10
- } from "./chunk-OECIR7LF.js";
10
+ } from "./chunk-4IHDLC7O.js";
11
11
  import {
12
12
  ContentBlockSchema,
13
13
  HARNESS_SERVER_NAME
14
14
  } from "./chunk-Z5PJ2F56.js";
15
15
  import "./chunk-TIW46SCK.js";
16
16
  import "./chunk-EHQITHQX.js";
17
- import "./chunk-3SBYNPEE.js";
18
- import "./chunk-DPUTHTSI.js";
17
+ import "./chunk-RBFSBLIB.js";
18
+ import "./chunk-PUPBVZTF.js";
19
19
  import "./chunk-X3MULCV5.js";
20
20
  import "./chunk-XVW6VCKW.js";
21
21
  import "./chunk-2H7UOFLK.js";
@@ -1,21 +1,21 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  getDaemonVersion
4
- } from "./chunk-EZB7DECI.js";
4
+ } from "./chunk-34SZI5Y5.js";
5
5
  import {
6
6
  enableNativeCrashReports
7
- } from "./chunk-MN4VLZCP.js";
7
+ } from "./chunk-MDCJP6SD.js";
8
8
  import {
9
9
  installWasmPanicBuffer
10
10
  } from "./chunk-5OTUGRW3.js";
11
11
  import "./chunk-UNGAIUEX.js";
12
12
  import {
13
13
  logger
14
- } from "./chunk-3SBYNPEE.js";
14
+ } from "./chunk-RBFSBLIB.js";
15
15
  import {
16
16
  getShipyardHome,
17
17
  validateEnv
18
- } from "./chunk-DPUTHTSI.js";
18
+ } from "./chunk-PUPBVZTF.js";
19
19
  import "./chunk-XVW6VCKW.js";
20
20
  import "./chunk-2H7UOFLK.js";
21
21
 
@@ -40,7 +40,7 @@ function isVersionQuery(data) {
40
40
  }
41
41
  async function loadAuthFromConfig(env) {
42
42
  if (env.SHIPYARD_USER_TOKEN) return;
43
- const { loadAuthToken } = await import("./auth-73BYXHRC.js");
43
+ const { loadAuthToken } = await import("./auth-C4IBDTRR.js");
44
44
  const auth = await loadAuthToken();
45
45
  if (auth.status === "ok") {
46
46
  env.SHIPYARD_USER_TOKEN = auth.token;
@@ -71,7 +71,7 @@ async function main() {
71
71
  await loadAuthFromConfig(env);
72
72
  crumb("post-auth-load");
73
73
  crumb("pre-serve-import");
74
- const { serve } = await import("./serve-6R3OWK2F.js");
74
+ const { serve } = await import("./serve-FI5KNQA2.js");
75
75
  crumb("post-serve-import");
76
76
  const portQueue = [];
77
77
  let acceptor = null;