@tekmidian/pai 0.66.1 → 0.66.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 (158) hide show
  1. package/dist/{aibroker-client-B8c42Lh8.mjs → aibroker-client-CHEEvJZW.mjs} +2 -2
  2. package/dist/{aibroker-client-C5Fw7DNz.mjs → aibroker-client-Dfv7j1Od.mjs} +3 -3
  3. package/dist/{aibroker-client-C5Fw7DNz.mjs.map → aibroker-client-Dfv7j1Od.mjs.map} +1 -1
  4. package/dist/{auto-route-o0BOsXn7.mjs → auto-route-BnizyALK.mjs} +65 -4
  5. package/dist/auto-route-BnizyALK.mjs.map +1 -0
  6. package/dist/auto-route-D6fW1Q8z.mjs +3 -0
  7. package/dist/{chain-CZfKIEq9.mjs → chain-D5876UQX.mjs} +3 -4
  8. package/dist/{chain-CZfKIEq9.mjs.map → chain-D5876UQX.mjs.map} +1 -1
  9. package/dist/cli/index.mjs +18 -23
  10. package/dist/cli/index.mjs.map +1 -1
  11. package/dist/cli/program.mjs +17 -22
  12. package/dist/{config-BbLFD7Uf.mjs → config-C-LiGlop.mjs} +2 -2
  13. package/dist/{config-BbLFD7Uf.mjs.map → config-C-LiGlop.mjs.map} +1 -1
  14. package/dist/{config-YinjgXEJ.mjs → config-DKIA7wgF.mjs} +1 -1
  15. package/dist/{context-handover-cache-pkHzmL3c.mjs → context-handover-cache-9PGvXRIw.mjs} +984 -10
  16. package/dist/context-handover-cache-9PGvXRIw.mjs.map +1 -0
  17. package/dist/daemon/index.mjs +17 -19
  18. package/dist/daemon/index.mjs.map +1 -1
  19. package/dist/daemon-BUgNvMUh.mjs +5029 -0
  20. package/dist/daemon-BUgNvMUh.mjs.map +1 -0
  21. package/dist/daemon-DL0eglMJ.mjs +18 -0
  22. package/dist/daemon-mcp/index.mjs +12 -9
  23. package/dist/daemon-mcp/index.mjs.map +1 -1
  24. package/dist/{embeddings-CcscYWwk.mjs → embeddings-CEBGrzwu.mjs} +1 -1
  25. package/dist/{embeddings-Bx3q0QOY.mjs → embeddings-DOLZnT1X.mjs} +1 -1
  26. package/dist/{embeddings-Bx3q0QOY.mjs.map → embeddings-DOLZnT1X.mjs.map} +1 -1
  27. package/dist/{env-JNEIrQWg.mjs → env-DiolswKQ.mjs} +1 -1
  28. package/dist/{env-JNEIrQWg.mjs.map → env-DiolswKQ.mjs.map} +1 -1
  29. package/dist/factory-DrBg24UT.mjs +8 -0
  30. package/dist/factory-Ypf8r0fK.mjs +2892 -0
  31. package/dist/factory-Ypf8r0fK.mjs.map +1 -0
  32. package/dist/{fallback-CIiq2Raw.mjs → fallback-D51R4shY.mjs} +23 -11
  33. package/dist/fallback-D51R4shY.mjs.map +1 -0
  34. package/dist/{chunker-BH4i-F2b.mjs → helpers-CZsi_49C.mjs} +221 -2
  35. package/dist/helpers-CZsi_49C.mjs.map +1 -0
  36. package/dist/hooks/worker-status-line.mjs.map +2 -2
  37. package/dist/index.mjs +6 -7
  38. package/dist/{ipc-client-D16Xw6Uo.mjs → ipc-client-BLYX51nG.mjs} +2 -2
  39. package/dist/{ipc-client-D16Xw6Uo.mjs.map → ipc-client-BLYX51nG.mjs.map} +1 -1
  40. package/dist/main-resolver-BYgP86C1.mjs +7 -0
  41. package/dist/{main-resolver-DPPwHNtn.mjs → main-resolver-kVkMJZUD.mjs} +6 -6
  42. package/dist/{main-resolver-DPPwHNtn.mjs.map → main-resolver-kVkMJZUD.mjs.map} +1 -1
  43. package/dist/{migrate-BD7D8EEh.mjs → migrate-Bq0esMOa.mjs} +2 -2
  44. package/dist/{migrate-BD7D8EEh.mjs.map → migrate-Bq0esMOa.mjs.map} +1 -1
  45. package/dist/{pai-marker-D1MMswkz.mjs → pai-marker-DXVpFsYz.mjs} +1 -1
  46. package/dist/{pai-marker-D1MMswkz.mjs.map → pai-marker-DXVpFsYz.mjs.map} +1 -1
  47. package/dist/{planner-Dm5Acyo1.mjs → planner-D5yt0EfA.mjs} +10 -7
  48. package/dist/{planner-Dm5Acyo1.mjs.map → planner-D5yt0EfA.mjs.map} +1 -1
  49. package/dist/postgres-BmLr0MUm.mjs +5 -0
  50. package/dist/{postgres-Ceqsa64C.mjs → postgres-D3xc2RB4.mjs} +364 -9
  51. package/dist/postgres-D3xc2RB4.mjs.map +1 -0
  52. package/dist/{program-JJ0TwSHI.mjs → program-DIXRtAFy.mjs} +77 -70
  53. package/dist/program-DIXRtAFy.mjs.map +1 -0
  54. package/dist/{query-feedback-BIaZTTFO.mjs → query-feedback-B7FYE4JR.mjs} +1 -1
  55. package/dist/{query-feedback-BIaZTTFO.mjs.map → query-feedback-B7FYE4JR.mjs.map} +1 -1
  56. package/dist/{reranker-DKv80KO5.mjs → reranker-3lnggwgq.mjs} +1 -1
  57. package/dist/{reranker-DKv80KO5.mjs.map → reranker-3lnggwgq.mjs.map} +1 -1
  58. package/dist/{reranker-CFiEzHQu.mjs → reranker-CZ2mP4cf.mjs} +1 -1
  59. package/dist/router-BK-hFeQ6.mjs +3 -0
  60. package/dist/{router-a5G7q8_3.mjs → router-BaTbc9VX.mjs} +2 -2
  61. package/dist/{router-a5G7q8_3.mjs.map → router-BaTbc9VX.mjs.map} +1 -1
  62. package/dist/{run-BCpbxqA5.mjs → run-CLYTOm0x.mjs} +599 -22
  63. package/dist/run-CLYTOm0x.mjs.map +1 -0
  64. package/dist/{run-env-DRcp7A8K.mjs → run-env-Bnmf6bRI.mjs} +2 -2
  65. package/dist/{run-env-DRcp7A8K.mjs.map → run-env-Bnmf6bRI.mjs.map} +1 -1
  66. package/dist/{runtime-paths-CHTg3ywb.mjs → runtime-paths-D3FKAm69.mjs} +1 -1
  67. package/dist/{runtime-paths-CHTg3ywb.mjs.map → runtime-paths-D3FKAm69.mjs.map} +1 -1
  68. package/dist/{search-BOSphCJ1.mjs → search-CNAGTiJP.mjs} +2 -2
  69. package/dist/{search-BOSphCJ1.mjs.map → search-CNAGTiJP.mjs.map} +1 -1
  70. package/dist/{sources-CijVso3n.mjs → sources-CM2g-CLT.mjs} +2 -2
  71. package/dist/{sources-CijVso3n.mjs.map → sources-CM2g-CLT.mjs.map} +1 -1
  72. package/dist/{stop-words-BdQuaE9K.mjs → stop-words-DtxaTWU_.mjs} +1 -1
  73. package/dist/{stop-words-BdQuaE9K.mjs.map → stop-words-DtxaTWU_.mjs.map} +1 -1
  74. package/dist/{utils-C9HsYDpO.mjs → utils-DddRwMsG.mjs} +2 -2
  75. package/dist/{utils-C9HsYDpO.mjs.map → utils-DddRwMsG.mjs.map} +1 -1
  76. package/dist/{zettelkasten-CtGHQWPU.mjs → zettelkasten-BhZMvmoK.mjs} +149 -7
  77. package/dist/zettelkasten-BhZMvmoK.mjs.map +1 -0
  78. package/dist/zettelkasten-BwV1pluL.mjs +5 -0
  79. package/docs/commands/worker.md +2 -0
  80. package/package.json +1 -1
  81. package/dist/async-C2Bm_Lal.mjs +0 -300
  82. package/dist/async-C2Bm_Lal.mjs.map +0 -1
  83. package/dist/auto-route-o0BOsXn7.mjs.map +0 -1
  84. package/dist/chunker-BH4i-F2b.mjs.map +0 -1
  85. package/dist/clusters-BCtD3fbe.mjs +0 -169
  86. package/dist/clusters-BCtD3fbe.mjs.map +0 -1
  87. package/dist/context-handover-cache-pkHzmL3c.mjs.map +0 -1
  88. package/dist/daemon-DXlaVCkw.mjs +0 -1741
  89. package/dist/daemon-DXlaVCkw.mjs.map +0 -1
  90. package/dist/daemon-DyORmxZu.mjs +0 -19
  91. package/dist/detector-BEPFsINR.mjs +0 -3
  92. package/dist/detector-BRTtAWrM.mjs +0 -65
  93. package/dist/detector-BRTtAWrM.mjs.map +0 -1
  94. package/dist/factory-CNpPQQ-5.mjs +0 -249
  95. package/dist/factory-CNpPQQ-5.mjs.map +0 -1
  96. package/dist/factory-DY7x73mE.mjs +0 -3
  97. package/dist/fallback-CIiq2Raw.mjs.map +0 -1
  98. package/dist/federation-db-BTyoufBh.mjs +0 -139
  99. package/dist/federation-db-BTyoufBh.mjs.map +0 -1
  100. package/dist/federation-db-HfIFc7FG.mjs +0 -3
  101. package/dist/helpers-BRCJg0G3.mjs +0 -223
  102. package/dist/helpers-BRCJg0G3.mjs.map +0 -1
  103. package/dist/indexer-backend-DFF2FrYx.mjs +0 -5
  104. package/dist/indexer-backend-isSLg6yE.mjs +0 -1
  105. package/dist/kg-entity-DCOcsVFD.mjs +0 -29
  106. package/dist/kg-entity-DCOcsVFD.mjs.map +0 -1
  107. package/dist/latent-ideas-wwAXquGe.mjs +0 -191
  108. package/dist/latent-ideas-wwAXquGe.mjs.map +0 -1
  109. package/dist/link-boost-CnI7UVMJ.mjs +0 -34
  110. package/dist/link-boost-CnI7UVMJ.mjs.map +0 -1
  111. package/dist/main-resolver-BKz_OuEh.mjs +0 -7
  112. package/dist/merge-2gqRPFu2.mjs +0 -3
  113. package/dist/merge-DgU9OgZy.mjs +0 -6
  114. package/dist/merge-DgU9OgZy.mjs.map +0 -1
  115. package/dist/module-paths-DdRzbkUI.mjs +0 -44
  116. package/dist/module-paths-DdRzbkUI.mjs.map +0 -1
  117. package/dist/neighborhood-2FsmzoxG.mjs +0 -114
  118. package/dist/neighborhood-2FsmzoxG.mjs.map +0 -1
  119. package/dist/note-context-De63k8na.mjs +0 -106
  120. package/dist/note-context-De63k8na.mjs.map +0 -1
  121. package/dist/postgres-Ceqsa64C.mjs.map +0 -1
  122. package/dist/program-JJ0TwSHI.mjs.map +0 -1
  123. package/dist/query-feedback-B_iigYj-.mjs +0 -3
  124. package/dist/registry-db-C7voqML9.mjs +0 -213
  125. package/dist/registry-db-C7voqML9.mjs.map +0 -1
  126. package/dist/registry-db-JHPhA8vF.mjs +0 -3
  127. package/dist/registry-postgres-nOfyBSIW.mjs +0 -795
  128. package/dist/registry-postgres-nOfyBSIW.mjs.map +0 -1
  129. package/dist/registry-sqlite-DrCW1aRK.mjs +0 -593
  130. package/dist/registry-sqlite-DrCW1aRK.mjs.map +0 -1
  131. package/dist/router-CXUGsv85.mjs +0 -3
  132. package/dist/run-BCpbxqA5.mjs.map +0 -1
  133. package/dist/search-Bf3Kub3F.mjs +0 -3
  134. package/dist/server-DgmAHyFK.mjs +0 -403
  135. package/dist/server-DgmAHyFK.mjs.map +0 -1
  136. package/dist/session-keepalive-DxjTHGcK.mjs +0 -582
  137. package/dist/session-keepalive-DxjTHGcK.mjs.map +0 -1
  138. package/dist/sqlite-CqsTy6xo.mjs +0 -936
  139. package/dist/sqlite-CqsTy6xo.mjs.map +0 -1
  140. package/dist/state-DW8zdweW.mjs +0 -3
  141. package/dist/state-HyjqTihC.mjs +0 -76
  142. package/dist/state-HyjqTihC.mjs.map +0 -1
  143. package/dist/themes-CTaOj3e1.mjs +0 -148
  144. package/dist/themes-CTaOj3e1.mjs.map +0 -1
  145. package/dist/tools-BcOKPBtg.mjs +0 -1489
  146. package/dist/tools-BcOKPBtg.mjs.map +0 -1
  147. package/dist/tools-C-_l0o8Z.mjs +0 -6
  148. package/dist/trace-CtV0RO6n.mjs +0 -137
  149. package/dist/trace-CtV0RO6n.mjs.map +0 -1
  150. package/dist/utils-BrX9FLeK.mjs +0 -3
  151. package/dist/vault-indexer-BG1sEVyM.mjs +0 -537
  152. package/dist/vault-indexer-BG1sEVyM.mjs.map +0 -1
  153. package/dist/wakeup-D8n33hYV.mjs +0 -335
  154. package/dist/wakeup-D8n33hYV.mjs.map +0 -1
  155. package/dist/work-queue-worker-4tLa5gpQ.mjs +0 -567
  156. package/dist/work-queue-worker-4tLa5gpQ.mjs.map +0 -1
  157. package/dist/work-queue-worker-rFZvTO3p.mjs +0 -11
  158. package/dist/zettelkasten-CtGHQWPU.mjs.map +0 -1
