@tekmidian/pai 0.39.0 → 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.
- package/README.md +41 -0
- package/dist/{auto-route-BlWOWT4z.mjs → auto-route-BwzmlW3W.mjs} +2 -2
- package/dist/{auto-route-BlWOWT4z.mjs.map → auto-route-BwzmlW3W.mjs.map} +1 -1
- package/dist/{chain-CTtHligI.mjs → chain-DhVHVnmT.mjs} +263 -791
- package/dist/chain-DhVHVnmT.mjs.map +1 -0
- package/dist/cli/index.mjs +10 -8
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli/program.mjs +10 -8
- package/dist/{clusters-wlK0w41E.mjs → clusters-DRHhfli9.mjs} +1 -1
- package/dist/{clusters-wlK0w41E.mjs.map → clusters-DRHhfli9.mjs.map} +1 -1
- package/dist/{config-B64vFg14.mjs → config-D1G9IFpn.mjs} +50 -3
- package/dist/config-D1G9IFpn.mjs.map +1 -0
- package/dist/{config-C_ErGddD.mjs → config-DD52BPB-.mjs} +1 -1
- package/dist/config-Dl8lT4Lu.mjs +527 -0
- package/dist/config-Dl8lT4Lu.mjs.map +1 -0
- package/dist/{context-handover-cache-BpUojjsi.mjs → context-handover-cache-C6_rs7JT.mjs} +112 -24
- package/dist/context-handover-cache-C6_rs7JT.mjs.map +1 -0
- package/dist/daemon/index.mjs +12 -10
- package/dist/daemon/index.mjs.map +1 -1
- package/dist/daemon-BSL9sXxm.mjs +22 -0
- package/dist/{daemon-CTkN_Vn8.mjs → daemon-CpdVUnl_.mjs} +26 -26
- package/dist/{daemon-CTkN_Vn8.mjs.map → daemon-CpdVUnl_.mjs.map} +1 -1
- package/dist/daemon-mcp/index.mjs +127 -6
- package/dist/daemon-mcp/index.mjs.map +1 -1
- package/dist/detector-BLVOCiJ_.mjs +5 -0
- package/dist/{detector-Bwk_4Pk4.mjs → detector-smpCm7ku.mjs} +1 -1
- package/dist/{detector-Bwk_4Pk4.mjs.map → detector-smpCm7ku.mjs.map} +1 -1
- package/dist/{factory-A9x-T2Kg.mjs → factory-Bc5EyN54.mjs} +7 -7
- package/dist/{factory-A9x-T2Kg.mjs.map → factory-Bc5EyN54.mjs.map} +1 -1
- package/dist/factory-C7ua_3ik.mjs +3 -0
- package/dist/{providers-FYkZjn_C.mjs → fallback-CdXv-Np0.mjs} +411 -51
- package/dist/fallback-CdXv-Np0.mjs.map +1 -0
- package/dist/hooks/context-compression-hook.mjs +136 -22
- package/dist/hooks/context-compression-hook.mjs.map +4 -4
- package/dist/hooks/post-compact-inject.mjs +98 -7
- package/dist/hooks/post-compact-inject.mjs.map +4 -4
- package/dist/hooks/route-agents-to-worker.mjs +75 -6
- package/dist/hooks/route-agents-to-worker.mjs.map +2 -2
- package/dist/hooks/worker-proxy.mjs +75 -6
- package/dist/hooks/worker-proxy.mjs.map +2 -2
- package/dist/hooks/worker-status-line.mjs +149 -90
- package/dist/hooks/worker-status-line.mjs.map +4 -4
- package/dist/{indexer-backend-TG64CCQC.mjs → indexer-backend-rohVVKrA.mjs} +1 -1
- package/dist/{indexer-backend-TG64CCQC.mjs.map → indexer-backend-rohVVKrA.mjs.map} +1 -1
- package/dist/{ipc-client-BmypMNYk.mjs → ipc-client-C7AVpsyv.mjs} +2 -2
- package/dist/{ipc-client-BmypMNYk.mjs.map → ipc-client-C7AVpsyv.mjs.map} +1 -1
- package/dist/{kg-entity-r8duqhi9.mjs → kg-entity-DbOMPdF9.mjs} +1 -1
- package/dist/{kg-entity-r8duqhi9.mjs.map → kg-entity-DbOMPdF9.mjs.map} +1 -1
- package/dist/{latent-ideas-B7wq75Pt.mjs → latent-ideas-iNp5s55R.mjs} +2 -2
- package/dist/{latent-ideas-B7wq75Pt.mjs.map → latent-ideas-iNp5s55R.mjs.map} +1 -1
- package/dist/{link-boost-HkG7JWZR.mjs → link-boost-NNzADHX_.mjs} +1 -1
- package/dist/{link-boost-HkG7JWZR.mjs.map → link-boost-NNzADHX_.mjs.map} +1 -1
- package/dist/{main-resolver-DlaLOFBA.mjs → main-resolver-CM1IHbuu.mjs} +78 -75
- package/dist/main-resolver-CM1IHbuu.mjs.map +1 -0
- package/dist/main-resolver-E5WlilhM.mjs +6 -0
- package/dist/{neighborhood-lThN-MaQ.mjs → neighborhood-AGL7oXQ2.mjs} +1 -1
- package/dist/{neighborhood-lThN-MaQ.mjs.map → neighborhood-AGL7oXQ2.mjs.map} +1 -1
- package/dist/{note-context-b6k0mAKi.mjs → note-context-BHwYpSFf.mjs} +1 -1
- package/dist/{note-context-b6k0mAKi.mjs.map → note-context-BHwYpSFf.mjs.map} +1 -1
- package/dist/{planner-BDI7bE9B.mjs → planner-Cm3g6fWH.mjs} +5 -3
- package/dist/{planner-BDI7bE9B.mjs.map → planner-Cm3g6fWH.mjs.map} +1 -1
- package/dist/{postgres-mW1n7Vi1.mjs → postgres-Dwxe290H.mjs} +1 -1
- package/dist/{postgres-mW1n7Vi1.mjs.map → postgres-Dwxe290H.mjs.map} +1 -1
- package/dist/{program-DXBwJV7h.mjs → program-AR0qlYRg.mjs} +334 -78
- package/dist/program-AR0qlYRg.mjs.map +1 -0
- package/dist/query-feedback-CGcEiGtY.mjs +3 -0
- package/dist/{query-feedback-BV4CcxqS.mjs → query-feedback-DZfjI34w.mjs} +1 -1
- package/dist/{query-feedback-BV4CcxqS.mjs.map → query-feedback-DZfjI34w.mjs.map} +1 -1
- package/dist/router-CAtyVQud.mjs +3 -0
- package/dist/{router-DcHKnEPa.mjs → router-DHracTUC.mjs} +1 -1
- package/dist/{router-DcHKnEPa.mjs.map → router-DHracTUC.mjs.map} +1 -1
- package/dist/server-BOuAOj9b.mjs +386 -0
- package/dist/server-BOuAOj9b.mjs.map +1 -0
- package/dist/skills/Worker/SKILL.md +19 -1
- package/dist/{sources-kLnQsNrW.mjs → sources-ju6AA7lL.mjs} +1 -1
- package/dist/{sources-kLnQsNrW.mjs.map → sources-ju6AA7lL.mjs.map} +1 -1
- package/dist/{sqlite-BenGr3UP.mjs → sqlite-kFZeWCJ2.mjs} +1 -1
- package/dist/{sqlite-BenGr3UP.mjs.map → sqlite-kFZeWCJ2.mjs.map} +1 -1
- package/dist/{state-Ca9F_sZc.mjs → state-DH_mp5Xe.mjs} +1 -1
- package/dist/{state-CAeyOdfq.mjs → state-ahFAbD8b.mjs} +1 -1
- package/dist/{state-CAeyOdfq.mjs.map → state-ahFAbD8b.mjs.map} +1 -1
- package/dist/{themes-BI4GMRP9.mjs → themes-DqhNUUQk.mjs} +1 -1
- package/dist/{themes-BI4GMRP9.mjs.map → themes-DqhNUUQk.mjs.map} +1 -1
- package/dist/{tools-DGcB3o_S.mjs → tools-CMlHa9lZ.mjs} +14 -14
- package/dist/{tools-DGcB3o_S.mjs.map → tools-CMlHa9lZ.mjs.map} +1 -1
- package/dist/{tools-Bp7hj6OW.mjs → tools-COna9vZR.mjs} +1 -1
- package/dist/{trace-bobARFEX.mjs → trace-DTP6k4B_.mjs} +1 -1
- package/dist/{trace-bobARFEX.mjs.map → trace-DTP6k4B_.mjs.map} +1 -1
- package/dist/{vault-indexer-C3OfXTNF.mjs → vault-indexer-YMH22mLU.mjs} +1 -1
- package/dist/{vault-indexer-C3OfXTNF.mjs.map → vault-indexer-YMH22mLU.mjs.map} +1 -1
- package/dist/{work-queue-worker-R7UGIag_.mjs → work-queue-worker-B3nl8yyn.mjs} +23 -26
- package/dist/work-queue-worker-B3nl8yyn.mjs.map +1 -0
- package/dist/work-queue-worker-BM1GcAAq.mjs +14 -0
- package/dist/{zettelkasten-m5QPtb-L.mjs → zettelkasten-DDvKRm2V.mjs} +3 -3
- package/dist/{zettelkasten-m5QPtb-L.mjs.map → zettelkasten-DDvKRm2V.mjs.map} +1 -1
- package/docs/commands/README.md +5 -2
- package/docs/commands/worker.md +66 -5
- package/docs/images/provider-abstraction-live.png +0 -0
- package/docs/images/workers.png +0 -0
- package/docs/launcher-independence.md +70 -0
- package/docs/provider-abstraction.md +87 -0
- package/docs/provider-independence-details.md +330 -0
- package/docs/provider-independence.md +75 -0
- package/docs/worker.md +72 -11
- package/package.json +1 -1
- package/scripts/build-hooks.mjs +6 -1
- package/scripts/build-skill-stubs.mjs +17 -4
- package/src/hooks/ts/lib/context-fill.test.ts +158 -4
- package/src/hooks/ts/lib/context-fill.ts +102 -35
- package/statusline-command.sh +120 -21
- package/dist/chain-CTtHligI.mjs.map +0 -1
- package/dist/config-B64vFg14.mjs.map +0 -1
- package/dist/context-handover-cache-BpUojjsi.mjs.map +0 -1
- package/dist/daemon-CmHHmKpg.mjs +0 -20
- package/dist/detector-DO730Zq0.mjs +0 -5
- package/dist/factory-BD-np0Vd.mjs +0 -3
- package/dist/main-resolver-D6IImXvF.mjs +0 -4
- package/dist/main-resolver-DlaLOFBA.mjs.map +0 -1
- package/dist/program-DXBwJV7h.mjs.map +0 -1
- package/dist/providers-FYkZjn_C.mjs.map +0 -1
- package/dist/query-feedback-DSVyHtrG.mjs +0 -3
- package/dist/router-Bk77E7hj.mjs +0 -3
- package/dist/runtime-paths-rni52zHX.mjs +0 -50
- package/dist/runtime-paths-rni52zHX.mjs.map +0 -1
- package/dist/work-queue-worker-DW8lz-Oo.mjs +0 -11
- 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,
|
|
@@ -167,7 +172,8 @@ function defaultWorkersConfig() {
|
|
|
167
172
|
pane: { ...DEFAULT_PANE },
|
|
168
173
|
logDir: DEFAULT_LOG_DIR,
|
|
169
174
|
routing: { ...DEFAULT_ROUTING2, order: [] },
|
|
170
|
-
tree: { ...DEFAULT_TREE }
|
|
175
|
+
tree: { ...DEFAULT_TREE },
|
|
176
|
+
fallback: null
|
|
171
177
|
};
|
|
172
178
|
}
|
|
173
179
|
var WorkersConfigError = class extends Error {
|
|
@@ -199,7 +205,35 @@ function parseProvider(name, raw) {
|
|
|
199
205
|
const m = modelsRaw;
|
|
200
206
|
const defaultModel = str(m.default);
|
|
201
207
|
if (!defaultModel) bad(`.providers.${name}.models.default`, "is required");
|
|
202
|
-
const
|
|
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
|
+
}
|
|
203
237
|
const env = {};
|
|
204
238
|
if (p.env !== void 0) {
|
|
205
239
|
if (typeof p.env !== "object" || p.env === null || Array.isArray(p.env)) {
|
|
@@ -249,7 +283,8 @@ function parseProvider(name, raw) {
|
|
|
249
283
|
protocol,
|
|
250
284
|
baseUrl,
|
|
251
285
|
keyFile,
|
|
252
|
-
models
|
|
286
|
+
models,
|
|
287
|
+
...modelTiers ? { modelTiers } : {},
|
|
253
288
|
env,
|
|
254
289
|
...str(p.note) ? { note: str(p.note) } : {},
|
|
255
290
|
...upstreamUrl ? { upstreamUrl } : {},
|
|
@@ -413,6 +448,39 @@ function parseWorkersConfig(raw) {
|
|
|
413
448
|
const active = w.active === void 0 || w.active === null ? null : str(w.active);
|
|
414
449
|
if (active !== null && active !== "auto" && !(active in providers)) {
|
|
415
450
|
}
|
|
451
|
+
let fallback = null;
|
|
452
|
+
if (w.fallback !== void 0 && w.fallback !== null) {
|
|
453
|
+
if (typeof w.fallback !== "object" || Array.isArray(w.fallback)) {
|
|
454
|
+
bad(".fallback", "must be an object (written by `pai worker fallback on`)");
|
|
455
|
+
}
|
|
456
|
+
const f = w.fallback;
|
|
457
|
+
const provider = str(f.provider);
|
|
458
|
+
if (!provider) bad(".fallback.provider", "is required");
|
|
459
|
+
const savedRaw = f.saved;
|
|
460
|
+
if (typeof savedRaw !== "object" || savedRaw === null || Array.isArray(savedRaw)) {
|
|
461
|
+
bad(".fallback.saved", "must be an object");
|
|
462
|
+
}
|
|
463
|
+
const s = savedRaw;
|
|
464
|
+
if (typeof s.env !== "object" || s.env === null || Array.isArray(s.env)) {
|
|
465
|
+
bad(".fallback.saved.env", "must be an object of env key \u2192 previous value or null");
|
|
466
|
+
}
|
|
467
|
+
const env = {};
|
|
468
|
+
for (const [k, v] of Object.entries(s.env)) {
|
|
469
|
+
env[k] = v === null || typeof v === "string" ? v : null;
|
|
470
|
+
}
|
|
471
|
+
if (s.model !== null && s.model !== void 0 && typeof s.model !== "string") {
|
|
472
|
+
bad(".fallback.saved.model", "must be a string or null");
|
|
473
|
+
}
|
|
474
|
+
fallback = {
|
|
475
|
+
provider,
|
|
476
|
+
saved: {
|
|
477
|
+
env,
|
|
478
|
+
model: typeof s.model === "string" ? s.model : null,
|
|
479
|
+
envExisted: s.envExisted === true
|
|
480
|
+
},
|
|
481
|
+
on: str(f.on) || (/* @__PURE__ */ new Date(0)).toISOString()
|
|
482
|
+
};
|
|
483
|
+
}
|
|
416
484
|
return {
|
|
417
485
|
enabled: w.enabled === void 0 ? d.enabled : w.enabled === true,
|
|
418
486
|
active,
|
|
@@ -422,11 +490,12 @@ function parseWorkersConfig(raw) {
|
|
|
422
490
|
pane,
|
|
423
491
|
logDir: str(w.logDir) || d.logDir,
|
|
424
492
|
routing,
|
|
425
|
-
tree
|
|
493
|
+
tree,
|
|
494
|
+
fallback
|
|
426
495
|
};
|
|
427
496
|
}
|
|
428
|
-
function readWorkersSection() {
|
|
429
|
-
const raw = readJsonStrict(
|
|
497
|
+
function readWorkersSection(path = CONFIG_FILE) {
|
|
498
|
+
const raw = readJsonStrict(path, "~/.config/pai/config.json");
|
|
430
499
|
return { raw, workers: parseWorkersConfig(raw.workers) };
|
|
431
500
|
}
|
|
432
501
|
function expandHome(p) {
|
|
@@ -439,13 +508,23 @@ function workersLogDir(config) {
|
|
|
439
508
|
return expandHome(config.logDir);
|
|
440
509
|
}
|
|
441
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
|
+
|
|
442
516
|
// src/workers/status.ts
|
|
443
517
|
import { existsSync as existsSync2, readFileSync as readFileSync2, renameSync as renameSync2, writeFileSync as writeFileSync2, readdirSync } from "node:fs";
|
|
444
518
|
import { join as join3 } from "node:path";
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
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";
|
|
448
524
|
}
|
|
525
|
+
|
|
526
|
+
// src/workers/status.ts
|
|
527
|
+
var UNLABELED = "unlabeled";
|
|
449
528
|
function loadStatuses(logDir) {
|
|
450
529
|
if (!existsSync2(logDir)) return [];
|
|
451
530
|
const out = [];
|
|
@@ -475,8 +554,6 @@ function ageOf(ts, now = /* @__PURE__ */ new Date()) {
|
|
|
475
554
|
}
|
|
476
555
|
|
|
477
556
|
// src/workers/scope.ts
|
|
478
|
-
import { homedir as homedir3 } from "node:os";
|
|
479
|
-
import { join as join4 } from "node:path";
|
|
480
557
|
var AIBROKER_REGISTRY = join4(homedir3(), ".aibroker", "session-names.json");
|
|
481
558
|
function tabKey(term2) {
|
|
482
559
|
if (!term2) return "";
|
|
@@ -497,41 +574,36 @@ function workerInScope(worker, term2) {
|
|
|
497
574
|
if (worker.session?.id && uuid) return worker.session.id === uuid;
|
|
498
575
|
return tabKey(worker.term) === tabKey(term2) && tabKey(term2) !== "";
|
|
499
576
|
}
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
function inboxPath(logDir, id) {
|
|
505
|
-
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");
|
|
506
581
|
}
|
|
507
|
-
function
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
if (
|
|
513
|
-
|
|
514
|
-
out.push(JSON.parse(line));
|
|
515
|
-
} 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"));
|
|
516
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 {
|
|
517
606
|
}
|
|
518
|
-
return out;
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
// src/workers/tree.ts
|
|
522
|
-
function workerDepth(statuses, id) {
|
|
523
|
-
const byId = new Map(statuses.map((s) => [s.id, s]));
|
|
524
|
-
let depth = 0;
|
|
525
|
-
let cur = byId.get(id);
|
|
526
|
-
const seen = /* @__PURE__ */ new Set([id]);
|
|
527
|
-
while (cur?.parent && !seen.has(cur.parent)) {
|
|
528
|
-
seen.add(cur.parent);
|
|
529
|
-
const next = byId.get(cur.parent);
|
|
530
|
-
if (!next) break;
|
|
531
|
-
depth += 1;
|
|
532
|
-
cur = next;
|
|
533
|
-
}
|
|
534
|
-
return depth;
|
|
535
607
|
}
|
|
536
608
|
|
|
537
609
|
// src/workers/report.ts
|
|
@@ -544,6 +616,8 @@ var WORKER_CONTRACT_PROMPT = [
|
|
|
544
616
|
"changed: files you touched (path + one-line summary). commands: the commands that verify the work.",
|
|
545
617
|
"checks: each with ok true/false and the evidence in detail. open: what you could not finish, if anything.",
|
|
546
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).",
|
|
547
621
|
"",
|
|
548
622
|
`Operator messages: a user turn starting with ${OPERATOR_MARK} was typed by the operator while you`,
|
|
549
623
|
"run (the prompt of a resumed run is the operator's too). Answer it FIRST, in one or two plain lines \u2014",
|
|
@@ -560,76 +634,61 @@ var WORKER_CONTRACT_PROMPT = [
|
|
|
560
634
|
].join("\n");
|
|
561
635
|
|
|
562
636
|
// src/workers/render.ts
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
cyan: "36"
|
|
572
|
-
};
|
|
573
|
-
function makeColor(enabled) {
|
|
574
|
-
return (name, s) => enabled ? `\x1B[${CODES[name]}m${s}\x1B[0m` : s;
|
|
575
|
-
}
|
|
576
|
-
function fmtK(n) {
|
|
577
|
-
return n >= 1e3 ? `${Math.round(n / 1e3)}k` : String(n);
|
|
578
|
-
}
|
|
579
|
-
function contextMeter(c, s, minPct = 0) {
|
|
580
|
-
const pct = contextPercent(s);
|
|
581
|
-
if (pct === null || pct <= minPct) return null;
|
|
582
|
-
const label = `ctx ${fmtK(s.contextTokens ?? 0)}/${fmtK(s.contextWindow ?? 0)} (${pct}%)`;
|
|
583
|
-
if (pct > 85) return c("red", label);
|
|
584
|
-
if (pct > 70) return c("yellow", label);
|
|
585
|
-
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);
|
|
586
645
|
}
|
|
587
|
-
function renderStatusLine(mine, now = /* @__PURE__ */ new Date()
|
|
646
|
+
function renderStatusLine(mine, now = /* @__PURE__ */ new Date()) {
|
|
588
647
|
if (!mine.length) return "";
|
|
589
|
-
const
|
|
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));
|
|
590
651
|
const today = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`;
|
|
591
652
|
const doneToday = mine.filter((s) => s.state !== "running" && s.started.startsWith(today));
|
|
592
653
|
const ok = doneToday.filter((s) => s.state === "done").length;
|
|
593
654
|
const bad2 = doneToday.length - ok;
|
|
594
|
-
const
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
const meter = contextMeter(c, s, 60);
|
|
599
|
-
const depth = workerDepth(all, s.id);
|
|
600
|
-
const lead = depth > 0 ? " ".repeat(depth - 1) + "\u21B3 " : "";
|
|
601
|
-
const box = inbox[s.id] ? ` \u25C6${inbox[s.id]}` : "";
|
|
602
|
-
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)}`;
|
|
603
659
|
});
|
|
604
|
-
|
|
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(" | ");
|
|
605
668
|
if (doneToday.length) head += ` \u2713${ok} \u2717${bad2} today`;
|
|
606
669
|
return head;
|
|
607
670
|
}
|
|
608
671
|
|
|
609
672
|
// src/workers/viewer.ts
|
|
610
|
-
function
|
|
611
|
-
const out = {};
|
|
612
|
-
for (const s of statuses) {
|
|
613
|
-
const n = readInbox(logDir, s.id).length;
|
|
614
|
-
if (n) out[s.id] = n;
|
|
615
|
-
}
|
|
616
|
-
return out;
|
|
617
|
-
}
|
|
618
|
-
function statusLineOutput(logDir, term2, cwd2, now = /* @__PURE__ */ new Date()) {
|
|
673
|
+
function statusLineOutput(logDir, term2, cwd2, claudeSession2 = "", now = /* @__PURE__ */ new Date()) {
|
|
619
674
|
const statuses = loadStatuses(logDir);
|
|
620
675
|
const mine = statuses.filter((s) => {
|
|
621
676
|
const sameScope = term2 && workerInScope(s, term2);
|
|
677
|
+
const spawnedHere = claudeSession2 && s.spawnerSession === claudeSession2;
|
|
622
678
|
const sameDir = cwd2 && s.cwd.startsWith(cwd2);
|
|
623
|
-
return sameScope || !term2 && sameDir;
|
|
679
|
+
return sameScope || spawnedHere || !term2 && sameDir;
|
|
624
680
|
});
|
|
625
|
-
return renderStatusLine(mine, now
|
|
681
|
+
return renderStatusLine(mine, now);
|
|
626
682
|
}
|
|
627
683
|
|
|
628
684
|
// src/workers/standalone/status-line.ts
|
|
629
685
|
var term = process.argv[2] ?? process.env.ITERM_SESSION_ID ?? "";
|
|
630
686
|
var cwd = process.argv[3] ?? process.cwd();
|
|
687
|
+
var claudeSession = process.argv[4] ?? "";
|
|
631
688
|
try {
|
|
632
|
-
const
|
|
689
|
+
const logDir = workersLogDir(readWorkersSection().workers);
|
|
690
|
+
if (claudeSession) recordSessionMapEntry(logDir, cwd, claudeSession);
|
|
691
|
+
const out = statusLineOutput(logDir, term, cwd, claudeSession);
|
|
633
692
|
if (out) process.stdout.write(out + "\n");
|
|
634
693
|
} catch {
|
|
635
694
|
}
|