@tekmidian/pai 0.39.1 → 0.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/README.md +41 -0
  2. package/dist/{auto-route-BlWOWT4z.mjs → auto-route-BwzmlW3W.mjs} +2 -2
  3. package/dist/{auto-route-BlWOWT4z.mjs.map → auto-route-BwzmlW3W.mjs.map} +1 -1
  4. package/dist/{chain-CqlgL7uH.mjs → chain-DhVHVnmT.mjs} +263 -821
  5. package/dist/chain-DhVHVnmT.mjs.map +1 -0
  6. package/dist/cli/index.mjs +10 -8
  7. package/dist/cli/index.mjs.map +1 -1
  8. package/dist/cli/program.mjs +10 -8
  9. package/dist/{clusters-wlK0w41E.mjs → clusters-DRHhfli9.mjs} +1 -1
  10. package/dist/{clusters-wlK0w41E.mjs.map → clusters-DRHhfli9.mjs.map} +1 -1
  11. package/dist/{config-B64vFg14.mjs → config-D1G9IFpn.mjs} +50 -3
  12. package/dist/config-D1G9IFpn.mjs.map +1 -0
  13. package/dist/{config-C_ErGddD.mjs → config-DD52BPB-.mjs} +1 -1
  14. package/dist/config-Dl8lT4Lu.mjs +527 -0
  15. package/dist/config-Dl8lT4Lu.mjs.map +1 -0
  16. package/dist/{context-handover-cache-BpUojjsi.mjs → context-handover-cache-C6_rs7JT.mjs} +112 -24
  17. package/dist/context-handover-cache-C6_rs7JT.mjs.map +1 -0
  18. package/dist/daemon/index.mjs +12 -10
  19. package/dist/daemon/index.mjs.map +1 -1
  20. package/dist/daemon-BSL9sXxm.mjs +22 -0
  21. package/dist/{daemon-CTkN_Vn8.mjs → daemon-CpdVUnl_.mjs} +26 -26
  22. package/dist/{daemon-CTkN_Vn8.mjs.map → daemon-CpdVUnl_.mjs.map} +1 -1
  23. package/dist/daemon-mcp/index.mjs +76 -6
  24. package/dist/daemon-mcp/index.mjs.map +1 -1
  25. package/dist/detector-BLVOCiJ_.mjs +5 -0
  26. package/dist/{detector-Bwk_4Pk4.mjs → detector-smpCm7ku.mjs} +1 -1
  27. package/dist/{detector-Bwk_4Pk4.mjs.map → detector-smpCm7ku.mjs.map} +1 -1
  28. package/dist/{factory-A9x-T2Kg.mjs → factory-Bc5EyN54.mjs} +7 -7
  29. package/dist/{factory-A9x-T2Kg.mjs.map → factory-Bc5EyN54.mjs.map} +1 -1
  30. package/dist/factory-C7ua_3ik.mjs +3 -0
  31. package/dist/{fallback-DqYhiACU.mjs → fallback-CdXv-Np0.mjs} +139 -49
  32. package/dist/fallback-CdXv-Np0.mjs.map +1 -0
  33. package/dist/hooks/context-compression-hook.mjs +136 -22
  34. package/dist/hooks/context-compression-hook.mjs.map +4 -4
  35. package/dist/hooks/post-compact-inject.mjs +98 -7
  36. package/dist/hooks/post-compact-inject.mjs.map +4 -4
  37. package/dist/hooks/route-agents-to-worker.mjs +36 -2
  38. package/dist/hooks/route-agents-to-worker.mjs.map +2 -2
  39. package/dist/hooks/worker-proxy.mjs +36 -2
  40. package/dist/hooks/worker-proxy.mjs.map +2 -2
  41. package/dist/hooks/worker-status-line.mjs +110 -86
  42. package/dist/hooks/worker-status-line.mjs.map +4 -4
  43. package/dist/{indexer-backend-TG64CCQC.mjs → indexer-backend-rohVVKrA.mjs} +1 -1
  44. package/dist/{indexer-backend-TG64CCQC.mjs.map → indexer-backend-rohVVKrA.mjs.map} +1 -1
  45. package/dist/{ipc-client-BmypMNYk.mjs → ipc-client-C7AVpsyv.mjs} +2 -2
  46. package/dist/{ipc-client-BmypMNYk.mjs.map → ipc-client-C7AVpsyv.mjs.map} +1 -1
  47. package/dist/{kg-entity-r8duqhi9.mjs → kg-entity-DbOMPdF9.mjs} +1 -1
  48. package/dist/{kg-entity-r8duqhi9.mjs.map → kg-entity-DbOMPdF9.mjs.map} +1 -1
  49. package/dist/{latent-ideas-B7wq75Pt.mjs → latent-ideas-iNp5s55R.mjs} +2 -2
  50. package/dist/{latent-ideas-B7wq75Pt.mjs.map → latent-ideas-iNp5s55R.mjs.map} +1 -1
  51. package/dist/{link-boost-HkG7JWZR.mjs → link-boost-NNzADHX_.mjs} +1 -1
  52. package/dist/{link-boost-HkG7JWZR.mjs.map → link-boost-NNzADHX_.mjs.map} +1 -1
  53. package/dist/{main-resolver-DlaLOFBA.mjs → main-resolver-CM1IHbuu.mjs} +78 -75
  54. package/dist/main-resolver-CM1IHbuu.mjs.map +1 -0
  55. package/dist/main-resolver-E5WlilhM.mjs +6 -0
  56. package/dist/{neighborhood-lThN-MaQ.mjs → neighborhood-AGL7oXQ2.mjs} +1 -1
  57. package/dist/{neighborhood-lThN-MaQ.mjs.map → neighborhood-AGL7oXQ2.mjs.map} +1 -1
  58. package/dist/{note-context-b6k0mAKi.mjs → note-context-BHwYpSFf.mjs} +1 -1
  59. package/dist/{note-context-b6k0mAKi.mjs.map → note-context-BHwYpSFf.mjs.map} +1 -1
  60. package/dist/{planner-DGV8VFib.mjs → planner-Cm3g6fWH.mjs} +5 -3
  61. package/dist/{planner-DGV8VFib.mjs.map → planner-Cm3g6fWH.mjs.map} +1 -1
  62. package/dist/{postgres-mW1n7Vi1.mjs → postgres-Dwxe290H.mjs} +1 -1
  63. package/dist/{postgres-mW1n7Vi1.mjs.map → postgres-Dwxe290H.mjs.map} +1 -1
  64. package/dist/{program-B-QJXCRb.mjs → program-AR0qlYRg.mjs} +309 -78
  65. package/dist/program-AR0qlYRg.mjs.map +1 -0
  66. package/dist/query-feedback-CGcEiGtY.mjs +3 -0
  67. package/dist/{query-feedback-BV4CcxqS.mjs → query-feedback-DZfjI34w.mjs} +1 -1
  68. package/dist/{query-feedback-BV4CcxqS.mjs.map → query-feedback-DZfjI34w.mjs.map} +1 -1
  69. package/dist/router-CAtyVQud.mjs +3 -0
  70. package/dist/{router-DcHKnEPa.mjs → router-DHracTUC.mjs} +1 -1
  71. package/dist/{router-DcHKnEPa.mjs.map → router-DHracTUC.mjs.map} +1 -1
  72. package/dist/server-BOuAOj9b.mjs +386 -0
  73. package/dist/server-BOuAOj9b.mjs.map +1 -0
  74. package/dist/skills/Worker/SKILL.md +6 -1
  75. package/dist/{sources-kLnQsNrW.mjs → sources-ju6AA7lL.mjs} +1 -1
  76. package/dist/{sources-kLnQsNrW.mjs.map → sources-ju6AA7lL.mjs.map} +1 -1
  77. package/dist/{sqlite-BenGr3UP.mjs → sqlite-kFZeWCJ2.mjs} +1 -1
  78. package/dist/{sqlite-BenGr3UP.mjs.map → sqlite-kFZeWCJ2.mjs.map} +1 -1
  79. package/dist/{state-Ca9F_sZc.mjs → state-DH_mp5Xe.mjs} +1 -1
  80. package/dist/{state-CAeyOdfq.mjs → state-ahFAbD8b.mjs} +1 -1
  81. package/dist/{state-CAeyOdfq.mjs.map → state-ahFAbD8b.mjs.map} +1 -1
  82. package/dist/{themes-BI4GMRP9.mjs → themes-DqhNUUQk.mjs} +1 -1
  83. package/dist/{themes-BI4GMRP9.mjs.map → themes-DqhNUUQk.mjs.map} +1 -1
  84. package/dist/{tools-DGcB3o_S.mjs → tools-CMlHa9lZ.mjs} +14 -14
  85. package/dist/{tools-DGcB3o_S.mjs.map → tools-CMlHa9lZ.mjs.map} +1 -1
  86. package/dist/{tools-Bp7hj6OW.mjs → tools-COna9vZR.mjs} +1 -1
  87. package/dist/{trace-bobARFEX.mjs → trace-DTP6k4B_.mjs} +1 -1
  88. package/dist/{trace-bobARFEX.mjs.map → trace-DTP6k4B_.mjs.map} +1 -1
  89. package/dist/{vault-indexer-C3OfXTNF.mjs → vault-indexer-YMH22mLU.mjs} +1 -1
  90. package/dist/{vault-indexer-C3OfXTNF.mjs.map → vault-indexer-YMH22mLU.mjs.map} +1 -1
  91. package/dist/{work-queue-worker-R7UGIag_.mjs → work-queue-worker-B3nl8yyn.mjs} +23 -26
  92. package/dist/work-queue-worker-B3nl8yyn.mjs.map +1 -0
  93. package/dist/work-queue-worker-BM1GcAAq.mjs +14 -0
  94. package/dist/{zettelkasten-m5QPtb-L.mjs → zettelkasten-DDvKRm2V.mjs} +3 -3
  95. package/dist/{zettelkasten-m5QPtb-L.mjs.map → zettelkasten-DDvKRm2V.mjs.map} +1 -1
  96. package/docs/commands/README.md +4 -2
  97. package/docs/commands/worker.md +48 -5
  98. package/docs/images/provider-abstraction-live.png +0 -0
  99. package/docs/images/workers.png +0 -0
  100. package/docs/launcher-independence.md +70 -0
  101. package/docs/provider-abstraction.md +87 -0
  102. package/docs/provider-independence-details.md +330 -0
  103. package/docs/provider-independence.md +75 -0
  104. package/docs/worker.md +29 -11
  105. package/package.json +1 -1
  106. package/scripts/build-hooks.mjs +6 -1
  107. package/scripts/build-skill-stubs.mjs +17 -4
  108. package/src/hooks/ts/lib/context-fill.test.ts +158 -4
  109. package/src/hooks/ts/lib/context-fill.ts +102 -35
  110. package/statusline-command.sh +120 -21
  111. package/dist/chain-CqlgL7uH.mjs.map +0 -1
  112. package/dist/config-B64vFg14.mjs.map +0 -1
  113. package/dist/context-handover-cache-BpUojjsi.mjs.map +0 -1
  114. package/dist/daemon-CmHHmKpg.mjs +0 -20
  115. package/dist/detector-DO730Zq0.mjs +0 -5
  116. package/dist/factory-BD-np0Vd.mjs +0 -3
  117. package/dist/fallback-DqYhiACU.mjs.map +0 -1
  118. package/dist/main-resolver-D6IImXvF.mjs +0 -4
  119. package/dist/main-resolver-DlaLOFBA.mjs.map +0 -1
  120. package/dist/program-B-QJXCRb.mjs.map +0 -1
  121. package/dist/query-feedback-DSVyHtrG.mjs +0 -3
  122. package/dist/router-Bk77E7hj.mjs +0 -3
  123. package/dist/runtime-paths-rni52zHX.mjs +0 -50
  124. package/dist/runtime-paths-rni52zHX.mjs.map +0 -1
  125. package/dist/work-queue-worker-DW8lz-Oo.mjs +0 -11
  126. package/dist/work-queue-worker-R7UGIag_.mjs.map +0 -1