@@ -1,11 +1,12 @@
1
- import { i as getRegistryBackend } from "./factory-CNpPQQ-5.mjs";
2
- import { A as resolveProviderKey, D as readWorkersSection, E as providerKeyPath, _ as classModelCapability, f as NATIVE_ANTHROPIC_MODELS, g as assertProviderRunnable, h as WorkersConfigError, k as resolveModelCapability, n as claudeCommand, t as buildRunEnv, x as isModelCapability } from "./run-env-DRcp7A8K.mjs";
3
- import { _ as statusPath, d as resolveTarget, f as setCooldown, g as panesDir, h as ledgerPath, i as capabilityForRun, m as eventsPath, n as ensureProxyRunning, o as isQuotaFailure, p as ensureNoMcpConfig, s as nextAutoProvider, t as DEFAULT_PROXY_PORT, u as resolveCapabilityRun, v as workersLogDir } from "./server-DgmAHyFK.mjs";
1
+ import { i as getRegistryBackend } from "./factory-Ypf8r0fK.mjs";
2
+ import { a as paiHomePath, o as resolvePaiFile } from "./pai-home-Cm9rcJgX.mjs";
3
+ import { A as resolveProviderKey, D as readWorkersSection, E as providerKeyPath, O as resolveCapability, T as providerCostTier, _ as classModelCapability, b as getProviderOrNative, f as NATIVE_ANTHROPIC_MODELS, g as assertProviderRunnable, h as WorkersConfigError, k as resolveModelCapability, m as WORKER_CLASSES, n as claudeCommand, o as DEFAULT_LOG_DIR, r as ANTHROPIC_NATIVE, t as buildRunEnv, x as isModelCapability, y as expandHome } from "./run-env-Bnmf6bRI.mjs";
4
4
  import { appendFileSync, closeSync, existsSync, lstatSync, mkdirSync, mkdtempSync, openSync, readFileSync, readdirSync, readlinkSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
5
5
  import { homedir, platform, tmpdir } from "node:os";
6
6
  import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
7
- import { execFileSync, spawn } from "node:child_process";
7
+ import { fileURLToPath } from "node:url";
8
8
  import { connect, createServer } from "node:net";
9
+ import { execFileSync, spawn } from "node:child_process";
9
10
  import { createInterface } from "node:readline";
10
11
 
11
12
  //#region src/workers/mcp.ts
@@ -223,6 +224,399 @@ function pinNotices(launch, claudeJson) {
223
224
  return lines;
224
225
  }
225
226
 
227
+ //#endregion
228
+ //#region src/workers/paths.ts
229
+ /**
230
+ * paths.ts — where worker run artefacts live.
231
+ *
232
+ * Everything a run writes (event mirror, status file, pane registry, routing
233
+ * state, the empty MCP config) sits under one logDir so the whole tree is
234
+ * disposable and configurable: `workers.logDir`, default ~/.claude/logs/workers.
235
+ */
236
+ /**
237
+ * Absolute logDir for the given config. An explicit `logDir` in workers.yaml
238
+ * is honored verbatim (the user chose it). Otherwise this resolves like every
239
+ * other PAI_HOME file: PAI_HOME/logs/workers if it exists, else the old
240
+ * ~/.claude/logs/workers (with a one-time notice), else the new path.
241
+ */
242
+ function workersLogDir(config) {
243
+ const expanded = expandHome(config.logDir);
244
+ if (config.logDir !== DEFAULT_LOG_DIR) return expanded;
245
+ return resolvePaiFile(paiHomePath("logs", "workers"), [expanded], "pai config migrate --logs");
246
+ }
247
+ /** The strict empty MCP config for headless runs, written on demand. */
248
+ function ensureNoMcpConfig(logDir) {
249
+ const path = noMcpConfigPath(logDir);
250
+ if (!existsSync(path)) {
251
+ mkdirSync(logDir, { recursive: true });
252
+ writeFileSync(path, "{ \"mcpServers\": {} }\n", "utf8");
253
+ }
254
+ return path;
255
+ }
256
+ function statusPath(logDir, id) {
257
+ return join(logDir, `${id}.status`);
258
+ }
259
+ function eventsPath(logDir, id) {
260
+ return join(logDir, `${id}.jsonl`);
261
+ }
262
+ function ledgerPath(logDir) {
263
+ return join(logDir, "ledger.log");
264
+ }
265
+ function routingStatePath(logDir) {
266
+ return join(logDir, "routing-state.json");
267
+ }
268
+ function panesDir(logDir) {
269
+ return join(logDir, "panes");
270
+ }
271
+ /**
272
+ * The strict empty MCP config handed to headless workers. Written into the
273
+ * logDir on demand (never into the user's vendor config directory — this is
274
+ * PAI state, not vendor state).
275
+ */
276
+ function noMcpConfigPath(logDir) {
277
+ return join(logDir, "no-mcp.json");
278
+ }
279
+
280
+ //#endregion
281
+ //#region src/workers/routing.ts
282
+ /**
283
+ * routing.ts — provider selection: flag > class > active (possibly "auto").
284
+ *
285
+ * Auto-routing walks `workers.routing.order` — or the class's own `order` —
286
+ * and takes the first provider that is enabled, out of cooldown, (when it
287
+ * defines a quotaProbe) under its quotaSkipAt threshold, and — when the class
288
+ * constrains it — within `maxCostTier` and carrying all `requireTags`. A run
289
+ * that dies of a quota/rate error puts its provider in cooldown for
290
+ * cooldownMinutes; when that happens before the first tool call and
291
+ * retryOnQuota is set, the runner restarts the same task on the next provider
292
+ * (ledger: WORKER-REROUTE).
293
+ *
294
+ * An explicit --provider or a class mapping that pins a provider always
295
+ * bypasses all of this.
296
+ */
297
+ const QUOTA_SKIP_DEFAULT = 95;
298
+ const PROBE_TIMEOUT_MS = 1e4;
299
+ function readRoutingState(logDir) {
300
+ const path = routingStatePath(logDir);
301
+ if (!existsSync(path)) return { cooldowns: {} };
302
+ try {
303
+ return { cooldowns: JSON.parse(readFileSync(path, "utf8")).cooldowns ?? {} };
304
+ } catch {
305
+ return { cooldowns: {} };
306
+ }
307
+ }
308
+ function writeRoutingState(logDir, state) {
309
+ const path = routingStatePath(logDir);
310
+ const dir = dirname(path);
311
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
312
+ const tmp = `${path}.tmp`;
313
+ writeFileSync(tmp, JSON.stringify(state, null, 2) + "\n", "utf8");
314
+ renameSync(tmp, path);
315
+ }
316
+ function cooldownRemaining(state, provider, now = /* @__PURE__ */ new Date()) {
317
+ const end = state.cooldowns[provider];
318
+ if (!end) return 0;
319
+ const ms = Date.parse(end) - now.getTime();
320
+ return ms > 0 ? ms : 0;
321
+ }
322
+ function setCooldown(logDir, provider, minutes, now = /* @__PURE__ */ new Date()) {
323
+ const state = readRoutingState(logDir);
324
+ state.cooldowns[provider] = new Date(now.getTime() + minutes * 6e4).toISOString();
325
+ writeRoutingState(logDir, state);
326
+ }
327
+ function clearCooldown(logDir, provider) {
328
+ const state = readRoutingState(logDir);
329
+ if (!(provider in state.cooldowns)) return;
330
+ delete state.cooldowns[provider];
331
+ writeRoutingState(logDir, state);
332
+ }
333
+ /**
334
+ * Run a provider's quotaProbe and return its percentage (0–100), or null when
335
+ * there is no probe or it printed nothing usable. A probe must never break
336
+ * routing: failures read as "unknown", not as "full".
337
+ */
338
+ function probeQuota(provider) {
339
+ if (!provider.quotaProbe) return null;
340
+ try {
341
+ const m = execFileSync("/bin/sh", ["-c", provider.quotaProbe], {
342
+ timeout: PROBE_TIMEOUT_MS,
343
+ encoding: "utf8",
344
+ stdio: [
345
+ "ignore",
346
+ "pipe",
347
+ "ignore"
348
+ ]
349
+ }).match(/(\d+(?:\.\d+)?)/);
350
+ if (!m) return null;
351
+ return Math.min(100, Math.max(0, Math.round(parseFloat(m[1]))));
352
+ } catch {
353
+ return null;
354
+ }
355
+ }
356
+ function quotaSkipThreshold(provider) {
357
+ return provider.quotaSkipAt ?? QUOTA_SKIP_DEFAULT;
358
+ }
359
+ /** Does this provider exceed its quota threshold right now? */
360
+ function quotaExceeded(provider) {
361
+ const used = probeQuota(provider);
362
+ return used !== null && used >= quotaSkipThreshold(provider);
363
+ }
364
+ var NoProviderError = class extends WorkersConfigError {};
365
+ function mustExist(config, name) {
366
+ const p = getProviderOrNative(config, name);
367
+ if (!p) throw new NoProviderError(`no worker provider named "${name}". Configured: ${Object.keys(config.providers).join(", ") || "(none)"}.\nAdd one with: pai worker providers add <name> --base-url <url> --key-file <path> --model <model>`);
368
+ return p;
369
+ }
370
+ function mustBeRunnable(name, p) {
371
+ if (!p.enabled) throw new NoProviderError(`provider "${name}" is disabled. Enable it with: pai worker providers enable ${name}`);
372
+ return p;
373
+ }
374
+ /** Why one provider of a routing order did not qualify (message fragment). */
375
+ function exclusionReason(config, state, name, cls) {
376
+ const p = getProviderOrNative(config, name);
377
+ if (!p) return "not configured";
378
+ if (!p.enabled) return "disabled";
379
+ if (cooldownRemaining(state, name) > 0) return "cooldown";
380
+ if (quotaExceeded(p)) return "quota";
381
+ const tier = providerCostTier(p);
382
+ if (cls?.maxCostTier !== void 0 && tier > cls.maxCostTier) return `cost tier ${tier} > max ${cls.maxCostTier}`;
383
+ if (cls?.requireTags?.length) {
384
+ const have = p.tags ?? [];
385
+ const missing = cls.requireTags.filter((t) => !have.includes(t));
386
+ if (missing.length) return `missing tags: ${missing.join(", ")}`;
387
+ }
388
+ return null;
389
+ }
390
+ /**
391
+ * Resolve which provider (and model alias) a run uses.
392
+ *
393
+ * @param flagProvider --provider value, highest precedence
394
+ * @param className --class value (the old --role), looked up in workers.classes
395
+ */
396
+ function resolveTarget(config, logDir, opts = {}) {
397
+ if (opts.flagProvider) return {
398
+ providerName: opts.flagProvider,
399
+ provider: mustBeRunnable(opts.flagProvider, mustExist(config, opts.flagProvider)),
400
+ modelAlias: null,
401
+ classMcp: null,
402
+ via: "flag"
403
+ };
404
+ const clsTarget = opts.className ? config.classes[opts.className] : void 0;
405
+ const cls = typeof clsTarget === "object" && clsTarget !== null ? clsTarget : void 0;
406
+ if (opts.className && clsTarget !== void 0 && typeof clsTarget !== "object") {
407
+ const [name, alias] = clsTarget.split("/");
408
+ return {
409
+ providerName: name,
410
+ provider: mustBeRunnable(name, mustExist(config, name)),
411
+ modelAlias: alias ?? null,
412
+ classMcp: null,
413
+ via: "class"
414
+ };
415
+ }
416
+ if (opts.className && cls?.provider) {
417
+ const provider = mustBeRunnable(cls.provider, mustExist(config, cls.provider));
418
+ return {
419
+ providerName: cls.provider,
420
+ provider,
421
+ modelAlias: null,
422
+ classMcp: cls.mcp ?? null,
423
+ via: "class"
424
+ };
425
+ }
426
+ if (opts.className && clsTarget === void 0) {
427
+ if (!WORKER_CLASSES.includes(opts.className)) throw new NoProviderError(`no class named "${opts.className}". Standard classes: ${WORKER_CLASSES.join(", ")}.Defined: ${Object.keys(config.classes).join(", ") || "(none)"}.\nSet one with: pai worker classes set ${opts.className}=<provider[/alias]>`);
428
+ }
429
+ if (config.active !== "auto") {
430
+ const name = config.active ?? ANTHROPIC_NATIVE;
431
+ return {
432
+ providerName: name,
433
+ provider: mustBeRunnable(name, mustExist(config, name)),
434
+ modelAlias: null,
435
+ classMcp: null,
436
+ via: "active"
437
+ };
438
+ }
439
+ const state = readRoutingState(logDir);
440
+ const order = cls?.order ?? config.routing.order;
441
+ const excluded = [];
442
+ for (const name of order) {
443
+ const p = getProviderOrNative(config, name);
444
+ const why = exclusionReason(config, state, name, cls);
445
+ if (why) {
446
+ excluded.push(`${name}: ${why}`);
447
+ continue;
448
+ }
449
+ return {
450
+ providerName: name,
451
+ provider: p,
452
+ modelAlias: null,
453
+ classMcp: cls?.mcp ?? null,
454
+ via: "auto"
455
+ };
456
+ }
457
+ throw new NoProviderError(`auto-routing found no usable provider${opts.className ? ` for class "${opts.className}"` : ""} (order: [${order.join(", ")}]).${excluded.length ? `\nExcluded: ${excluded.join("; ")}.` : ""}\nClear a cooldown with: pai worker providers enable <name>; widen the class with: pai worker classes set ${opts.className ?? "<class>"}=<target>`);
458
+ }
459
+ /**
460
+ * Next provider after `from` in auto order, applying the same filters.
461
+ * Used by rerouting; null when the order is exhausted.
462
+ */
463
+ function nextAutoProvider(config, logDir, from, now = /* @__PURE__ */ new Date()) {
464
+ const state = readRoutingState(logDir);
465
+ const order = config.routing.order;
466
+ const start = order.indexOf(from);
467
+ for (let i = start + 1; i < order.length; i++) {
468
+ const name = order[i];
469
+ const p = getProviderOrNative(config, name);
470
+ if (!p || !p.enabled) continue;
471
+ const end = state.cooldowns[name];
472
+ if (end && Date.parse(end) > now.getTime()) continue;
473
+ if (quotaExceeded(p)) continue;
474
+ return name;
475
+ }
476
+ return null;
477
+ }
478
+ /**
479
+ * Was this failure a quota/rate failure? Detected from the result text the
480
+ * endpoint produced (HTTP status is not visible in the stream events).
481
+ */
482
+ function isQuotaFailure(resultText) {
483
+ return /usage limit reached|rate limit|quota/i.test(resultText);
484
+ }
485
+ /**
486
+ * Whether a run should resolve through `resolveCapability` instead of
487
+ * `resolveTarget`: an explicit `--capability` always does. A `--class`
488
+ * whose implied capability is not "default" (e.g. `image`) does too, but
489
+ * only when the class itself names no provider — a class already pinned to
490
+ * one (`image: glm/image`) always wins unchanged, same as any other class.
491
+ */
492
+ function capabilityForRun(config, opts) {
493
+ if (opts.capabilityFlag) return opts.capabilityFlag;
494
+ if (!opts.className) return null;
495
+ const capability = classModelCapability(opts.className);
496
+ if (capability === "default") return null;
497
+ const clsTarget = config.classes[opts.className];
498
+ return (typeof clsTarget === "string" ? true : Boolean(clsTarget?.provider)) ? null : capability;
499
+ }
500
+ /**
501
+ * resolveCapability, turned into a runnable provider (NoProviderError-shaped
502
+ * on failure). Unlike resolveCapability itself — which falls back to the
503
+ * active provider's default model so `describeCapabilities` has something to
504
+ * report — an actual run refuses the fallback: silently running a normal
505
+ * model on a prompt written for a capability it does not have (an image
506
+ * prompt fed to a text model, say) produces a confusing non-answer instead
507
+ * of a clear error naming the config key to set.
508
+ */
509
+ function resolveCapabilityRun(config, capability) {
510
+ const r = resolveCapability(config, capability);
511
+ if (r.fellBack) throw new NoProviderError(`no provider declares the "${capability}" capability — configure one with: pai worker capability ${capability} <provider>[,<provider>…], or pai worker model ${capability} <model-id> --provider <name>`);
512
+ if (capability === "image" && r.engine !== "image") throw new NoProviderError(`provider "${r.provider}" has no image engine (it would run "${r.model}" on its normal ${r.engine} engine, not generate an image) — configure an engine=image provider with: pai worker providers add <name> --engine image --url <url> --key <key> --model <id>, then pai worker capability image <name>`);
513
+ const provider = getProviderOrNative(config, r.provider);
514
+ if (!provider) throw new NoProviderError(`capability "${capability}" resolved to unknown provider "${r.provider}"`);
515
+ return {
516
+ providerName: r.provider,
517
+ provider,
518
+ model: r.model,
519
+ engine: r.engine,
520
+ fellBack: r.fellBack,
521
+ capability
522
+ };
523
+ }
524
+
525
+ //#endregion
526
+ //#region src/workers/proxy/server.ts
527
+ /**
528
+ * server.ts — the PAI worker proxy: Anthropic Messages API on the front,
529
+ * OpenAI Chat Completions on the back, loopback only.
530
+ *
531
+ * One proxy serves every OpenAI-protocol provider: Claude Code points
532
+ * ANTHROPIC_BASE_URL at `http://127.0.0.1:8797/<provider>` and the provider
533
+ * name in the path selects the upstream (`upstreamUrl` + `keyFile` from the
534
+ * workers config, re-read per request so config edits apply without a
535
+ * restart). `run` starts the proxy on demand (detached, pid file under the
536
+ * logDir) and `pai worker proxy stop` stops it again.
537
+ *
538
+ * All translation lives in translate.ts; this file is only HTTP plumbing.
539
+ */
540
+ const DEFAULT_PROXY_PORT = 8797;
541
+ const HOST = "127.0.0.1";
542
+ function proxyPidPath(logDir) {
543
+ return join(logDir, "proxy.pid");
544
+ }
545
+ /** True when something already accepts connections on the port. */
546
+ function proxyListening(port = DEFAULT_PROXY_PORT, timeoutMs = 400) {
547
+ return new Promise((resolve) => {
548
+ const sock = connect({
549
+ port,
550
+ host: HOST
551
+ });
552
+ const done = (ok) => {
553
+ sock.removeAllListeners();
554
+ sock.destroy();
555
+ resolve(ok);
556
+ };
557
+ sock.setTimeout(timeoutMs, () => done(false));
558
+ sock.once("connect", () => done(true));
559
+ sock.once("error", () => done(false));
560
+ });
561
+ }
562
+ /**
563
+ * Where the standalone proxy artefact lives, found from this module's own
564
+ * location (dist/cli bundle → ../hooks/, dev checkout → <repo>/dist/hooks).
565
+ */
566
+ function standaloneProxyPath() {
567
+ let dir = dirname(fileURLToPath(import.meta.url));
568
+ for (let i = 0; i < 6; i++) {
569
+ for (const cand of [
570
+ join(dir, "worker-proxy.mjs"),
571
+ join(dir, "hooks", "worker-proxy.mjs"),
572
+ join(dir, "dist", "hooks", "worker-proxy.mjs")
573
+ ]) if (existsSync(cand)) return cand;
574
+ const parent = dirname(dir);
575
+ if (parent === dir) break;
576
+ dir = parent;
577
+ }
578
+ return null;
579
+ }
580
+ /**
581
+ * Ensure a proxy is listening on the port; start the detached standalone when
582
+ * nothing answers. Returns the base URL (`http://127.0.0.1:<port>`).
583
+ */
584
+ async function ensureProxyRunning(port, logDir) {
585
+ if (await proxyListening(port)) return `http://${HOST}:${port}`;
586
+ const script = standaloneProxyPath();
587
+ if (!script) throw new Error(`the PAI worker proxy is not running and its build was not found — run \`bun run build\` (or start one with: pai worker proxy --port ${port})`);
588
+ if (!existsSync(logDir)) mkdirSync(logDir, { recursive: true });
589
+ const child = spawn(process.execPath, [
590
+ script,
591
+ "--port",
592
+ String(port)
593
+ ], {
594
+ detached: true,
595
+ stdio: "ignore"
596
+ });
597
+ child.unref();
598
+ writeFileSync(proxyPidPath(logDir), `${child.pid}\n`, "utf8");
599
+ for (let i = 0; i < 40; i++) {
600
+ if (await proxyListening(port)) return `http://${HOST}:${port}`;
601
+ await new Promise((r) => setTimeout(r, 250));
602
+ }
603
+ throw new Error(`the PAI worker proxy did not come up on port ${port} (see ${proxyPidPath(logDir)})`);
604
+ }
605
+ /** `pai worker proxy stop`: SIGTERM the pid from the pid file. */
606
+ function stopProxy(logDir) {
607
+ const path = proxyPidPath(logDir);
608
+ if (!existsSync(path)) return "no proxy pid file — nothing to stop";
609
+ const pid = parseInt(readFileSync(path, "utf8").trim(), 10);
610
+ unlinkSync(path);
611
+ if (!Number.isFinite(pid)) return "stale proxy pid file removed";
612
+ try {
613
+ process.kill(pid, "SIGTERM");
614
+ } catch {
615
+ return `proxy pid ${pid} was not running (pid file removed)`;
616
+ }
617
+ return `proxy pid ${pid} stopped`;
618
+ }
619
+
226
620
  //#endregion
227
621
  //#region src/workers/args.ts
228
622
  function parseRunnerArgs(argv) {
@@ -2058,7 +2452,7 @@ async function runImageCapability(opts) {
2058
2452
  * dynamic profile (Close Sessions On End), so panes disappear by themselves.
2059
2453
  *
2060
2454
  * Panes are tracked per scope (AIBroker session id, else tab key) in
2061
- * <logDir>/panes/<key>.json, keyed by iTerm session unique id, newest first —
2455
+ * <logDir>/panes/<key>/<worker id>.json (one file per worker), iTerm session unique id, newest first —
2062
2456
  * the split lands below the lowest live worker pane.
2063
2457
  *
2064
2458
  * The dynamic profile's font is the family of iTerm's DEFAULT profile (the
@@ -2459,21 +2853,204 @@ async function followProfile(fontSize, read = itermPrefs) {
2459
2853
  process.stderr.write(`pai worker pane: profile ${PROFILE_NAME} not visible, splitting with default\n`);
2460
2854
  return "";
2461
2855
  }
2462
- function loadRegistry(path) {
2856
+ /**
2857
+ * One file per worker, `<panes>/<scope>/<worker id>.json`: concurrent opens
2858
+ * for the same scope write different files, so none can be lost (the former
2859
+ * shared `<scope>.json` list was a read-modify-write that dropped entries when
2860
+ * workers started a second apart). Legacy `<scope>.json` lists are still read.
2861
+ */
2862
+ function readEntry(path, scope) {
2463
2863
  try {
2464
- const reg = JSON.parse(readFileSync(path, "utf8"));
2465
- return Array.isArray(reg) ? reg : [];
2864
+ const v = JSON.parse(readFileSync(path, "utf8"));
2865
+ return (Array.isArray(v) ? v : [v]).filter((e) => !!e && typeof e.session === "string" && typeof e.worker === "string").map((e) => ({
2866
+ ...e,
2867
+ scope
2868
+ }));
2466
2869
  } catch {
2467
2870
  return [];
2468
2871
  }
2469
2872
  }
2470
- function saveRegistry(path, reg) {
2471
- const dir = dirname(path);
2472
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
2473
- const tmp = `${path}.tmp`;
2474
- writeFileSync(tmp, JSON.stringify(reg, null, 1), "utf8");
2873
+ /** Registry entries of one scope (`scope` set) or of all scopes, oldest first. */
2874
+ function loadRegistry(logDir, scope) {
2875
+ const root = panesDir(logDir);
2876
+ const out = [];
2877
+ let names = [];
2878
+ try {
2879
+ names = readdirSync(root);
2880
+ } catch {
2881
+ return out;
2882
+ }
2883
+ for (const name of names.sort()) {
2884
+ const full = join(root, name);
2885
+ if (name.endsWith(".json")) {
2886
+ const sc = name.slice(0, -5);
2887
+ if (!scope || sc === scope) out.push(...readEntry(full, sc));
2888
+ } else if (!scope || name === scope) try {
2889
+ for (const f of readdirSync(full)) if (f.endsWith(".json")) out.push(...readEntry(join(full, f), name));
2890
+ } catch {}
2891
+ }
2892
+ return out.sort((x, y) => x.opened.localeCompare(y.opened));
2893
+ }
2894
+ function entryPath(logDir, e) {
2895
+ return join(panesDir(logDir), e.scope ?? "", `${e.worker}.json`);
2896
+ }
2897
+ function saveEntry(logDir, e) {
2898
+ const path = entryPath(logDir, e);
2899
+ mkdirSync(dirname(path), { recursive: true });
2900
+ const tmp = `${path}.${process.pid}.tmp`;
2901
+ writeFileSync(tmp, JSON.stringify({
2902
+ session: e.session,
2903
+ worker: e.worker,
2904
+ opened: e.opened
2905
+ }, null, 1), "utf8");
2475
2906
  renameSync(tmp, path);
2476
2907
  }
2908
+ /** Forget an entry (its per-worker file; a legacy list is rewritten without it). */
2909
+ function dropEntry(logDir, e) {
2910
+ const legacy = join(panesDir(logDir), `${e.scope}.json`);
2911
+ rmSync(entryPath(logDir, e), { force: true });
2912
+ if (existsSync(legacy)) {
2913
+ const rest = readEntry(legacy, e.scope ?? "").filter((x) => x.session !== e.session);
2914
+ writeFileSync(legacy, JSON.stringify(rest.map(({ scope: _s, ...x }) => x), null, 1), "utf8");
2915
+ }
2916
+ }
2917
+ const LIST_SESSIONS_SCRIPT = `on run(argv)
2918
+ set out to ""
2919
+ tell application id "com.googlecode.iterm2"
2920
+ if not running then return ""
2921
+ repeat with w in windows
2922
+ repeat with t in tabs of w
2923
+ repeat with s in sessions of t
2924
+ set out to out & (id of s as text) & (ASCII character 9) & (tty of s as text) & (ASCII character 9) & (name of s as text) & linefeed
2925
+ end repeat
2926
+ end repeat
2927
+ end repeat
2928
+ end tell
2929
+ return out
2930
+ end run`;
2931
+ const END_SESSION_SCRIPT = `on run(argv)
2932
+ set targetID to item 1 of argv
2933
+ tell application id "com.googlecode.iterm2"
2934
+ if not running then return "notrunning"
2935
+ repeat with w in windows
2936
+ repeat with t in tabs of w
2937
+ repeat with s in sessions of t
2938
+ if id of s is targetID then
2939
+ close s
2940
+ return "closed"
2941
+ end if
2942
+ end repeat
2943
+ end repeat
2944
+ end repeat
2945
+ end tell
2946
+ return "notfound"
2947
+ end run`;
2948
+ const realPaneOps = {
2949
+ async listIterm() {
2950
+ if (process.platform !== "darwin") return [];
2951
+ try {
2952
+ const p = await osascript(LIST_SESSIONS_SCRIPT, []);
2953
+ const cmdByTty = /* @__PURE__ */ new Map();
2954
+ for (const line of psOutput("tty=,command=").split("\n")) {
2955
+ const [tty, ...rest] = line.trim().split(/\s+/);
2956
+ if (tty && tty !== "??") cmdByTty.set(`/dev/${tty}`, rest.join(" "));
2957
+ }
2958
+ return p.stdout.split("\n").filter(Boolean).map((l) => {
2959
+ const [id, tty, ...name] = l.split(" ");
2960
+ return {
2961
+ id,
2962
+ name: `${name.join(" ")} ${cmdByTty.get(tty) ?? ""}`.trim()
2963
+ };
2964
+ });
2965
+ } catch {
2966
+ return [];
2967
+ }
2968
+ },
2969
+ async closeIterm(id) {
2970
+ return (await osascript(END_SESSION_SCRIPT, [id])).stdout.trim() === "closed";
2971
+ },
2972
+ listTmux() {
2973
+ try {
2974
+ return execFileSync("tmux", [
2975
+ "list-panes",
2976
+ "-a",
2977
+ "-F",
2978
+ "#{pane_id} #{pane_start_command}"
2979
+ ], {
2980
+ encoding: "utf8",
2981
+ stdio: [
2982
+ "ignore",
2983
+ "pipe",
2984
+ "ignore"
2985
+ ]
2986
+ }).split("\n").filter(Boolean).map((l) => ({
2987
+ id: l.split(" ")[0],
2988
+ command: l.split(" ").slice(1).join(" ")
2989
+ }));
2990
+ } catch {
2991
+ return [];
2992
+ }
2993
+ },
2994
+ closeTmux(id) {
2995
+ try {
2996
+ execFileSync("tmux", [
2997
+ "kill-pane",
2998
+ "-t",
2999
+ id
3000
+ ], { stdio: "ignore" });
3001
+ return true;
3002
+ } catch {
3003
+ return false;
3004
+ }
3005
+ }
3006
+ };
3007
+ const FOLLOW_ID = /worker[- ]follow (\d{8}-\d{6}-\d+)/;
3008
+ /**
3009
+ * Close every open follow pane whose worker has ended: registry entries first
3010
+ * (by worker id), then any iTerm session named after / tmux pane started with a
3011
+ * `worker follow <id>` command of an ended worker. `ended(id)` says whether
3012
+ * that worker is over; unknown ids are never closed. `dryRun` only reports.
3013
+ */
3014
+ async function closeEndedPanes(logDir, ended, dryRun, ops = realPaneOps) {
3015
+ const res = {
3016
+ closed: [],
3017
+ kept: []
3018
+ };
3019
+ const seen = /* @__PURE__ */ new Set();
3020
+ const handle = async (backend, id, worker, entry) => {
3021
+ const key = `${backend}:${id}`;
3022
+ if (seen.has(key)) return;
3023
+ seen.add(key);
3024
+ if (!ended(worker)) {
3025
+ res.kept.push(`${worker} ${key} (running)`);
3026
+ return;
3027
+ }
3028
+ if (!dryRun) {
3029
+ const ok = backend === "tmux" ? ops.closeTmux(id) : await ops.closeIterm(id).catch(() => false);
3030
+ if (entry) dropEntry(logDir, entry);
3031
+ if (!ok && !entry) return;
3032
+ }
3033
+ res.closed.push(`${worker} ${key}${dryRun ? " (dry run)" : ""}`);
3034
+ };
3035
+ const sessions = await ops.listIterm();
3036
+ const open = new Set(sessions.map((s) => s.id));
3037
+ for (const e of loadRegistry(logDir)) {
3038
+ if (sessions.length && !open.has(e.session)) {
3039
+ if (!dryRun) dropEntry(logDir, e);
3040
+ continue;
3041
+ }
3042
+ await handle("iterm", e.session, e.worker, e);
3043
+ }
3044
+ for (const s of sessions) {
3045
+ const m = FOLLOW_ID.exec(s.name);
3046
+ if (m) await handle("iterm", s.id, m[1]);
3047
+ }
3048
+ for (const t of ops.listTmux()) {
3049
+ const m = FOLLOW_ID.exec(t.command);
3050
+ if (m) await handle("tmux", t.id, m[1]);
3051
+ }
3052
+ return res;
3053
+ }
2477
3054
  /**
2478
3055
  * The command a worker pane runs: one exec-able line with no shell syntax —
2479
3056
  * iTerm's split command parameter execs without a shell (proven live: panes
@@ -2537,8 +3114,8 @@ async function openPaneForWorker(logDir, config, wid, term) {
2537
3114
  };
2538
3115
  }
2539
3116
  const uid = itermUuid(term);
2540
- const regPath = join(panesDir(logDir), `${scopeKey(term)}.json`);
2541
- const reg = loadRegistry(regPath);
3117
+ const scope = scopeKey(term);
3118
+ const reg = loadRegistry(logDir, scope);
2542
3119
  const profile = await followProfile(config.pane.fontSize);
2543
3120
  const cmd = followCommand(wid, config.pane.autoExitSecs);
2544
3121
  const p = await osascript(WORKER_SPLIT_SCRIPT, [
@@ -2552,13 +3129,13 @@ async function openPaneForWorker(logDir, config, wid, term) {
2552
3129
  const bar = out.indexOf("|");
2553
3130
  if (bar < 0) throw new Error(`pai worker pane: osascript failed: ${(p.stderr || out).slice(0, 200)}`);
2554
3131
  const live = new Set(out.slice(0, bar).split(",").filter(Boolean));
2555
- const pruned = reg.filter((e) => live.has(e.session));
2556
- pruned.push({
3132
+ for (const e of reg) if (!live.has(e.session)) dropEntry(logDir, e);
3133
+ saveEntry(logDir, {
2557
3134
  session: out.slice(bar + 1),
2558
3135
  worker: wid,
2559
- opened: (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19)
3136
+ opened: (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19),
3137
+ scope
2560
3138
  });
2561
- saveRegistry(regPath, pruned);
2562
3139
  return {
2563
3140
  message: `pane opened for ${wid}`,
2564
3141
  session: out.slice(bar + 1)
@@ -3895,7 +4472,7 @@ async function runWorker(opts) {
3895
4472
  if (gc?.length) process.stderr.write(`pai worker: archived ${gc.length} leftover worktree(s) (pai worker gc)\n`);
3896
4473
  } catch {}
3897
4474
  if (opts.className === "plan" && !opts._planner) {
3898
- const { runPlanner } = await import("./planner-Dm5Acyo1.mjs");
4475
+ const { runPlanner } = await import("./planner-D5yt0EfA.mjs");
3899
4476
  return runPlanner(opts);
3900
4477
  }
3901
4478
  const parent = launchParent(opts.parent);
@@ -5154,5 +5731,5 @@ function resultFromOutput(out) {
5154
5731
  }
5155
5732
 
5156
5733
  //#endregion
5157
- export { parseRunnerArgs as $, mergeWorker as A, contextPercent as B, resolveSession as C, discardWorker as D, workerInScope as E, ledgerSummary as F, loadStatuses as G, isChatPane as H, UNLABELED as I, ownsPid as J, newWorkerId as K, ageOf as L, verifyWorker as M, worktreesDir as N, gcWorktrees as O, appendLedger as P, longInlinePromptHint as Q, alive as R, itermUuid as S, sessionTag as T, isLive as U, elapsedOf as V, loadStatus as W, setWorkerLabel as X, saveStatus as Y, waitForTerminalStatus as Z, callerDescription as _, deadlineLabel as a, currentTabKey as b, handoffFromInside as c, workerDepth as d, shortText as et, checkPaneForWorker as f, markControlsHeld as g, clickrControlsArgv as h, usageContextTokens as i, expandMcpNames as it, uncommittedPaths as j, git as k, readInbox as l, openPaneForWorker as m, runWorker as n, projectLaunchConfig as nt, parseWorkerReport as o, openFollowPane as p, nowStamp as q, testProvider as r, describeMcp as rt, renderReport as s, printResult as t, pinNotices as tt, sayToWorker as u, endLabel as v, sessionMapPath as w, itermForClaudeSession as x, requestKill as y, contextLabel as z };
5158
- //# sourceMappingURL=run-BCpbxqA5.mjs.map
5734
+ export { longInlinePromptHint as $, git as A, contextLabel as B, itermUuid as C, workerInScope as D, sessionTag as E, appendLedger as F, loadStatus as G, elapsedOf as H, ledgerSummary as I, nowStamp as J, loadStatuses as K, UNLABELED as L, uncommittedPaths as M, verifyWorker as N, discardWorker as O, worktreesDir as P, waitForTerminalStatus as Q, ageOf as R, itermForClaudeSession as S, sessionMapPath as T, isChatPane as U, contextPercent as V, isLive as W, saveStatus as X, ownsPid as Y, setWorkerLabel as Z, markControlsHeld as _, expandMcpNames as _t, deadlineLabel as a, clearCooldown as at, requestKill as b, handoffFromInside as c, resolveTarget as ct, workerDepth as d, ledgerPath as dt, parseRunnerArgs as et, checkPaneForWorker as f, statusPath as ft, clickrControlsArgv as g, describeMcp as gt, openPaneForWorker as h, projectLaunchConfig as ht, usageContextTokens as i, stopProxy as it, mergeWorker as j, gcWorktrees as k, readInbox as l, ensureNoMcpConfig as lt, openFollowPane as m, pinNotices as mt, runWorker as n, DEFAULT_PROXY_PORT as nt, parseWorkerReport as o, probeQuota as ot, closeEndedPanes as p, workersLogDir as pt, newWorkerId as q, testProvider as r, ensureProxyRunning as rt, renderReport as s, quotaSkipThreshold as st, printResult as t, shortText as tt, sayToWorker as u, eventsPath as ut, callerDescription as v, resolveSession as w, currentTabKey as x, endLabel as y, alive as z };
5735
+ //# sourceMappingURL=run-CLYTOm0x.mjs.map