@tekmidian/pai 0.37.0 → 0.39.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/dist/{auto-route-DM7GhJ8y.mjs → auto-route-BlWOWT4z.mjs} +2 -2
- package/dist/{auto-route-DM7GhJ8y.mjs.map → auto-route-BlWOWT4z.mjs.map} +1 -1
- package/dist/{providers-sXcK5bDZ.mjs → chain-CTtHligI.mjs} +1040 -782
- package/dist/chain-CTtHligI.mjs.map +1 -0
- package/dist/cli/index.mjs +4 -3
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli/program.mjs +4 -3
- package/dist/{clusters-Do4tEGyc.mjs → clusters-wlK0w41E.mjs} +1 -1
- package/dist/{clusters-Do4tEGyc.mjs.map → clusters-wlK0w41E.mjs.map} +1 -1
- package/dist/daemon/index.mjs +7 -7
- package/dist/{daemon-CGg1VCbA.mjs → daemon-CTkN_Vn8.mjs} +25 -25
- package/dist/{daemon-CGg1VCbA.mjs.map → daemon-CTkN_Vn8.mjs.map} +1 -1
- package/dist/{daemon-DsGGiIJM.mjs → daemon-CmHHmKpg.mjs} +7 -7
- package/dist/daemon-mcp/index.mjs +207 -34
- package/dist/daemon-mcp/index.mjs.map +1 -1
- package/dist/{detector-CMap-9vw.mjs → detector-Bwk_4Pk4.mjs} +1 -1
- package/dist/{detector-CMap-9vw.mjs.map → detector-Bwk_4Pk4.mjs.map} +1 -1
- package/dist/detector-DO730Zq0.mjs +5 -0
- package/dist/{factory-DD2T33C9.mjs → factory-A9x-T2Kg.mjs} +5 -5
- package/dist/{factory-DD2T33C9.mjs.map → factory-A9x-T2Kg.mjs.map} +1 -1
- package/dist/factory-BD-np0Vd.mjs +3 -0
- package/dist/hooks/route-agents-to-worker.mjs +112 -20
- package/dist/hooks/route-agents-to-worker.mjs.map +2 -2
- package/dist/hooks/worker-proxy.mjs +110 -18
- package/dist/hooks/worker-proxy.mjs.map +2 -2
- package/dist/hooks/worker-status-line.mjs +176 -23
- package/dist/hooks/worker-status-line.mjs.map +4 -4
- package/dist/{indexer-backend-Cox9BCo-.mjs → indexer-backend-TG64CCQC.mjs} +1 -1
- package/dist/{indexer-backend-Cox9BCo-.mjs.map → indexer-backend-TG64CCQC.mjs.map} +1 -1
- package/dist/{latent-ideas-BC1oINZ-.mjs → latent-ideas-B7wq75Pt.mjs} +2 -2
- package/dist/{latent-ideas-BC1oINZ-.mjs.map → latent-ideas-B7wq75Pt.mjs.map} +1 -1
- package/dist/{link-boost-QFLrJwD6.mjs → link-boost-HkG7JWZR.mjs} +1 -1
- package/dist/{link-boost-QFLrJwD6.mjs.map → link-boost-HkG7JWZR.mjs.map} +1 -1
- package/dist/{neighborhood-D9MJ1c8f.mjs → neighborhood-lThN-MaQ.mjs} +1 -1
- package/dist/{neighborhood-D9MJ1c8f.mjs.map → neighborhood-lThN-MaQ.mjs.map} +1 -1
- package/dist/{note-context-d1wT_-GA.mjs → note-context-b6k0mAKi.mjs} +1 -1
- package/dist/{note-context-d1wT_-GA.mjs.map → note-context-b6k0mAKi.mjs.map} +1 -1
- package/dist/planner-BDI7bE9B.mjs +243 -0
- package/dist/planner-BDI7bE9B.mjs.map +1 -0
- package/dist/{postgres--BjPtLa0.mjs → postgres-mW1n7Vi1.mjs} +1 -1
- package/dist/{postgres--BjPtLa0.mjs.map → postgres-mW1n7Vi1.mjs.map} +1 -1
- package/dist/{program-CEIHn_Ma.mjs → program-DXBwJV7h.mjs} +274 -65
- package/dist/program-DXBwJV7h.mjs.map +1 -0
- package/dist/providers-FYkZjn_C.mjs +1405 -0
- package/dist/providers-FYkZjn_C.mjs.map +1 -0
- package/dist/{query-feedback-BUJxgw5B.mjs → query-feedback-BV4CcxqS.mjs} +1 -1
- package/dist/{query-feedback-BUJxgw5B.mjs.map → query-feedback-BV4CcxqS.mjs.map} +1 -1
- package/dist/query-feedback-DSVyHtrG.mjs +3 -0
- package/dist/router-Bk77E7hj.mjs +3 -0
- package/dist/{router-DK_sLsUL.mjs → router-DcHKnEPa.mjs} +1 -1
- package/dist/{router-DK_sLsUL.mjs.map → router-DcHKnEPa.mjs.map} +1 -1
- package/dist/skills/Worker/SKILL.md +34 -12
- package/dist/{sources-Bi7--33T.mjs → sources-kLnQsNrW.mjs} +1 -1
- package/dist/{sources-Bi7--33T.mjs.map → sources-kLnQsNrW.mjs.map} +1 -1
- package/dist/{sqlite-DtaL1glm.mjs → sqlite-BenGr3UP.mjs} +1 -1
- package/dist/{sqlite-DtaL1glm.mjs.map → sqlite-BenGr3UP.mjs.map} +1 -1
- package/dist/{state-BY2L6-vX.mjs → state-CAeyOdfq.mjs} +1 -1
- package/dist/{state-BY2L6-vX.mjs.map → state-CAeyOdfq.mjs.map} +1 -1
- package/dist/{state-8Hm9E4tW.mjs → state-Ca9F_sZc.mjs} +1 -1
- package/dist/{themes-BN0a2duq.mjs → themes-BI4GMRP9.mjs} +1 -1
- package/dist/{themes-BN0a2duq.mjs.map → themes-BI4GMRP9.mjs.map} +1 -1
- package/dist/{tools-CGPqpU3A.mjs → tools-Bp7hj6OW.mjs} +1 -1
- package/dist/{tools-y2bJpKom.mjs → tools-DGcB3o_S.mjs} +13 -13
- package/dist/{tools-y2bJpKom.mjs.map → tools-DGcB3o_S.mjs.map} +1 -1
- package/dist/{trace-h23JCcFD.mjs → trace-bobARFEX.mjs} +1 -1
- package/dist/{trace-h23JCcFD.mjs.map → trace-bobARFEX.mjs.map} +1 -1
- package/dist/{vault-indexer-DgsPjMgs.mjs → vault-indexer-C3OfXTNF.mjs} +1 -1
- package/dist/{vault-indexer-DgsPjMgs.mjs.map → vault-indexer-C3OfXTNF.mjs.map} +1 -1
- package/dist/{work-queue-worker-gsKd2LJa.mjs → work-queue-worker-DW8lz-Oo.mjs} +3 -3
- package/dist/{work-queue-worker-Dva_v_pI.mjs → work-queue-worker-R7UGIag_.mjs} +3 -3
- package/dist/{work-queue-worker-Dva_v_pI.mjs.map → work-queue-worker-R7UGIag_.mjs.map} +1 -1
- package/dist/{zettelkasten-vo7psPdT.mjs → zettelkasten-m5QPtb-L.mjs} +3 -3
- package/dist/{zettelkasten-vo7psPdT.mjs.map → zettelkasten-m5QPtb-L.mjs.map} +1 -1
- package/docs/commands/README.md +12 -7
- package/docs/commands/worker.md +110 -17
- package/docs/worker.md +244 -25
- package/package.json +1 -1
- package/src/hooks/ts/pre-tool-use/route-agents-to-worker.ts +2 -2
- package/dist/detector-DtLExmHN.mjs +0 -5
- package/dist/factory-BXzqRYVZ.mjs +0 -3
- package/dist/program-CEIHn_Ma.mjs.map +0 -1
- package/dist/providers-sXcK5bDZ.mjs.map +0 -1
- package/dist/query-feedback-DhyLOe5S.mjs +0 -3
- package/dist/router-1zi8jiNF.mjs +0 -3
- /package/dist/{main-resolver-IhZo4pI0.mjs → main-resolver-D6IImXvF.mjs} +0 -0
|
@@ -131,6 +131,14 @@ 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 PROVIDER_TAGS = [
|
|
135
|
+
"code",
|
|
136
|
+
"vision",
|
|
137
|
+
"image-gen",
|
|
138
|
+
"long-context",
|
|
139
|
+
"fast",
|
|
140
|
+
"reasoning"
|
|
141
|
+
];
|
|
134
142
|
var DEFAULT_LOG_DIR = "~/.claude/logs/workers";
|
|
135
143
|
var DEFAULT_PANE = {
|
|
136
144
|
enabled: true,
|
|
@@ -142,16 +150,24 @@ var DEFAULT_ROUTING2 = {
|
|
|
142
150
|
cooldownMinutes: 30,
|
|
143
151
|
retryOnQuota: true
|
|
144
152
|
};
|
|
153
|
+
var DEFAULT_TREE = {
|
|
154
|
+
maxDepth: 2,
|
|
155
|
+
maxChildren: 4
|
|
156
|
+
};
|
|
157
|
+
var DEFAULT_MCP_SETS = {
|
|
158
|
+
desktop: ["clickr"]
|
|
159
|
+
};
|
|
145
160
|
function defaultWorkersConfig() {
|
|
146
161
|
return {
|
|
147
162
|
enabled: false,
|
|
148
163
|
active: null,
|
|
149
164
|
providers: {},
|
|
150
|
-
|
|
151
|
-
mcpSets: {},
|
|
165
|
+
classes: {},
|
|
166
|
+
mcpSets: { ...DEFAULT_MCP_SETS },
|
|
152
167
|
pane: { ...DEFAULT_PANE },
|
|
153
168
|
logDir: DEFAULT_LOG_DIR,
|
|
154
|
-
routing: { ...DEFAULT_ROUTING2, order: [] }
|
|
169
|
+
routing: { ...DEFAULT_ROUTING2, order: [] },
|
|
170
|
+
tree: { ...DEFAULT_TREE }
|
|
155
171
|
};
|
|
156
172
|
}
|
|
157
173
|
var WorkersConfigError = class extends Error {
|
|
@@ -210,6 +226,24 @@ function parseProvider(name, raw) {
|
|
|
210
226
|
if (protocol === "openai" && !upstreamUrl) {
|
|
211
227
|
bad(`.providers.${name}.upstreamUrl`, `is required for protocol "openai" (the Chat Completions base, e.g. "https://api.openai.com/v1")`);
|
|
212
228
|
}
|
|
229
|
+
const costTier = p.costTier === void 0 ? void 0 : p.costTier;
|
|
230
|
+
if (costTier !== void 0) {
|
|
231
|
+
if (typeof costTier !== "number" || !Number.isInteger(costTier) || costTier < 1 || costTier > 5) {
|
|
232
|
+
bad(`.providers.${name}.costTier`, "must be an integer 1 (cheapest) \u2026 5 (most expensive)");
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
let tags;
|
|
236
|
+
if (p.tags !== void 0) {
|
|
237
|
+
if (!Array.isArray(p.tags) || p.tags.some((x) => typeof x !== "string")) {
|
|
238
|
+
bad(`.providers.${name}.tags`, `must be an array of tags from: ${PROVIDER_TAGS.join(", ")}`);
|
|
239
|
+
}
|
|
240
|
+
for (const t of p.tags) {
|
|
241
|
+
if (!PROVIDER_TAGS.includes(t)) {
|
|
242
|
+
bad(`.providers.${name}.tags`, `"${t}" is not a tag (from: ${PROVIDER_TAGS.join(", ")})`);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
tags = p.tags;
|
|
246
|
+
}
|
|
213
247
|
return {
|
|
214
248
|
enabled: p.enabled === void 0 ? true : p.enabled === true,
|
|
215
249
|
protocol,
|
|
@@ -222,7 +256,9 @@ function parseProvider(name, raw) {
|
|
|
222
256
|
...engine !== "claude" ? { engine } : {},
|
|
223
257
|
...str(p.quotaProbe) ? { quotaProbe: str(p.quotaProbe) } : {},
|
|
224
258
|
...quotaSkipAt !== void 0 ? { quotaSkipAt } : {},
|
|
225
|
-
...contextWindow !== void 0 ? { contextWindow } : {}
|
|
259
|
+
...contextWindow !== void 0 ? { contextWindow } : {},
|
|
260
|
+
...costTier !== void 0 ? { costTier } : {},
|
|
261
|
+
...tags ? { tags } : {}
|
|
226
262
|
};
|
|
227
263
|
}
|
|
228
264
|
function parseWorkersConfig(raw) {
|
|
@@ -241,34 +277,68 @@ function parseWorkersConfig(raw) {
|
|
|
241
277
|
providers[name] = parseProvider(name, p);
|
|
242
278
|
}
|
|
243
279
|
}
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
280
|
+
const classes = {};
|
|
281
|
+
const classesRaw = w.classes !== void 0 ? w.classes : w.roles;
|
|
282
|
+
if (classesRaw !== void 0) {
|
|
283
|
+
if (typeof classesRaw !== "object" || classesRaw === null || Array.isArray(classesRaw)) {
|
|
284
|
+
bad(w.classes !== void 0 ? ".classes" : ".roles", "must be an object of class \u2192 provider[/alias] or {provider, mcp, maxCostTier, requireTags, order}");
|
|
248
285
|
}
|
|
249
|
-
for (const [
|
|
286
|
+
for (const [cls, target] of Object.entries(classesRaw)) {
|
|
250
287
|
if (typeof target === "object" && target !== null && !Array.isArray(target)) {
|
|
251
288
|
const o = target;
|
|
252
289
|
const provider = str(o.provider);
|
|
253
|
-
if (!provider || provider.includes(" ")) {
|
|
254
|
-
bad(`.
|
|
290
|
+
if (o.provider !== void 0 && (!provider || provider.includes(" "))) {
|
|
291
|
+
bad(`.classes.${cls}.provider`, `invalid provider "${provider}"`);
|
|
255
292
|
}
|
|
256
293
|
let mcp;
|
|
257
294
|
if (o.mcp !== void 0) {
|
|
258
295
|
if (!Array.isArray(o.mcp) || o.mcp.some((x) => typeof x !== "string")) {
|
|
259
|
-
bad(`.
|
|
296
|
+
bad(`.classes.${cls}.mcp`, "must be an array of MCP server or set names");
|
|
260
297
|
}
|
|
261
298
|
mcp = o.mcp;
|
|
262
299
|
}
|
|
263
|
-
|
|
300
|
+
let maxCostTier;
|
|
301
|
+
if (o.maxCostTier !== void 0) {
|
|
302
|
+
if (typeof o.maxCostTier !== "number" || !Number.isInteger(o.maxCostTier) || o.maxCostTier < 1 || o.maxCostTier > 5) {
|
|
303
|
+
bad(`.classes.${cls}.maxCostTier`, "must be an integer 1 \u2026 5");
|
|
304
|
+
}
|
|
305
|
+
maxCostTier = o.maxCostTier;
|
|
306
|
+
}
|
|
307
|
+
let requireTags;
|
|
308
|
+
if (o.requireTags !== void 0) {
|
|
309
|
+
if (!Array.isArray(o.requireTags) || o.requireTags.some((x) => typeof x !== "string")) {
|
|
310
|
+
bad(`.classes.${cls}.requireTags`, `must be an array of tags from: ${PROVIDER_TAGS.join(", ")}`);
|
|
311
|
+
}
|
|
312
|
+
for (const t of o.requireTags) {
|
|
313
|
+
if (!PROVIDER_TAGS.includes(t)) {
|
|
314
|
+
bad(`.classes.${cls}.requireTags`, `"${t}" is not a tag (from: ${PROVIDER_TAGS.join(", ")})`);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
requireTags = o.requireTags;
|
|
318
|
+
}
|
|
319
|
+
let order;
|
|
320
|
+
if (o.order !== void 0) {
|
|
321
|
+
if (!Array.isArray(o.order) || o.order.some((x) => typeof x !== "string")) {
|
|
322
|
+
bad(`.classes.${cls}.order`, "must be an array of provider names");
|
|
323
|
+
}
|
|
324
|
+
order = o.order;
|
|
325
|
+
}
|
|
326
|
+
const obj = {
|
|
327
|
+
...provider ? { provider } : {},
|
|
328
|
+
...mcp ? { mcp } : {},
|
|
329
|
+
...maxCostTier !== void 0 ? { maxCostTier } : {},
|
|
330
|
+
...requireTags ? { requireTags } : {},
|
|
331
|
+
...order ? { order } : {}
|
|
332
|
+
};
|
|
333
|
+
classes[cls] = Object.keys(obj).length ? obj : {};
|
|
264
334
|
} else {
|
|
265
335
|
const t = str(target);
|
|
266
|
-
if (!t || t.includes(" ")) bad(`.
|
|
267
|
-
|
|
336
|
+
if (!t || t.includes(" ")) bad(`.classes.${cls}`, `invalid target "${t}"`);
|
|
337
|
+
classes[cls] = t;
|
|
268
338
|
}
|
|
269
339
|
}
|
|
270
340
|
}
|
|
271
|
-
const mcpSets = {};
|
|
341
|
+
const mcpSets = { ...DEFAULT_MCP_SETS };
|
|
272
342
|
if (w.mcpSets !== void 0) {
|
|
273
343
|
if (typeof w.mcpSets !== "object" || w.mcpSets === null || Array.isArray(w.mcpSets)) {
|
|
274
344
|
bad(".mcpSets", "must be an object of set name \u2192 [server names]");
|
|
@@ -319,6 +389,27 @@ function parseWorkersConfig(raw) {
|
|
|
319
389
|
retryOnQuota: r.retryOnQuota === void 0 ? DEFAULT_ROUTING2.retryOnQuota : r.retryOnQuota === true
|
|
320
390
|
};
|
|
321
391
|
}
|
|
392
|
+
let tree = { ...DEFAULT_TREE };
|
|
393
|
+
if (w.tree !== void 0) {
|
|
394
|
+
if (typeof w.tree !== "object" || w.tree === null || Array.isArray(w.tree)) {
|
|
395
|
+
bad(".tree", "must be an object");
|
|
396
|
+
}
|
|
397
|
+
const t = w.tree;
|
|
398
|
+
if (t.maxDepth !== void 0) {
|
|
399
|
+
if (typeof t.maxDepth !== "number" || !Number.isInteger(t.maxDepth) || t.maxDepth < 0) {
|
|
400
|
+
bad(".tree.maxDepth", "must be a non-negative integer");
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
if (t.maxChildren !== void 0) {
|
|
404
|
+
if (typeof t.maxChildren !== "number" || !Number.isInteger(t.maxChildren) || t.maxChildren < 1) {
|
|
405
|
+
bad(".tree.maxChildren", "must be a positive integer");
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
tree = {
|
|
409
|
+
maxDepth: t.maxDepth === void 0 ? DEFAULT_TREE.maxDepth : t.maxDepth,
|
|
410
|
+
maxChildren: t.maxChildren === void 0 ? DEFAULT_TREE.maxChildren : t.maxChildren
|
|
411
|
+
};
|
|
412
|
+
}
|
|
322
413
|
const active = w.active === void 0 || w.active === null ? null : str(w.active);
|
|
323
414
|
if (active !== null && active !== "auto" && !(active in providers)) {
|
|
324
415
|
}
|
|
@@ -326,11 +417,12 @@ function parseWorkersConfig(raw) {
|
|
|
326
417
|
enabled: w.enabled === void 0 ? d.enabled : w.enabled === true,
|
|
327
418
|
active,
|
|
328
419
|
providers,
|
|
329
|
-
|
|
420
|
+
classes,
|
|
330
421
|
mcpSets,
|
|
331
422
|
pane,
|
|
332
423
|
logDir: str(w.logDir) || d.logDir,
|
|
333
|
-
routing
|
|
424
|
+
routing,
|
|
425
|
+
tree
|
|
334
426
|
};
|
|
335
427
|
}
|
|
336
428
|
function readWorkersSection() {
|
|
@@ -406,7 +498,44 @@ function workerInScope(worker, term2) {
|
|
|
406
498
|
return tabKey(worker.term) === tabKey(term2) && tabKey(term2) !== "";
|
|
407
499
|
}
|
|
408
500
|
|
|
501
|
+
// src/workers/handoff.ts
|
|
502
|
+
import { appendFileSync, existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3 } from "node:fs";
|
|
503
|
+
import { dirname, join as join5 } from "node:path";
|
|
504
|
+
function inboxPath(logDir, id) {
|
|
505
|
+
return join5(logDir, `${id}.inbox.jsonl`);
|
|
506
|
+
}
|
|
507
|
+
function readInbox(logDir, id) {
|
|
508
|
+
const path = inboxPath(logDir, id);
|
|
509
|
+
if (!existsSync3(path)) return [];
|
|
510
|
+
const out = [];
|
|
511
|
+
for (const line of readFileSync3(path, "utf8").split("\n")) {
|
|
512
|
+
if (!line.trim()) continue;
|
|
513
|
+
try {
|
|
514
|
+
out.push(JSON.parse(line));
|
|
515
|
+
} catch {
|
|
516
|
+
}
|
|
517
|
+
}
|
|
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
|
+
}
|
|
536
|
+
|
|
409
537
|
// src/workers/report.ts
|
|
538
|
+
var OPERATOR_MARK = "[operator]";
|
|
410
539
|
var WORKER_CONTRACT_PROMPT = [
|
|
411
540
|
"You are a headless implementation worker, run non-interactively by an orchestrating session.",
|
|
412
541
|
"No narration, no timestamps, no greetings, no summaries of what you read; act, verify, then stop.",
|
|
@@ -414,7 +543,20 @@ var WORKER_CONTRACT_PROMPT = [
|
|
|
414
543
|
'{"changed":[{"path":"\u2026","summary":"\u2026"}],"commands":["\u2026"],"checks":[{"name":"\u2026","ok":true,"detail":"\u2026"}],"open":["\u2026"],"notes":"one line"}',
|
|
415
544
|
"changed: files you touched (path + one-line summary). commands: the commands that verify the work.",
|
|
416
545
|
"checks: each with ok true/false and the evidence in detail. open: what you could not finish, if anything.",
|
|
417
|
-
"notes: one line, the headline a reviewer reads first."
|
|
546
|
+
"notes: one line, the headline a reviewer reads first.",
|
|
547
|
+
"",
|
|
548
|
+
`Operator messages: a user turn starting with ${OPERATOR_MARK} was typed by the operator while you`,
|
|
549
|
+
"run (the prompt of a resumed run is the operator's too). Answer it FIRST, in one or two plain lines \u2014",
|
|
550
|
+
"a question gets its answer, an instruction gets one line naming what will change \u2014 then continue the",
|
|
551
|
+
"task you were on.",
|
|
552
|
+
"",
|
|
553
|
+
"Sub-workers: you may start your own workers with `pai worker run --class <class> -p '<prompt>'`",
|
|
554
|
+
"(Bash tool). Your children run on their own provider and report back to you automatically when",
|
|
555
|
+
"they finish. Send a handoff UP instead of doing work yourself when a cheaper provider would",
|
|
556
|
+
"suffice, the task is out of your scope, or a decision is needed:",
|
|
557
|
+
'`pai worker handoff \'{"kind":"proposal","text":"\u2026","data":{\u2026}}\'` (kinds: proposal,',
|
|
558
|
+
"question, blocker; results are sent for you when you finish). Sibling workers are not a",
|
|
559
|
+
"coordination path \u2014 there is no sideways channel; everything goes up to your parent."
|
|
418
560
|
].join("\n");
|
|
419
561
|
|
|
420
562
|
// src/workers/render.ts
|
|
@@ -442,9 +584,9 @@ function contextMeter(c, s, minPct = 0) {
|
|
|
442
584
|
if (pct > 70) return c("yellow", label);
|
|
443
585
|
return label;
|
|
444
586
|
}
|
|
445
|
-
function renderStatusLine(mine, now = /* @__PURE__ */ new Date(), c = makeColor(true)) {
|
|
587
|
+
function renderStatusLine(mine, now = /* @__PURE__ */ new Date(), c = makeColor(true), all = mine, inbox = {}) {
|
|
446
588
|
if (!mine.length) return "";
|
|
447
|
-
const running = mine.filter((s) => s.state === "running" && alive(s.pid));
|
|
589
|
+
const running = mine.filter((s) => s.state === "running" && alive(s.pid)).sort((a, b) => workerDepth(all, a.id) - workerDepth(all, b.id));
|
|
448
590
|
const today = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`;
|
|
449
591
|
const doneToday = mine.filter((s) => s.state !== "running" && s.started.startsWith(today));
|
|
450
592
|
const ok = doneToday.filter((s) => s.state === "done").length;
|
|
@@ -454,7 +596,10 @@ function renderStatusLine(mine, now = /* @__PURE__ */ new Date(), c = makeColor(
|
|
|
454
596
|
let head = `${providerTag} \u25B6${running.length}`;
|
|
455
597
|
const parts = running.slice(0, 3).map((s) => {
|
|
456
598
|
const meter = contextMeter(c, s, 60);
|
|
457
|
-
|
|
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}` : "");
|
|
458
603
|
});
|
|
459
604
|
if (parts.length) head += " " + parts.join(" | ");
|
|
460
605
|
if (doneToday.length) head += ` \u2713${ok} \u2717${bad2} today`;
|
|
@@ -462,6 +607,14 @@ function renderStatusLine(mine, now = /* @__PURE__ */ new Date(), c = makeColor(
|
|
|
462
607
|
}
|
|
463
608
|
|
|
464
609
|
// src/workers/viewer.ts
|
|
610
|
+
function inboxCounts(logDir, statuses) {
|
|
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
|
+
}
|
|
465
618
|
function statusLineOutput(logDir, term2, cwd2, now = /* @__PURE__ */ new Date()) {
|
|
466
619
|
const statuses = loadStatuses(logDir);
|
|
467
620
|
const mine = statuses.filter((s) => {
|
|
@@ -469,7 +622,7 @@ function statusLineOutput(logDir, term2, cwd2, now = /* @__PURE__ */ new Date())
|
|
|
469
622
|
const sameDir = cwd2 && s.cwd.startsWith(cwd2);
|
|
470
623
|
return sameScope || !term2 && sameDir;
|
|
471
624
|
});
|
|
472
|
-
return renderStatusLine(mine, now);
|
|
625
|
+
return renderStatusLine(mine, now, makeColor(false), statuses, inboxCounts(logDir, mine));
|
|
473
626
|
}
|
|
474
627
|
|
|
475
628
|
// src/workers/standalone/status-line.ts
|