@@ -131,6 +131,7 @@ var CONFIG_DIR = join(homedir(), ".config", "pai");
131
131
  var CONFIG_FILE = join(CONFIG_DIR, "config.json");
132
132
 
133
133
  // src/workers/config.ts
134
+ var MODEL_TIERS = ["haiku", "sonnet", "opus"];
134
135
  var PROVIDER_TAGS = [
135
136
  "code",
136
137
  "vision",
@@ -139,6 +140,10 @@ var PROVIDER_TAGS = [
139
140
  "fast",
140
141
  "reasoning"
141
142
  ];
143
+ var MODEL_CAPABILITIES = ["default", "fast", "image"];
144
+ function isModelCapability(v) {
145
+ return MODEL_CAPABILITIES.includes(v);
146
+ }
142
147
  var DEFAULT_LOG_DIR = "~/.claude/logs/workers";
143
148
  var DEFAULT_PANE = {
144
149
  enabled: true,
@@ -200,7 +205,35 @@ function parseProvider(name, raw) {
200
205
  const m = modelsRaw;
201
206
  const defaultModel = str(m.default);
202
207
  if (!defaultModel) bad(`.providers.${name}.models.default`, "is required");
203
- const fast = m.fast === void 0 ? void 0 : str(m.fast);
208
+ const models = { default: defaultModel };
209
+ for (const key of Object.keys(m)) {
210
+ if (key === "default") continue;
211
+ if (!isModelCapability(key)) {
212
+ bad(
213
+ `.providers.${name}.models.${key}`,
214
+ `"${key}" is not a model capability (from: ${MODEL_CAPABILITIES.join(", ")})`
215
+ );
216
+ }
217
+ const id = str(m[key]);
218
+ if (!id) bad(`.providers.${name}.models.${key}`, "must be a non-empty model id");
219
+ models[key] = id;
220
+ }
221
+ let modelTiers;
222
+ if (p.modelTiers !== void 0) {
223
+ if (typeof p.modelTiers !== "object" || p.modelTiers === null || Array.isArray(p.modelTiers)) {
224
+ bad(`.providers.${name}.modelTiers`, "must be an object of model id \u2192 haiku | sonnet | opus");
225
+ }
226
+ modelTiers = {};
227
+ for (const [id, tier] of Object.entries(p.modelTiers)) {
228
+ if (typeof tier !== "string" || !MODEL_TIERS.includes(tier)) {
229
+ bad(
230
+ `.providers.${name}.modelTiers.${id}`,
231
+ `must be "haiku", "sonnet" or "opus" (got ${JSON.stringify(tier)})`
232
+ );
233
+ }
234
+ modelTiers[id] = tier;
235
+ }
236
+ }
204
237
  const env = {};
205
238
  if (p.env !== void 0) {
206
239
  if (typeof p.env !== "object" || p.env === null || Array.isArray(p.env)) {
@@ -250,7 +283,8 @@ function parseProvider(name, raw) {
250
283
  protocol,
251
284
  baseUrl,
252
285
  keyFile,
253
- models: fast ? { default: defaultModel, fast } : { default: defaultModel },
286
+ models,
287
+ ...modelTiers ? { modelTiers } : {},
254
288
  env,
255
289
  ...str(p.note) ? { note: str(p.note) } : {},
256
290
  ...upstreamUrl ? { upstreamUrl } : {},
@@ -474,13 +508,23 @@ function workersLogDir(config) {
474
508
  return expandHome(config.logDir);
475
509
  }
476
510
 
511
+ // src/workers/scope.ts
512
+ import { existsSync as existsSync3, readFileSync as readFileSync3, renameSync as renameSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync2 } from "node:fs";
513
+ import { homedir as homedir3 } from "node:os";
514
+ import { join as join4 } from "node:path";
515
+
477
516
  // src/workers/status.ts
478
517
  import { existsSync as existsSync2, readFileSync as readFileSync2, renameSync as renameSync2, writeFileSync as writeFileSync2, readdirSync } from "node:fs";
479
518
  import { join as join3 } from "node:path";
480
- function contextPercent(s) {
481
- if (!s.contextTokens || !s.contextWindow) return null;
482
- return Math.round(s.contextTokens / s.contextWindow * 100);
519
+
520
+ // src/workers/args.ts
521
+ function shortText(s, n) {
522
+ const t = String(s ?? "").split(/\s+/).filter(Boolean).join(" ");
523
+ return t.length <= n ? t : t.slice(0, n - 1) + "\u2026";
483
524
  }
525
+
526
+ // src/workers/status.ts
527
+ var UNLABELED = "unlabeled";
484
528
  function loadStatuses(logDir) {
485
529
  if (!existsSync2(logDir)) return [];
486
530
  const out = [];
@@ -510,8 +554,6 @@ function ageOf(ts, now = /* @__PURE__ */ new Date()) {
510
554
  }
511
555
 
512
556
  // src/workers/scope.ts
513
- import { homedir as homedir3 } from "node:os";
514
- import { join as join4 } from "node:path";
515
557
  var AIBROKER_REGISTRY = join4(homedir3(), ".aibroker", "session-names.json");
516
558
  function tabKey(term2) {
517
559
  if (!term2) return "";
@@ -532,41 +574,36 @@ function workerInScope(worker, term2) {
532
574
  if (worker.session?.id && uuid) return worker.session.id === uuid;
533
575
  return tabKey(worker.term) === tabKey(term2) && tabKey(term2) !== "";
534
576
  }
535
-
536
- // src/workers/handoff.ts
537
- import { appendFileSync, existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3 } from "node:fs";
538
- import { dirname, join as join5 } from "node:path";
539
- function inboxPath(logDir, id) {
540
- return join5(logDir, `${id}.inbox.jsonl`);
577
+ var SPAWNER_SESSION_TTL_MS = 10 * 6e4;
578
+ var SESSION_MAP_PRUNE_MS = 60 * 6e4;
579
+ function sessionMapPath(logDir) {
580
+ return join4(logDir, "claude-session-map.json");
541
581
  }
542
- function readInbox(logDir, id) {
543
- const path = inboxPath(logDir, id);
544
- if (!existsSync3(path)) return [];
545
- const out = [];
546
- for (const line of readFileSync3(path, "utf8").split("\n")) {
547
- if (!line.trim()) continue;
548
- try {
549
- out.push(JSON.parse(line));
550
- } catch {
582
+ function recordSessionMapEntry(logDir, cwd2, session, now = Date.now()) {
583
+ if (!cwd2 || !session) return;
584
+ const path = sessionMapPath(logDir);
585
+ let map = {};
586
+ try {
587
+ if (existsSync3(path)) {
588
+ map = JSON.parse(readFileSync3(path, "utf8"));
551
589
  }
590
+ } catch {
591
+ map = {};
592
+ }
593
+ const prev = map[cwd2];
594
+ if (prev && prev.session === session && now - prev.ts < 6e4) return;
595
+ const pruned = {};
596
+ for (const [dir, e] of Object.entries(map)) {
597
+ if (now - e.ts < SESSION_MAP_PRUNE_MS) pruned[dir] = e;
598
+ }
599
+ pruned[cwd2] = { session, ts: now };
600
+ try {
601
+ mkdirSync2(logDir, { recursive: true });
602
+ const tmp = `${path}.tmp`;
603
+ writeFileSync3(tmp, JSON.stringify(pruned), "utf8");
604
+ renameSync3(tmp, path);
605
+ } catch {
552
606
  }
553
- return out;
554
- }
555
-
556
- // src/workers/tree.ts
557
- function workerDepth(statuses, id) {
558
- const byId = new Map(statuses.map((s) => [s.id, s]));
559
- let depth = 0;
560
- let cur = byId.get(id);
561
- const seen = /* @__PURE__ */ new Set([id]);
562
- while (cur?.parent && !seen.has(cur.parent)) {
563
- seen.add(cur.parent);
564
- const next = byId.get(cur.parent);
565
- if (!next) break;
566
- depth += 1;
567
- cur = next;
568
- }
569
- return depth;
570
607
  }
571
608
 
572
609
  // src/workers/report.ts
@@ -579,6 +616,8 @@ var WORKER_CONTRACT_PROMPT = [
579
616
  "changed: files you touched (path + one-line summary). commands: the commands that verify the work.",
580
617
  "checks: each with ok true/false and the evidence in detail. open: what you could not finish, if anything.",
581
618
  "notes: one line, the headline a reviewer reads first.",
619
+ "Never write shell heredocs \u2014 write the script to a file with the Write tool, then run it",
620
+ "(heredocs fail silently or get swallowed).",
582
621
  "",
583
622
  `Operator messages: a user turn starting with ${OPERATOR_MARK} was typed by the operator while you`,
584
623
  "run (the prompt of a resumed run is the operator's too). Answer it FIRST, in one or two plain lines \u2014",
@@ -595,76 +634,61 @@ var WORKER_CONTRACT_PROMPT = [
595
634
  ].join("\n");
596
635
 
597
636
  // src/workers/render.ts
598
- var CODES = {
599
- dim: "2",
600
- bold: "1",
601
- red: "31",
602
- green: "32",
603
- yellow: "33",
604
- blue: "34",
605
- mag: "35",
606
- cyan: "36"
607
- };
608
- function makeColor(enabled) {
609
- return (name, s) => enabled ? `\x1B[${CODES[name]}m${s}\x1B[0m` : s;
610
- }
611
- function fmtK(n) {
612
- return n >= 1e3 ? `${Math.round(n / 1e3)}k` : String(n);
613
- }
614
- function contextMeter(c, s, minPct = 0) {
615
- const pct = contextPercent(s);
616
- if (pct === null || pct <= minPct) return null;
617
- const label = `ctx ${fmtK(s.contextTokens ?? 0)}/${fmtK(s.contextWindow ?? 0)} (${pct}%)`;
618
- if (pct > 85) return c("red", label);
619
- if (pct > 70) return c("yellow", label);
620
- return label;
637
+ function stepOf(last) {
638
+ const s = String(last ?? "").trim();
639
+ if (s.startsWith("Bash: ")) {
640
+ const cmd = s.slice(6).trim();
641
+ const verb = cmd.split(/\s+/)[0] ?? "";
642
+ return shortText(cmd.length > verb.length ? `${verb} \u2026` : verb, 24);
643
+ }
644
+ return shortText(s, 24);
621
645
  }
622
- function renderStatusLine(mine, now = /* @__PURE__ */ new Date(), c = makeColor(true), all = mine, inbox = {}) {
646
+ function renderStatusLine(mine, now = /* @__PURE__ */ new Date()) {
623
647
  if (!mine.length) return "";
624
- const running = mine.filter((s) => s.state === "running" && alive(s.pid)).sort((a, b) => workerDepth(all, a.id) - workerDepth(all, b.id));
648
+ const isChat = (s) => s.origin === "chat" || !s.origin && (s.label === UNLABELED || s.label === "(no prompt)") && s.turns === 0;
649
+ const chat = mine.find((s) => isChat(s) && s.state === "running" && alive(s.pid));
650
+ const running = mine.filter((s) => !isChat(s) && s.state === "running" && alive(s.pid)).sort((a, b) => a.started.localeCompare(b.started));
625
651
  const today = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`;
626
652
  const doneToday = mine.filter((s) => s.state !== "running" && s.started.startsWith(today));
627
653
  const ok = doneToday.filter((s) => s.state === "done").length;
628
654
  const bad2 = doneToday.length - ok;
629
- const providers = new Set(running.map((s) => s.provider));
630
- const providerTag = providers.size === 1 ? [...providers][0] : "workers";
631
- let head = `${providerTag} \u25B6${running.length}`;
632
- const parts = running.slice(0, 3).map((s) => {
633
- const meter = contextMeter(c, s, 60);
634
- const depth = workerDepth(all, s.id);
635
- const lead = depth > 0 ? " ".repeat(depth - 1) + "\u21B3 " : "";
636
- const box = inbox[s.id] ? ` \u25C6${inbox[s.id]}` : "";
637
- return `${lead}${s.id.slice(-4)} ${s.label.slice(0, 26)} ${ageOf(s.started, now)} \xB7 ${s.last.slice(0, 30)}${box}` + (meter ? ` ${meter}` : "");
655
+ const rows = running.slice(0, 3).map((s) => {
656
+ const twin = running.some((o) => o !== s && o.label === s.label);
657
+ const name = `${twin ? `#${s.id.slice(-4)} ` : ""}${s.label.slice(0, 26)}`;
658
+ return `${name} \xB7 ${ageOf(s.started, now)} \xB7 ${stepOf(s.last)}`;
638
659
  });
639
- if (parts.length) head += " " + parts.join(" | ");
660
+ let head;
661
+ if (chat) head = chat.provider;
662
+ else {
663
+ const providers = new Set(running.map((s) => s.provider));
664
+ head = providers.size === 1 ? [...providers][0] : "workers";
665
+ }
666
+ if (running.length) head += ` \u25B6${running.length}`;
667
+ if (rows.length) head += " | " + rows.join(" | ");
640
668
  if (doneToday.length) head += ` \u2713${ok} \u2717${bad2} today`;
641
669
  return head;
642
670
  }
643
671
 
644
672
  // src/workers/viewer.ts
645
- function inboxCounts(logDir, statuses) {
646
- const out = {};
647
- for (const s of statuses) {
648
- const n = readInbox(logDir, s.id).length;
649
- if (n) out[s.id] = n;
650
- }
651
- return out;
652
- }
653
- function statusLineOutput(logDir, term2, cwd2, now = /* @__PURE__ */ new Date()) {
673
+ function statusLineOutput(logDir, term2, cwd2, claudeSession2 = "", now = /* @__PURE__ */ new Date()) {
654
674
  const statuses = loadStatuses(logDir);
655
675
  const mine = statuses.filter((s) => {
656
676
  const sameScope = term2 && workerInScope(s, term2);
677
+ const spawnedHere = claudeSession2 && s.spawnerSession === claudeSession2;
657
678
  const sameDir = cwd2 && s.cwd.startsWith(cwd2);
658
- return sameScope || !term2 && sameDir;
679
+ return sameScope || spawnedHere || !term2 && sameDir;
659
680
  });
660
- return renderStatusLine(mine, now, makeColor(false), statuses, inboxCounts(logDir, mine));
681
+ return renderStatusLine(mine, now);
661
682
  }
662
683
 
663
684
  // src/workers/standalone/status-line.ts
664
685
  var term = process.argv[2] ?? process.env.ITERM_SESSION_ID ?? "";
665
686
  var cwd = process.argv[3] ?? process.cwd();
687
+ var claudeSession = process.argv[4] ?? "";
666
688
  try {
667
- const out = statusLineOutput(workersLogDir(readWorkersSection().workers), term, cwd);
689
+ const logDir = workersLogDir(readWorkersSection().workers);
690
+ if (claudeSession) recordSessionMapEntry(logDir, cwd, claudeSession);
691
+ const out = statusLineOutput(logDir, term, cwd, claudeSession);
668
692
  if (out) process.stdout.write(out + "\n");
669
693
  } catch {
670
694
  }