@tekmidian/pai 0.36.2 → 0.38.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-Byf8ENXj.mjs → auto-route-DM7GhJ8y.mjs} +2 -2
- package/dist/{auto-route-Byf8ENXj.mjs.map → auto-route-DM7GhJ8y.mjs.map} +1 -1
- package/dist/cli/index.mjs +5 -4
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli/program.d.mts.map +1 -1
- package/dist/cli/program.mjs +5 -4
- package/dist/{clusters-wZgTCYCB.mjs → clusters-Do4tEGyc.mjs} +1 -1
- package/dist/{clusters-wZgTCYCB.mjs.map → clusters-Do4tEGyc.mjs.map} +1 -1
- package/dist/{context-handover-cache-PtNvj_8D.mjs → context-handover-cache-BpUojjsi.mjs} +2 -2
- package/dist/{context-handover-cache-PtNvj_8D.mjs.map → context-handover-cache-BpUojjsi.mjs.map} +1 -1
- package/dist/daemon/index.mjs +8 -8
- package/dist/{daemon-BZ93KRBo.mjs → daemon-CGg1VCbA.mjs} +25 -25
- package/dist/{daemon-BZ93KRBo.mjs.map → daemon-CGg1VCbA.mjs.map} +1 -1
- package/dist/daemon-DsGGiIJM.mjs +20 -0
- package/dist/daemon-mcp/index.mjs +549 -1
- package/dist/daemon-mcp/index.mjs.map +1 -1
- package/dist/{detector--Gg5JRN5.mjs → detector-CMap-9vw.mjs} +1 -1
- package/dist/{detector--Gg5JRN5.mjs.map → detector-CMap-9vw.mjs.map} +1 -1
- package/dist/detector-DtLExmHN.mjs +5 -0
- package/dist/factory-BXzqRYVZ.mjs +3 -0
- package/dist/{factory-Bsp7xOpO.mjs → factory-DD2T33C9.mjs} +5 -5
- package/dist/{factory-Bsp7xOpO.mjs.map → factory-DD2T33C9.mjs.map} +1 -1
- package/dist/hooks/context-compression-hook.mjs +164 -14
- package/dist/hooks/context-compression-hook.mjs.map +4 -4
- package/dist/hooks/initialize-session.mjs +6 -0
- package/dist/hooks/initialize-session.mjs.map +3 -3
- package/dist/hooks/load-core-context.mjs +6 -0
- package/dist/hooks/load-core-context.mjs.map +3 -3
- package/dist/hooks/load-project-context.mjs +6 -0
- package/dist/hooks/load-project-context.mjs.map +3 -3
- package/dist/hooks/post-compact-inject.mjs +6 -0
- package/dist/hooks/post-compact-inject.mjs.map +3 -3
- package/dist/hooks/route-agents-to-worker.mjs +518 -0
- package/dist/hooks/route-agents-to-worker.mjs.map +7 -0
- package/dist/hooks/status-line.mjs +400 -0
- package/dist/hooks/status-line.mjs.map +7 -0
- package/dist/hooks/stop-hook.mjs +6 -0
- package/dist/hooks/stop-hook.mjs.map +3 -3
- package/dist/hooks/subagent-stop-hook.mjs +6 -0
- package/dist/hooks/subagent-stop-hook.mjs.map +3 -3
- package/dist/hooks/sync-todo-to-md.mjs +6 -0
- package/dist/hooks/sync-todo-to-md.mjs.map +3 -3
- package/dist/hooks/update-tab-on-action.mjs +6 -0
- package/dist/hooks/update-tab-on-action.mjs.map +3 -3
- package/dist/hooks/update-tab-titles.mjs +6 -0
- package/dist/hooks/update-tab-titles.mjs.map +3 -3
- package/dist/hooks/worker-proxy.mjs +858 -0
- package/dist/hooks/worker-proxy.mjs.map +7 -0
- package/dist/hooks/worker-status-line.mjs +545 -0
- package/dist/hooks/worker-status-line.mjs.map +7 -0
- package/dist/{indexer-backend-nQZuEx6N.mjs → indexer-backend-Cox9BCo-.mjs} +1 -1
- package/dist/{indexer-backend-nQZuEx6N.mjs.map → indexer-backend-Cox9BCo-.mjs.map} +1 -1
- package/dist/{kg-entity-DbOMPdF9.mjs → kg-entity-r8duqhi9.mjs} +1 -1
- package/dist/{kg-entity-DbOMPdF9.mjs.map → kg-entity-r8duqhi9.mjs.map} +1 -1
- package/dist/{latent-ideas-Bn6A5-5P.mjs → latent-ideas-BC1oINZ-.mjs} +2 -2
- package/dist/{latent-ideas-Bn6A5-5P.mjs.map → latent-ideas-BC1oINZ-.mjs.map} +1 -1
- package/dist/{link-boost-fYjUnxCN.mjs → link-boost-QFLrJwD6.mjs} +1 -1
- package/dist/{link-boost-fYjUnxCN.mjs.map → link-boost-QFLrJwD6.mjs.map} +1 -1
- package/dist/{main-resolver-BAbhKpeX.mjs → main-resolver-DlaLOFBA.mjs} +1 -1
- package/dist/{main-resolver-BAbhKpeX.mjs.map → main-resolver-DlaLOFBA.mjs.map} +1 -1
- package/dist/{main-resolver-Dxh444GO.mjs → main-resolver-IhZo4pI0.mjs} +1 -1
- package/dist/{neighborhood-DpaEM991.mjs → neighborhood-D9MJ1c8f.mjs} +1 -1
- package/dist/{neighborhood-DpaEM991.mjs.map → neighborhood-D9MJ1c8f.mjs.map} +1 -1
- package/dist/{note-context-DrcY4cWm.mjs → note-context-d1wT_-GA.mjs} +1 -1
- package/dist/{note-context-DrcY4cWm.mjs.map → note-context-d1wT_-GA.mjs.map} +1 -1
- package/dist/{postgres-BVme6qX0.mjs → postgres--BjPtLa0.mjs} +1 -1
- package/dist/{postgres-BVme6qX0.mjs.map → postgres--BjPtLa0.mjs.map} +1 -1
- package/dist/{program-C-fUghPv.mjs → program-Y0hAiVy8.mjs} +851 -101
- package/dist/program-Y0hAiVy8.mjs.map +1 -0
- package/dist/providers-DUshcB-d.mjs +4031 -0
- package/dist/providers-DUshcB-d.mjs.map +1 -0
- package/dist/{query-feedback-C1T6kS18.mjs → query-feedback-BUJxgw5B.mjs} +1 -1
- package/dist/{query-feedback-C1T6kS18.mjs.map → query-feedback-BUJxgw5B.mjs.map} +1 -1
- package/dist/query-feedback-DhyLOe5S.mjs +3 -0
- package/dist/router-1zi8jiNF.mjs +3 -0
- package/dist/{router-CsDm7HvK.mjs → router-DK_sLsUL.mjs} +1 -1
- package/dist/{router-CsDm7HvK.mjs.map → router-DK_sLsUL.mjs.map} +1 -1
- package/dist/skills/Worker/SKILL.md +63 -0
- package/dist/{sources-D8ZdNfvK.mjs → sources-Bi7--33T.mjs} +1 -1
- package/dist/{sources-D8ZdNfvK.mjs.map → sources-Bi7--33T.mjs.map} +1 -1
- package/dist/{sqlite-D1IaR8Am.mjs → sqlite-DtaL1glm.mjs} +1 -1
- package/dist/{sqlite-D1IaR8Am.mjs.map → sqlite-DtaL1glm.mjs.map} +1 -1
- package/dist/{state-qtmrBWCm.mjs → state-8Hm9E4tW.mjs} +1 -1
- package/dist/{state-WaXhLr6R.mjs → state-BY2L6-vX.mjs} +1 -1
- package/dist/{state-WaXhLr6R.mjs.map → state-BY2L6-vX.mjs.map} +1 -1
- package/dist/{themes-XPkj_bfP.mjs → themes-BN0a2duq.mjs} +1 -1
- package/dist/{themes-XPkj_bfP.mjs.map → themes-BN0a2duq.mjs.map} +1 -1
- package/dist/{tools-DEt6YPfc.mjs → tools-CGPqpU3A.mjs} +1 -1
- package/dist/{tools-ceiy7ANX.mjs → tools-y2bJpKom.mjs} +14 -14
- package/dist/{tools-ceiy7ANX.mjs.map → tools-y2bJpKom.mjs.map} +1 -1
- package/dist/{trace-DfyGmMG_.mjs → trace-h23JCcFD.mjs} +1 -1
- package/dist/{trace-DfyGmMG_.mjs.map → trace-h23JCcFD.mjs.map} +1 -1
- package/dist/{vault-indexer-CFvlPUMB.mjs → vault-indexer-DgsPjMgs.mjs} +1 -1
- package/dist/{vault-indexer-CFvlPUMB.mjs.map → vault-indexer-DgsPjMgs.mjs.map} +1 -1
- package/dist/{work-queue-worker-B8W8_3Rn.mjs → work-queue-worker-Dva_v_pI.mjs} +4 -4
- package/dist/{work-queue-worker-B8W8_3Rn.mjs.map → work-queue-worker-Dva_v_pI.mjs.map} +1 -1
- package/dist/{work-queue-worker-HN2Ufg-L.mjs → work-queue-worker-gsKd2LJa.mjs} +4 -4
- package/dist/{zettelkasten-CvjmMghT.mjs → zettelkasten-vo7psPdT.mjs} +3 -3
- package/dist/{zettelkasten-CvjmMghT.mjs.map → zettelkasten-vo7psPdT.mjs.map} +1 -1
- package/docs/commands/README.md +29 -0
- package/docs/commands/backup.md +1 -1
- package/docs/commands/clear-names.md +1 -1
- package/docs/commands/daemon.md +1 -1
- package/docs/commands/db.md +1 -1
- package/docs/commands/end.md +1 -1
- package/docs/commands/help.md +1 -1
- package/docs/commands/identity.md +1 -1
- package/docs/commands/kg.md +1 -1
- package/docs/commands/mcp.md +1 -1
- package/docs/commands/memory.md +1 -1
- package/docs/commands/notify.md +1 -1
- package/docs/commands/observation.md +1 -1
- package/docs/commands/obsidian.md +1 -1
- package/docs/commands/pause.md +1 -1
- package/docs/commands/project.md +1 -1
- package/docs/commands/projects.md +1 -1
- package/docs/commands/registry.md +1 -1
- package/docs/commands/restore.md +1 -1
- package/docs/commands/session.md +1 -1
- package/docs/commands/sessions.md +1 -1
- package/docs/commands/setup.md +1 -1
- package/docs/commands/shell-init.md +1 -1
- package/docs/commands/skill.md +1 -1
- package/docs/commands/task.md +1 -1
- package/docs/commands/topic.md +1 -1
- package/docs/commands/update.md +1 -1
- package/docs/commands/worker.md +398 -0
- package/docs/commands/zettel.md +1 -1
- package/docs/worker.md +434 -0
- package/package.json +1 -1
- package/scripts/build-hooks.mjs +46 -1
- package/src/hooks/pre-compact.sh +1 -0
- package/src/hooks/session-autosave.sh +1 -0
- package/src/hooks/session-stop.sh +1 -0
- package/src/hooks/ts/lib/context-fill.test.ts +104 -0
- package/src/hooks/ts/lib/context-fill.ts +73 -0
- package/src/hooks/ts/lib/handover-evidence.ts +227 -0
- package/src/hooks/ts/lib/worker-session.test.ts +24 -0
- package/src/hooks/ts/lib/worker-session.ts +23 -0
- package/src/hooks/ts/post-tool-use/sync-todo-to-md.ts +2 -0
- package/src/hooks/ts/post-tool-use/update-tab-on-action.ts +2 -0
- package/src/hooks/ts/pre-compact/context-compression-hook.ts +17 -0
- package/src/hooks/ts/pre-tool-use/route-agents-to-worker.ts +128 -0
- package/src/hooks/ts/session-start/initialize-session.ts +2 -0
- package/src/hooks/ts/session-start/load-core-context.ts +2 -0
- package/src/hooks/ts/session-start/load-project-context.ts +2 -0
- package/src/hooks/ts/session-start/post-compact-inject.ts +2 -0
- package/src/hooks/ts/stop/stop-hook.ts +2 -0
- package/src/hooks/ts/subagent-stop/subagent-stop-hook.ts +2 -0
- package/src/hooks/ts/user-prompt/update-tab-titles.ts +2 -0
- package/statusline-command.sh +17 -0
- package/dist/daemon-DRdoA489.mjs +0 -20
- package/dist/detector-DGAk1iBR.mjs +0 -5
- package/dist/factory-CrokPMk2.mjs +0 -3
- package/dist/program-C-fUghPv.mjs.map +0 -1
- package/dist/query-feedback-BBMBp96K.mjs +0 -3
- package/dist/router-BMkOb62X.mjs +0 -3
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { t as PaiClient } from "../ipc-client-BmypMNYk.mjs";
|
|
3
3
|
import { o as loadConfig } from "../config-B64vFg14.mjs";
|
|
4
|
+
import { A as ledgerPath, D as ledgerSummary, E as loadStatus, P as readWorkersSection, _ as testProvider, a as setClass, c as unsetClass, f as psOutput, g as runWorker, h as runChain, i as removeProvider, j as workersLogDir, l as updateProvider, n as classTargetText, o as setProviderEnabled, p as replayOutput, r as describeProviders, s as setWorkersEnabled, t as addProvider, u as useProvider, x as sayToWorker } from "../providers-DUshcB-d.mjs";
|
|
4
5
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
6
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
7
|
|
|
@@ -1406,6 +1407,97 @@ function handleIntersectionResults(result, left, right) {
|
|
|
1406
1407
|
result.value = merged.data;
|
|
1407
1408
|
return result;
|
|
1408
1409
|
}
|
|
1410
|
+
const $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
|
|
1411
|
+
$ZodType.init(inst, def);
|
|
1412
|
+
inst._zod.parse = (payload, ctx) => {
|
|
1413
|
+
const input = payload.value;
|
|
1414
|
+
if (!isPlainObject(input)) {
|
|
1415
|
+
payload.issues.push({
|
|
1416
|
+
expected: "record",
|
|
1417
|
+
code: "invalid_type",
|
|
1418
|
+
input,
|
|
1419
|
+
inst
|
|
1420
|
+
});
|
|
1421
|
+
return payload;
|
|
1422
|
+
}
|
|
1423
|
+
const proms = [];
|
|
1424
|
+
const values = def.keyType._zod.values;
|
|
1425
|
+
if (values) {
|
|
1426
|
+
payload.value = {};
|
|
1427
|
+
const recordKeys = /* @__PURE__ */ new Set();
|
|
1428
|
+
for (const key of values) if (typeof key === "string" || typeof key === "number" || typeof key === "symbol") {
|
|
1429
|
+
recordKeys.add(typeof key === "number" ? key.toString() : key);
|
|
1430
|
+
const result = def.valueType._zod.run({
|
|
1431
|
+
value: input[key],
|
|
1432
|
+
issues: []
|
|
1433
|
+
}, ctx);
|
|
1434
|
+
if (result instanceof Promise) proms.push(result.then((result) => {
|
|
1435
|
+
if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues));
|
|
1436
|
+
payload.value[key] = result.value;
|
|
1437
|
+
}));
|
|
1438
|
+
else {
|
|
1439
|
+
if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues));
|
|
1440
|
+
payload.value[key] = result.value;
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
let unrecognized;
|
|
1444
|
+
for (const key in input) if (!recordKeys.has(key)) {
|
|
1445
|
+
unrecognized = unrecognized ?? [];
|
|
1446
|
+
unrecognized.push(key);
|
|
1447
|
+
}
|
|
1448
|
+
if (unrecognized && unrecognized.length > 0) payload.issues.push({
|
|
1449
|
+
code: "unrecognized_keys",
|
|
1450
|
+
input,
|
|
1451
|
+
inst,
|
|
1452
|
+
keys: unrecognized
|
|
1453
|
+
});
|
|
1454
|
+
} else {
|
|
1455
|
+
payload.value = {};
|
|
1456
|
+
for (const key of Reflect.ownKeys(input)) {
|
|
1457
|
+
if (key === "__proto__") continue;
|
|
1458
|
+
let keyResult = def.keyType._zod.run({
|
|
1459
|
+
value: key,
|
|
1460
|
+
issues: []
|
|
1461
|
+
}, ctx);
|
|
1462
|
+
if (keyResult instanceof Promise) throw new Error("Async schemas not supported in object keys currently");
|
|
1463
|
+
if (typeof key === "string" && number$1.test(key) && keyResult.issues.length) {
|
|
1464
|
+
const retryResult = def.keyType._zod.run({
|
|
1465
|
+
value: Number(key),
|
|
1466
|
+
issues: []
|
|
1467
|
+
}, ctx);
|
|
1468
|
+
if (retryResult instanceof Promise) throw new Error("Async schemas not supported in object keys currently");
|
|
1469
|
+
if (retryResult.issues.length === 0) keyResult = retryResult;
|
|
1470
|
+
}
|
|
1471
|
+
if (keyResult.issues.length) {
|
|
1472
|
+
if (def.mode === "loose") payload.value[key] = input[key];
|
|
1473
|
+
else payload.issues.push({
|
|
1474
|
+
code: "invalid_key",
|
|
1475
|
+
origin: "record",
|
|
1476
|
+
issues: keyResult.issues.map((iss) => finalizeIssue(iss, ctx, config())),
|
|
1477
|
+
input: key,
|
|
1478
|
+
path: [key],
|
|
1479
|
+
inst
|
|
1480
|
+
});
|
|
1481
|
+
continue;
|
|
1482
|
+
}
|
|
1483
|
+
const result = def.valueType._zod.run({
|
|
1484
|
+
value: input[key],
|
|
1485
|
+
issues: []
|
|
1486
|
+
}, ctx);
|
|
1487
|
+
if (result instanceof Promise) proms.push(result.then((result) => {
|
|
1488
|
+
if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues));
|
|
1489
|
+
payload.value[keyResult.value] = result.value;
|
|
1490
|
+
}));
|
|
1491
|
+
else {
|
|
1492
|
+
if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues));
|
|
1493
|
+
payload.value[keyResult.value] = result.value;
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
if (proms.length) return Promise.all(proms).then(() => payload);
|
|
1498
|
+
return payload;
|
|
1499
|
+
};
|
|
1500
|
+
});
|
|
1409
1501
|
const $ZodEnum = /* @__PURE__ */ $constructor("$ZodEnum", (inst, def) => {
|
|
1410
1502
|
$ZodType.init(inst, def);
|
|
1411
1503
|
const values = getEnumValues(def.entries);
|
|
@@ -2614,6 +2706,39 @@ const intersectionProcessor = (schema, ctx, json, params) => {
|
|
|
2614
2706
|
const isSimpleIntersection = (val) => "allOf" in val && Object.keys(val).length === 1;
|
|
2615
2707
|
json.allOf = [...isSimpleIntersection(a) ? a.allOf : [a], ...isSimpleIntersection(b) ? b.allOf : [b]];
|
|
2616
2708
|
};
|
|
2709
|
+
const recordProcessor = (schema, ctx, _json, params) => {
|
|
2710
|
+
const json = _json;
|
|
2711
|
+
const def = schema._zod.def;
|
|
2712
|
+
json.type = "object";
|
|
2713
|
+
const keyType = def.keyType;
|
|
2714
|
+
const patterns = keyType._zod.bag?.patterns;
|
|
2715
|
+
if (def.mode === "loose" && patterns && patterns.size > 0) {
|
|
2716
|
+
const valueSchema = process$1(def.valueType, ctx, {
|
|
2717
|
+
...params,
|
|
2718
|
+
path: [
|
|
2719
|
+
...params.path,
|
|
2720
|
+
"patternProperties",
|
|
2721
|
+
"*"
|
|
2722
|
+
]
|
|
2723
|
+
});
|
|
2724
|
+
json.patternProperties = {};
|
|
2725
|
+
for (const pattern of patterns) json.patternProperties[pattern.source] = valueSchema;
|
|
2726
|
+
} else {
|
|
2727
|
+
if (ctx.target === "draft-07" || ctx.target === "draft-2020-12") json.propertyNames = process$1(def.keyType, ctx, {
|
|
2728
|
+
...params,
|
|
2729
|
+
path: [...params.path, "propertyNames"]
|
|
2730
|
+
});
|
|
2731
|
+
json.additionalProperties = process$1(def.valueType, ctx, {
|
|
2732
|
+
...params,
|
|
2733
|
+
path: [...params.path, "additionalProperties"]
|
|
2734
|
+
});
|
|
2735
|
+
}
|
|
2736
|
+
const keyValues = keyType._zod.values;
|
|
2737
|
+
if (keyValues) {
|
|
2738
|
+
const validKeyValues = [...keyValues].filter((v) => typeof v === "string" || typeof v === "number");
|
|
2739
|
+
if (validKeyValues.length > 0) json.required = validKeyValues;
|
|
2740
|
+
}
|
|
2741
|
+
};
|
|
2617
2742
|
const nullableProcessor = (schema, ctx, json, params) => {
|
|
2618
2743
|
const def = schema._zod.def;
|
|
2619
2744
|
const inner = process$1(def.innerType, ctx, params);
|
|
@@ -3047,6 +3172,21 @@ function intersection(left, right) {
|
|
|
3047
3172
|
right
|
|
3048
3173
|
});
|
|
3049
3174
|
}
|
|
3175
|
+
const ZodRecord = /* @__PURE__ */ $constructor("ZodRecord", (inst, def) => {
|
|
3176
|
+
$ZodRecord.init(inst, def);
|
|
3177
|
+
ZodType.init(inst, def);
|
|
3178
|
+
inst._zod.processJSONSchema = (ctx, json, params) => recordProcessor(inst, ctx, json, params);
|
|
3179
|
+
inst.keyType = def.keyType;
|
|
3180
|
+
inst.valueType = def.valueType;
|
|
3181
|
+
});
|
|
3182
|
+
function record(keyType, valueType, params) {
|
|
3183
|
+
return new ZodRecord({
|
|
3184
|
+
type: "record",
|
|
3185
|
+
keyType,
|
|
3186
|
+
valueType,
|
|
3187
|
+
...normalizeParams(params)
|
|
3188
|
+
});
|
|
3189
|
+
}
|
|
3050
3190
|
const ZodEnum = /* @__PURE__ */ $constructor("ZodEnum", (inst, def) => {
|
|
3051
3191
|
$ZodEnum.init(inst, def);
|
|
3052
3192
|
ZodType.init(inst, def);
|
|
@@ -3299,6 +3439,7 @@ Fetch the full skill instructions with: prompts/get { name: "<skill-name>" }
|
|
|
3299
3439
|
| what's emerging, find patterns in vault | vault-emerge |
|
|
3300
3440
|
| find orphans, orphaned notes | vault-orphans |
|
|
3301
3441
|
| trace idea, how did X evolve | vault-trace |
|
|
3442
|
+
| run a worker, check workers, worker providers | worker |
|
|
3302
3443
|
|
|
3303
3444
|
### Reference Resources
|
|
3304
3445
|
|
|
@@ -4377,6 +4518,70 @@ Otherwise the open items live only in a session note nobody re-reads, which is t
|
|
|
4377
4518
|
`
|
|
4378
4519
|
};
|
|
4379
4520
|
|
|
4521
|
+
//#endregion
|
|
4522
|
+
//#region src/daemon-mcp/prompts/worker.ts
|
|
4523
|
+
const worker = {
|
|
4524
|
+
description: "Run, watch and route subagent workers on configured providers",
|
|
4525
|
+
content: `## Worker Skill
|
|
4526
|
+
|
|
4527
|
+
USE WHEN delegating subagent work, checking on running workers, or managing worker providers/classes from chat.
|
|
4528
|
+
|
|
4529
|
+
### Delegating
|
|
4530
|
+
|
|
4531
|
+
The Agent tool is denied when workers are on — delegate with Bash instead:
|
|
4532
|
+
|
|
4533
|
+
\`\`\`
|
|
4534
|
+
pai worker run --label "short task label" --class research \\
|
|
4535
|
+
-p '<full, self-contained task spec>' \\
|
|
4536
|
+
--allowedTools 'Read,Edit,Write,Bash,Grep,Glob' --output-format json
|
|
4537
|
+
\`\`\`
|
|
4538
|
+
|
|
4539
|
+
- Always run in background (run_in_background: true) and with a timeout.
|
|
4540
|
+
- Classes: draft (spec writing), plan, implement (default quality), review,
|
|
4541
|
+
research (web: add WebSearch,WebFetch), spotcheck (cheap/fast model), simple,
|
|
4542
|
+
complex, image. \`--role\` still works as an alias of \`--class\`.
|
|
4543
|
+
- Anything larger than a one-file change goes through a chain:
|
|
4544
|
+
\`pai worker run --chain draft,implement …\` — the draft stage turns the brief
|
|
4545
|
+
into a spec file, implement runs with it, \`--chain draft,implement,review\`
|
|
4546
|
+
adds a review pass. \`--class spotcheck\` for verification runs.
|
|
4547
|
+
- The answer is in the \`result\` field of the JSON it prints. Review the diff yourself.
|
|
4548
|
+
- \`--no-pane\` suppresses the iTerm follow pane; panes open automatically otherwise.
|
|
4549
|
+
- \`--agent <name>\` runs a definition from ~/.claude/agents/<name>.md (the agent
|
|
4550
|
+
library runs on workers: body becomes the system prompt, tools the allowlist,
|
|
4551
|
+
model the class).
|
|
4552
|
+
|
|
4553
|
+
### Watching
|
|
4554
|
+
|
|
4555
|
+
- \`worker_ps\` — running + last finished workers (chains show as trees).
|
|
4556
|
+
- \`worker_replay\` with id — the transcript of one worker.
|
|
4557
|
+
- CLI equivalents: \`pai worker ps\`, \`pai worker follow <id>\`.
|
|
4558
|
+
|
|
4559
|
+
### Routing
|
|
4560
|
+
|
|
4561
|
+
- \`worker_status\` — on/off, active provider, providers, run tally.
|
|
4562
|
+
- \`worker_providers\` — list/add/update/remove/use/enable/disable/test. Adding
|
|
4563
|
+
needs name, base_url, model and a key (key file path, or a raw key which is
|
|
4564
|
+
parked in ~/.config/pai/keys/<name>, mode 0600). update changes cost_tier
|
|
4565
|
+
(1 cheapest … 5 most expensive) and tags (code, vision, image-gen,
|
|
4566
|
+
long-context, fast, reasoning).
|
|
4567
|
+
- \`worker_classes\` — list/set/unset class → provider[/fast], or constraints
|
|
4568
|
+
only (max_cost_tier, require_tags) so auto-routing picks a qualifying provider.
|
|
4569
|
+
- \`worker_run\` — start a worker or chain from chat; returns the id immediately.
|
|
4570
|
+
- \`worker_toggle\` — off makes Agent subagents run on Anthropic again.
|
|
4571
|
+
|
|
4572
|
+
### Preferences from chat (map the phrase, use the tool, never mention files)
|
|
4573
|
+
|
|
4574
|
+
- "use <provider> for image generation" / "route research to <provider>" →
|
|
4575
|
+
worker_classes set <class>=<provider>. One line back.
|
|
4576
|
+
- "prefer the flash model for simple tasks" / "cheap only for drafts" →
|
|
4577
|
+
worker_classes set simple|draft=<provider>/fast (or a max_cost_tier). One line.
|
|
4578
|
+
- "reviews should use a reasoning model" → worker_classes set review with
|
|
4579
|
+
require_tags ["reasoning"] (drop the pin if one exists). One line.
|
|
4580
|
+
- "what handles reviews" / "show the routing table" → worker_classes list
|
|
4581
|
+
(plus worker_status for providers). One or two lines.
|
|
4582
|
+
- Never tell the user to edit a config file — the tools do it.`
|
|
4583
|
+
};
|
|
4584
|
+
|
|
4380
4585
|
//#endregion
|
|
4381
4586
|
//#region src/daemon-mcp/resources/aesthetic.ts
|
|
4382
4587
|
const aesthetic = {
|
|
@@ -5261,7 +5466,8 @@ async function startShim() {
|
|
|
5261
5466
|
"whisper": whisper,
|
|
5262
5467
|
"consolidate": consolidate,
|
|
5263
5468
|
"advisor": advisor,
|
|
5264
|
-
"tasks": tasks
|
|
5469
|
+
"tasks": tasks,
|
|
5470
|
+
"worker": worker
|
|
5265
5471
|
};
|
|
5266
5472
|
for (const [promptName, skill] of Object.entries(SKILL_PROMPTS)) server.prompt(promptName, skill.description, () => ({ messages: [{
|
|
5267
5473
|
role: "user",
|
|
@@ -5521,6 +5727,348 @@ async function startShim() {
|
|
|
5521
5727
|
top_k: number().int().min(1).max(100).optional().describe("Maximum KG triples to return after re-ranking. Default: 20."),
|
|
5522
5728
|
tenant_id: string().optional().describe("Tenant ID for entity lookup scoping. Default: 'default'.")
|
|
5523
5729
|
}, async (args) => proxyTool("memory_kg_search", args));
|
|
5730
|
+
const workerText = (s) => ({ content: [{
|
|
5731
|
+
type: "text",
|
|
5732
|
+
text: s
|
|
5733
|
+
}] });
|
|
5734
|
+
const workerError = (e) => ({
|
|
5735
|
+
content: [{
|
|
5736
|
+
type: "text",
|
|
5737
|
+
text: e instanceof Error ? e.message : String(e)
|
|
5738
|
+
}],
|
|
5739
|
+
isError: true
|
|
5740
|
+
});
|
|
5741
|
+
server.tool("worker_status", [
|
|
5742
|
+
"Show the worker system state: on/off, active provider, configured providers,",
|
|
5743
|
+
"roles, and today's run tally from the ledger.",
|
|
5744
|
+
"",
|
|
5745
|
+
"Use this before delegating with `pai worker run` to see what routing will choose."
|
|
5746
|
+
].join("\n"), {}, async () => {
|
|
5747
|
+
try {
|
|
5748
|
+
const { workers } = readWorkersSection();
|
|
5749
|
+
const s = ledgerSummary(ledgerPath(workersLogDir(workers)), "all", 10);
|
|
5750
|
+
const tally = s ? [`runs ${s.scope}: ${s.started} started, ${s.endedOk} ok, ${s.endedFailed} failed`, `agent hook: ${s.denied} denied, ${s.allowed} allowed, ${s.reroutes} reroutes`] : ["no runs recorded yet"];
|
|
5751
|
+
return workerText([
|
|
5752
|
+
`workers: ${workers.enabled ? "on" : "off"}`,
|
|
5753
|
+
`active provider: ${workers.active ?? "(none)"}`,
|
|
5754
|
+
...describeProviders(workers),
|
|
5755
|
+
"",
|
|
5756
|
+
...tally
|
|
5757
|
+
].join("\n"));
|
|
5758
|
+
} catch (e) {
|
|
5759
|
+
return workerError(e);
|
|
5760
|
+
}
|
|
5761
|
+
});
|
|
5762
|
+
server.tool("worker_providers", [
|
|
5763
|
+
"Manage worker providers (list, add, update, remove, use, enable, disable, test).",
|
|
5764
|
+
"",
|
|
5765
|
+
"action=list (default) shows providers (with cost tier and tags), classes and routing.",
|
|
5766
|
+
"action=add needs name, model — and either key_file or key, plus:",
|
|
5767
|
+
" base_url (anthropic protocol) or upstream_url (protocol=openai, runs",
|
|
5768
|
+
" through the local PAI proxy). A raw key is written to",
|
|
5769
|
+
" ~/.config/pai/keys/<name> (mode 0600); only the path lands in the config.",
|
|
5770
|
+
" engine=codex runs the Codex CLI instead of Claude Code.",
|
|
5771
|
+
"action=update changes cost_tier / tags of an existing provider.",
|
|
5772
|
+
"action=test runs a one-word pong probe through the provider",
|
|
5773
|
+
" (reports 'codex not installed' when that engine's CLI is missing)."
|
|
5774
|
+
].join("\n"), {
|
|
5775
|
+
action: _enum([
|
|
5776
|
+
"list",
|
|
5777
|
+
"add",
|
|
5778
|
+
"update",
|
|
5779
|
+
"remove",
|
|
5780
|
+
"use",
|
|
5781
|
+
"enable",
|
|
5782
|
+
"disable",
|
|
5783
|
+
"test"
|
|
5784
|
+
]).optional().describe("Default: list."),
|
|
5785
|
+
name: string().optional().describe("Provider name (required for every action but list)."),
|
|
5786
|
+
base_url: string().optional().describe("Anthropic-compatible API base URL (add)."),
|
|
5787
|
+
upstream_url: string().optional().describe("Chat Completions base URL (add, protocol=openai)."),
|
|
5788
|
+
protocol: _enum(["anthropic", "openai"]).optional().describe("Protocol (add). Default: anthropic."),
|
|
5789
|
+
engine: _enum(["claude", "codex"]).optional().describe("Runner engine (add). Default: claude."),
|
|
5790
|
+
context_window: number().int().positive().optional().describe("Context window for the meter (add). Default: 200000."),
|
|
5791
|
+
key_file: string().optional().describe("File holding the API token, 0600 (add)."),
|
|
5792
|
+
key: string().optional().describe("Raw API token (add) — parked in ~/.config/pai/keys/<name>."),
|
|
5793
|
+
model: string().optional().describe("Default model id (add)."),
|
|
5794
|
+
fast_model: string().optional().describe("Cheaper model for spotchecks (add, optional)."),
|
|
5795
|
+
env: record(string(), string()).optional().describe("Extra env for runs (add, optional)."),
|
|
5796
|
+
note: string().optional().describe("Human note shown in listings (add, optional)."),
|
|
5797
|
+
quota_probe: string().optional().describe("URL whose JSON first number is the quota percent (add, optional)."),
|
|
5798
|
+
cost_tier: number().int().min(1).max(5).optional().describe("Cost tier 1 (cheapest) … 5 (most expensive). Default 3. (add, update)"),
|
|
5799
|
+
tags: array(_enum([
|
|
5800
|
+
"code",
|
|
5801
|
+
"vision",
|
|
5802
|
+
"image-gen",
|
|
5803
|
+
"long-context",
|
|
5804
|
+
"fast",
|
|
5805
|
+
"reasoning"
|
|
5806
|
+
])).optional().describe("Capability tags (add, update).")
|
|
5807
|
+
}, async (args) => {
|
|
5808
|
+
try {
|
|
5809
|
+
const action = args.action ?? "list";
|
|
5810
|
+
if (action === "list") return workerText(describeProviders(readWorkersSection().workers).join("\n"));
|
|
5811
|
+
if (!args.name) return workerError(/* @__PURE__ */ new Error("name is required for this action"));
|
|
5812
|
+
if (action === "update") {
|
|
5813
|
+
if (args.cost_tier === void 0 && args.tags === void 0) return workerError(/* @__PURE__ */ new Error("update needs cost_tier and/or tags"));
|
|
5814
|
+
updateProvider(args.name, {
|
|
5815
|
+
...args.cost_tier !== void 0 ? { costTier: args.cost_tier } : {},
|
|
5816
|
+
...args.tags !== void 0 ? { tags: args.tags } : {}
|
|
5817
|
+
});
|
|
5818
|
+
return workerText([`provider ${args.name} updated`, ...describeProviders(readWorkersSection().workers)].join("\n"));
|
|
5819
|
+
}
|
|
5820
|
+
if (action === "add") {
|
|
5821
|
+
if (!args.model) return workerError(/* @__PURE__ */ new Error("add needs model"));
|
|
5822
|
+
if (args.protocol !== "openai" && !args.base_url) return workerError(/* @__PURE__ */ new Error("add needs base_url (only protocol=openai goes without it)"));
|
|
5823
|
+
const workers = addProvider({
|
|
5824
|
+
name: args.name,
|
|
5825
|
+
baseUrl: args.base_url ?? "",
|
|
5826
|
+
keyFile: args.key_file ?? null,
|
|
5827
|
+
...args.key !== void 0 ? { key: args.key } : {},
|
|
5828
|
+
model: args.model,
|
|
5829
|
+
...args.fast_model ? { fastModel: args.fast_model } : {},
|
|
5830
|
+
env: args.env ?? {},
|
|
5831
|
+
...args.note ? { note: args.note } : {},
|
|
5832
|
+
...args.protocol ? { protocol: args.protocol } : {},
|
|
5833
|
+
...args.upstream_url ? { upstreamUrl: args.upstream_url } : {},
|
|
5834
|
+
...args.engine ? { engine: args.engine } : {},
|
|
5835
|
+
...args.context_window ? { contextWindow: args.context_window } : {},
|
|
5836
|
+
...args.quota_probe ? { quotaProbe: args.quota_probe } : {},
|
|
5837
|
+
...args.cost_tier !== void 0 ? { costTier: args.cost_tier } : {},
|
|
5838
|
+
...args.tags?.length ? { tags: args.tags } : {}
|
|
5839
|
+
});
|
|
5840
|
+
return workerText([`provider ${args.name} added; active: ${workers.active ?? "(none)"}; workers ${workers.enabled ? "on" : "off"}`, ...describeProviders(workers)].join("\n"));
|
|
5841
|
+
}
|
|
5842
|
+
if (action === "remove") {
|
|
5843
|
+
removeProvider(args.name);
|
|
5844
|
+
return workerText(`provider ${args.name} removed`);
|
|
5845
|
+
}
|
|
5846
|
+
if (action === "use") {
|
|
5847
|
+
useProvider(args.name);
|
|
5848
|
+
return workerText(`active provider: ${args.name}`);
|
|
5849
|
+
}
|
|
5850
|
+
if (action === "enable" || action === "disable") {
|
|
5851
|
+
setProviderEnabled(args.name, action === "enable");
|
|
5852
|
+
return workerText(`provider ${args.name} ${action}d`);
|
|
5853
|
+
}
|
|
5854
|
+
const { workers } = readWorkersSection();
|
|
5855
|
+
const p = workers.providers[args.name];
|
|
5856
|
+
if (!p) return workerError(/* @__PURE__ */ new Error(`no provider named "${args.name}"`));
|
|
5857
|
+
const r = await testProvider(args.name, p, workersLogDir(workers));
|
|
5858
|
+
if (r.skipped) return workerText(`${r.provider} ${r.model} ${r.skipped}\nreply: ${r.result.slice(0, 200)}`);
|
|
5859
|
+
return workerText(`${r.provider} ${r.model} ${(r.latencyMs / 1e3).toFixed(1)}s\nreply: ${r.result.slice(0, 200)}\n${r.ok ? "OK" : "FAILED"}`);
|
|
5860
|
+
} catch (e) {
|
|
5861
|
+
return workerError(e);
|
|
5862
|
+
}
|
|
5863
|
+
});
|
|
5864
|
+
server.tool("worker_classes", [
|
|
5865
|
+
"Manage worker classes (list, set, unset).",
|
|
5866
|
+
"",
|
|
5867
|
+
"A class maps a task class to a provider, optionally its fast model:",
|
|
5868
|
+
"implement=glm, research=glm, spotcheck=glm/fast.",
|
|
5869
|
+
"set can instead give routing constraints only (max_cost_tier,",
|
|
5870
|
+
"require_tags) — auto-routing then picks a qualifying provider.",
|
|
5871
|
+
"Runs pick the provider via --class first, then the active provider."
|
|
5872
|
+
].join("\n"), {
|
|
5873
|
+
action: _enum([
|
|
5874
|
+
"list",
|
|
5875
|
+
"set",
|
|
5876
|
+
"unset"
|
|
5877
|
+
]).optional().describe("Default: list."),
|
|
5878
|
+
class: string().optional().describe("Class name (set/unset), e.g. implement, spotcheck."),
|
|
5879
|
+
target: string().optional().describe("Provider or provider/fast (set)."),
|
|
5880
|
+
max_cost_tier: number().int().min(1).max(5).optional().describe("Auto-routing considers only providers up to this cost tier (set)."),
|
|
5881
|
+
require_tags: array(_enum([
|
|
5882
|
+
"code",
|
|
5883
|
+
"vision",
|
|
5884
|
+
"image-gen",
|
|
5885
|
+
"long-context",
|
|
5886
|
+
"fast",
|
|
5887
|
+
"reasoning"
|
|
5888
|
+
])).optional().describe("Auto-routing needs these tags (set).")
|
|
5889
|
+
}, async (args) => {
|
|
5890
|
+
try {
|
|
5891
|
+
const action = args.action ?? "list";
|
|
5892
|
+
if (action === "list") {
|
|
5893
|
+
const { workers } = readWorkersSection();
|
|
5894
|
+
const entries = Object.entries(workers.classes);
|
|
5895
|
+
return workerText(entries.length ? entries.map(([cls, t]) => `${cls}: ${classTargetText(t)}`).join("\n") : "no classes set");
|
|
5896
|
+
}
|
|
5897
|
+
if (!args.class) return workerError(/* @__PURE__ */ new Error("class is required for this action"));
|
|
5898
|
+
if (action === "set") {
|
|
5899
|
+
const hasConstraints = args.max_cost_tier !== void 0 || args.require_tags !== void 0;
|
|
5900
|
+
if (!args.target && !hasConstraints) return workerError(/* @__PURE__ */ new Error("set needs target provider[/fast] and/or max_cost_tier/require_tags"));
|
|
5901
|
+
const target = args.target !== void 0 && !hasConstraints ? args.target : {
|
|
5902
|
+
...args.target ? { provider: args.target.split("/")[0] } : {},
|
|
5903
|
+
...args.max_cost_tier !== void 0 ? { maxCostTier: args.max_cost_tier } : {},
|
|
5904
|
+
...args.require_tags !== void 0 ? { requireTags: args.require_tags } : {}
|
|
5905
|
+
};
|
|
5906
|
+
setClass(args.class, target);
|
|
5907
|
+
return workerText(`class ${args.class} → ${classTargetText(target)}`);
|
|
5908
|
+
}
|
|
5909
|
+
unsetClass(args.class);
|
|
5910
|
+
return workerText(`class ${args.class} removed`);
|
|
5911
|
+
} catch (e) {
|
|
5912
|
+
return workerError(e);
|
|
5913
|
+
}
|
|
5914
|
+
});
|
|
5915
|
+
server.tool("worker_run", [
|
|
5916
|
+
"Start a worker (or a chain) and return its id immediately.",
|
|
5917
|
+
"",
|
|
5918
|
+
"This is the chat-side face of `pai worker run`: prompt is required,",
|
|
5919
|
+
"chain (e.g. \"draft,implement\") runs spec-first stages, class picks the",
|
|
5920
|
+
"provider (default: active). Check on it with worker_ps / worker_replay,",
|
|
5921
|
+
"talk to it with worker_say."
|
|
5922
|
+
].join("\n"), {
|
|
5923
|
+
prompt: string().min(1).describe("The task (the -p value)."),
|
|
5924
|
+
chain: string().optional().describe("Comma-separated stages, e.g. draft,implement or draft,implement,review."),
|
|
5925
|
+
class: string().optional().describe("Task class (draft, implement, review, research, spotcheck, simple, complex, image)."),
|
|
5926
|
+
label: string().optional().describe("Short task label shown in worker_ps."),
|
|
5927
|
+
cwd: string().optional().describe("Working directory (default: here)."),
|
|
5928
|
+
allowed_tools: string().optional().describe("Comma-separated tool allowlist passed to the worker."),
|
|
5929
|
+
mcp: string().optional().describe("MCP servers/sets the worker may use (comma-separated).")
|
|
5930
|
+
}, async (args) => {
|
|
5931
|
+
try {
|
|
5932
|
+
const claudeArgs = [
|
|
5933
|
+
"-p",
|
|
5934
|
+
args.prompt,
|
|
5935
|
+
...args.allowed_tools ? ["--allowedTools", args.allowed_tools] : []
|
|
5936
|
+
];
|
|
5937
|
+
let startedIdResolve;
|
|
5938
|
+
let startupFailure = null;
|
|
5939
|
+
const idArrived = new Promise((resolve) => {
|
|
5940
|
+
startedIdResolve = resolve;
|
|
5941
|
+
});
|
|
5942
|
+
const background = async () => {
|
|
5943
|
+
if (args.chain) return runChain({
|
|
5944
|
+
stages: args.chain.split(","),
|
|
5945
|
+
className: args.class,
|
|
5946
|
+
label: args.label,
|
|
5947
|
+
noPane: false,
|
|
5948
|
+
mcpFlag: args.mcp,
|
|
5949
|
+
brief: args.prompt,
|
|
5950
|
+
claudeArgs,
|
|
5951
|
+
...args.cwd ? { cwd: args.cwd } : {},
|
|
5952
|
+
onChainStart: (id) => startedIdResolve(id),
|
|
5953
|
+
quiet: true
|
|
5954
|
+
});
|
|
5955
|
+
return runWorker({
|
|
5956
|
+
className: args.class,
|
|
5957
|
+
label: args.label,
|
|
5958
|
+
noPane: false,
|
|
5959
|
+
mcpFlag: args.mcp,
|
|
5960
|
+
claudeArgs,
|
|
5961
|
+
...args.cwd ? { cwd: args.cwd } : {},
|
|
5962
|
+
onWorkerStart: (wid) => startedIdResolve(wid),
|
|
5963
|
+
quiet: true
|
|
5964
|
+
});
|
|
5965
|
+
};
|
|
5966
|
+
background().catch((e) => {
|
|
5967
|
+
startupFailure = e;
|
|
5968
|
+
startedIdResolve("");
|
|
5969
|
+
});
|
|
5970
|
+
const id = await Promise.race([idArrived, new Promise((_, reject) => setTimeout(() => reject(/* @__PURE__ */ new Error("worker did not start within 15s")), 15e3))]);
|
|
5971
|
+
if (!id) return workerError(startupFailure ?? /* @__PURE__ */ new Error("worker failed to start"));
|
|
5972
|
+
return workerText(`${id} started${args.chain ? ` (chain: ${args.chain})` : ""} — check on it with worker_ps, worker_replay, worker_say`);
|
|
5973
|
+
} catch (e) {
|
|
5974
|
+
return workerError(e);
|
|
5975
|
+
}
|
|
5976
|
+
});
|
|
5977
|
+
server.tool("worker_toggle", [
|
|
5978
|
+
"Turn worker routing on or off.",
|
|
5979
|
+
"",
|
|
5980
|
+
"off: the Agent-tool hook stops denying, subagents run on Anthropic.",
|
|
5981
|
+
"on: subagents are denied and rewritten to `pai worker run`."
|
|
5982
|
+
].join("\n"), { enabled: boolean().describe("true = route subagents to workers, false = Anthropic.") }, async (args) => {
|
|
5983
|
+
try {
|
|
5984
|
+
const workers = setWorkersEnabled(args.enabled);
|
|
5985
|
+
return workerText(`workers ${workers.enabled ? "on" : "off"} — Agent subagents ${workers.enabled ? "denied and rewritten to `pai worker run`" : "run on Anthropic"}`);
|
|
5986
|
+
} catch (e) {
|
|
5987
|
+
return workerError(e);
|
|
5988
|
+
}
|
|
5989
|
+
});
|
|
5990
|
+
server.tool("worker_ps", [
|
|
5991
|
+
"List workers: running (id, provider, age, turns, current tool) and the last finished.",
|
|
5992
|
+
"",
|
|
5993
|
+
"Use this to check on delegated `pai worker run` calls; worker_replay shows",
|
|
5994
|
+
"the transcript of one worker."
|
|
5995
|
+
].join("\n"), { all: boolean().optional().describe("Show workers of all sessions (default: this one's).") }, async (args) => {
|
|
5996
|
+
try {
|
|
5997
|
+
const { workers } = readWorkersSection();
|
|
5998
|
+
return workerText(psOutput(workersLogDir(workers), args.all === true, {}, false));
|
|
5999
|
+
} catch (e) {
|
|
6000
|
+
return workerError(e);
|
|
6001
|
+
}
|
|
6002
|
+
});
|
|
6003
|
+
server.tool("worker_replay", [
|
|
6004
|
+
"Replay the transcript of one worker: tool calls, short outputs, result.",
|
|
6005
|
+
"",
|
|
6006
|
+
"Plain text, no colors. Use tail to cap the output."
|
|
6007
|
+
].join("\n"), {
|
|
6008
|
+
id: string().describe("Worker id (as shown by worker_ps)."),
|
|
6009
|
+
tail: number().int().min(1).max(2e3).optional().describe("Last N rendered lines. Default: all.")
|
|
6010
|
+
}, async (args) => {
|
|
6011
|
+
try {
|
|
6012
|
+
const { workers } = readWorkersSection();
|
|
6013
|
+
return workerText(replayOutput(workersLogDir(workers), args.id, false, args.tail));
|
|
6014
|
+
} catch (e) {
|
|
6015
|
+
return workerError(e);
|
|
6016
|
+
}
|
|
6017
|
+
});
|
|
6018
|
+
server.tool("worker_say", [
|
|
6019
|
+
"Send one message to a RUNNING worker: it lands on the worker's open stdin",
|
|
6020
|
+
"as a user message, mid-run, without breaking its stream.",
|
|
6021
|
+
"",
|
|
6022
|
+
"Fails with an explanation when the worker already finished — then use",
|
|
6023
|
+
"worker_resume (or `pai worker resume <id> \"text\"`) instead."
|
|
6024
|
+
].join("\n"), {
|
|
6025
|
+
id: string().describe("Worker id (as shown by worker_ps)."),
|
|
6026
|
+
text: string().min(1).describe("The message to send (one line).")
|
|
6027
|
+
}, async (args) => {
|
|
6028
|
+
try {
|
|
6029
|
+
const { workers } = readWorkersSection();
|
|
6030
|
+
await sayToWorker(workersLogDir(workers), args.id, args.text);
|
|
6031
|
+
return workerText(`sent to ${args.id}`);
|
|
6032
|
+
} catch (e) {
|
|
6033
|
+
return workerError(e);
|
|
6034
|
+
}
|
|
6035
|
+
});
|
|
6036
|
+
server.tool("worker_resume", [
|
|
6037
|
+
"Continue a FINISHED worker with a follow-up message: claude --resume on the",
|
|
6038
|
+
"same provider, same Claude session, context intact.",
|
|
6039
|
+
"",
|
|
6040
|
+
"Returns the new worker id. Not for running workers — say to those instead."
|
|
6041
|
+
].join("\n"), {
|
|
6042
|
+
id: string().describe("Worker id of the finished run (as shown by worker_ps)."),
|
|
6043
|
+
text: string().min(1).describe("The follow-up message.")
|
|
6044
|
+
}, async (args) => {
|
|
6045
|
+
try {
|
|
6046
|
+
const { workers } = readWorkersSection();
|
|
6047
|
+
const old = loadStatus(workersLogDir(workers), args.id);
|
|
6048
|
+
if (!old) return workerError(/* @__PURE__ */ new Error(`no worker named "${args.id}"`));
|
|
6049
|
+
if (old.state === "running") return workerError(/* @__PURE__ */ new Error(`worker ${args.id} is still running — send messages with worker_say`));
|
|
6050
|
+
if (!old.claudeSession) return workerError(/* @__PURE__ */ new Error(`worker ${args.id} recorded no Claude session id — it predates resume support or ran through an engine that does not expose one`));
|
|
6051
|
+
let newId = "";
|
|
6052
|
+
const rc = await runWorker({
|
|
6053
|
+
providerFlag: old.provider,
|
|
6054
|
+
modelFlag: old.model,
|
|
6055
|
+
label: `↩ ${old.label}`,
|
|
6056
|
+
noPane: true,
|
|
6057
|
+
claudeArgs: [
|
|
6058
|
+
"--resume",
|
|
6059
|
+
old.claudeSession,
|
|
6060
|
+
"-p",
|
|
6061
|
+
args.text
|
|
6062
|
+
],
|
|
6063
|
+
onWorkerStart: (wid) => {
|
|
6064
|
+
newId = wid;
|
|
6065
|
+
}
|
|
6066
|
+
});
|
|
6067
|
+
return workerText(`resumed ${args.id} as ${newId || "(unknown id)"} — rc=${rc}\ncheck on it with worker_ps / worker_replay`);
|
|
6068
|
+
} catch (e) {
|
|
6069
|
+
return workerError(e);
|
|
6070
|
+
}
|
|
6071
|
+
});
|
|
5524
6072
|
const transport = new StdioServerTransport();
|
|
5525
6073
|
await server.connect(transport);
|
|
5526
6074
|
}
|