@tekmidian/pai 0.38.0 → 0.39.1

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 (84) hide show
  1. package/dist/{auto-route-DM7GhJ8y.mjs → auto-route-BlWOWT4z.mjs} +2 -2
  2. package/dist/{auto-route-DM7GhJ8y.mjs.map → auto-route-BlWOWT4z.mjs.map} +1 -1
  3. package/dist/{providers-DUshcB-d.mjs → chain-CqlgL7uH.mjs} +734 -1410
  4. package/dist/chain-CqlgL7uH.mjs.map +1 -0
  5. package/dist/cli/index.mjs +4 -3
  6. package/dist/cli/index.mjs.map +1 -1
  7. package/dist/cli/program.mjs +4 -3
  8. package/dist/{clusters-Do4tEGyc.mjs → clusters-wlK0w41E.mjs} +1 -1
  9. package/dist/{clusters-Do4tEGyc.mjs.map → clusters-wlK0w41E.mjs.map} +1 -1
  10. package/dist/daemon/index.mjs +7 -7
  11. package/dist/{daemon-CGg1VCbA.mjs → daemon-CTkN_Vn8.mjs} +25 -25
  12. package/dist/{daemon-CGg1VCbA.mjs.map → daemon-CTkN_Vn8.mjs.map} +1 -1
  13. package/dist/{daemon-DsGGiIJM.mjs → daemon-CmHHmKpg.mjs} +7 -7
  14. package/dist/daemon-mcp/index.mjs +106 -3
  15. package/dist/daemon-mcp/index.mjs.map +1 -1
  16. package/dist/{detector-CMap-9vw.mjs → detector-Bwk_4Pk4.mjs} +1 -1
  17. package/dist/{detector-CMap-9vw.mjs.map → detector-Bwk_4Pk4.mjs.map} +1 -1
  18. package/dist/detector-DO730Zq0.mjs +5 -0
  19. package/dist/{factory-DD2T33C9.mjs → factory-A9x-T2Kg.mjs} +5 -5
  20. package/dist/{factory-DD2T33C9.mjs.map → factory-A9x-T2Kg.mjs.map} +1 -1
  21. package/dist/factory-BD-np0Vd.mjs +3 -0
  22. package/dist/fallback-DqYhiACU.mjs +1675 -0
  23. package/dist/fallback-DqYhiACU.mjs.map +1 -0
  24. package/dist/hooks/route-agents-to-worker.mjs +73 -8
  25. package/dist/hooks/route-agents-to-worker.mjs.map +2 -2
  26. package/dist/hooks/worker-proxy.mjs +71 -6
  27. package/dist/hooks/worker-proxy.mjs.map +2 -2
  28. package/dist/hooks/worker-status-line.mjs +137 -11
  29. package/dist/hooks/worker-status-line.mjs.map +4 -4
  30. package/dist/{indexer-backend-Cox9BCo-.mjs → indexer-backend-TG64CCQC.mjs} +1 -1
  31. package/dist/{indexer-backend-Cox9BCo-.mjs.map → indexer-backend-TG64CCQC.mjs.map} +1 -1
  32. package/dist/{latent-ideas-BC1oINZ-.mjs → latent-ideas-B7wq75Pt.mjs} +2 -2
  33. package/dist/{latent-ideas-BC1oINZ-.mjs.map → latent-ideas-B7wq75Pt.mjs.map} +1 -1
  34. package/dist/{link-boost-QFLrJwD6.mjs → link-boost-HkG7JWZR.mjs} +1 -1
  35. package/dist/{link-boost-QFLrJwD6.mjs.map → link-boost-HkG7JWZR.mjs.map} +1 -1
  36. package/dist/{neighborhood-D9MJ1c8f.mjs → neighborhood-lThN-MaQ.mjs} +1 -1
  37. package/dist/{neighborhood-D9MJ1c8f.mjs.map → neighborhood-lThN-MaQ.mjs.map} +1 -1
  38. package/dist/{note-context-d1wT_-GA.mjs → note-context-b6k0mAKi.mjs} +1 -1
  39. package/dist/{note-context-d1wT_-GA.mjs.map → note-context-b6k0mAKi.mjs.map} +1 -1
  40. package/dist/planner-DGV8VFib.mjs +243 -0
  41. package/dist/planner-DGV8VFib.mjs.map +1 -0
  42. package/dist/{postgres--BjPtLa0.mjs → postgres-mW1n7Vi1.mjs} +1 -1
  43. package/dist/{postgres--BjPtLa0.mjs.map → postgres-mW1n7Vi1.mjs.map} +1 -1
  44. package/dist/{program-Y0hAiVy8.mjs → program-B-QJXCRb.mjs} +95 -19
  45. package/dist/{program-Y0hAiVy8.mjs.map → program-B-QJXCRb.mjs.map} +1 -1
  46. package/dist/{query-feedback-BUJxgw5B.mjs → query-feedback-BV4CcxqS.mjs} +1 -1
  47. package/dist/{query-feedback-BUJxgw5B.mjs.map → query-feedback-BV4CcxqS.mjs.map} +1 -1
  48. package/dist/query-feedback-DSVyHtrG.mjs +3 -0
  49. package/dist/router-Bk77E7hj.mjs +3 -0
  50. package/dist/{router-DK_sLsUL.mjs → router-DcHKnEPa.mjs} +1 -1
  51. package/dist/{router-DK_sLsUL.mjs.map → router-DcHKnEPa.mjs.map} +1 -1
  52. package/dist/skills/Worker/SKILL.md +13 -0
  53. package/dist/{sources-Bi7--33T.mjs → sources-kLnQsNrW.mjs} +1 -1
  54. package/dist/{sources-Bi7--33T.mjs.map → sources-kLnQsNrW.mjs.map} +1 -1
  55. package/dist/{sqlite-DtaL1glm.mjs → sqlite-BenGr3UP.mjs} +1 -1
  56. package/dist/{sqlite-DtaL1glm.mjs.map → sqlite-BenGr3UP.mjs.map} +1 -1
  57. package/dist/{state-BY2L6-vX.mjs → state-CAeyOdfq.mjs} +1 -1
  58. package/dist/{state-BY2L6-vX.mjs.map → state-CAeyOdfq.mjs.map} +1 -1
  59. package/dist/{state-8Hm9E4tW.mjs → state-Ca9F_sZc.mjs} +1 -1
  60. package/dist/{themes-BN0a2duq.mjs → themes-BI4GMRP9.mjs} +1 -1
  61. package/dist/{themes-BN0a2duq.mjs.map → themes-BI4GMRP9.mjs.map} +1 -1
  62. package/dist/{tools-CGPqpU3A.mjs → tools-Bp7hj6OW.mjs} +1 -1
  63. package/dist/{tools-y2bJpKom.mjs → tools-DGcB3o_S.mjs} +13 -13
  64. package/dist/{tools-y2bJpKom.mjs.map → tools-DGcB3o_S.mjs.map} +1 -1
  65. package/dist/{trace-h23JCcFD.mjs → trace-bobARFEX.mjs} +1 -1
  66. package/dist/{trace-h23JCcFD.mjs.map → trace-bobARFEX.mjs.map} +1 -1
  67. package/dist/{vault-indexer-DgsPjMgs.mjs → vault-indexer-C3OfXTNF.mjs} +1 -1
  68. package/dist/{vault-indexer-DgsPjMgs.mjs.map → vault-indexer-C3OfXTNF.mjs.map} +1 -1
  69. package/dist/{work-queue-worker-gsKd2LJa.mjs → work-queue-worker-DW8lz-Oo.mjs} +3 -3
  70. package/dist/{work-queue-worker-Dva_v_pI.mjs → work-queue-worker-R7UGIag_.mjs} +3 -3
  71. package/dist/{work-queue-worker-Dva_v_pI.mjs.map → work-queue-worker-R7UGIag_.mjs.map} +1 -1
  72. package/dist/{zettelkasten-vo7psPdT.mjs → zettelkasten-m5QPtb-L.mjs} +3 -3
  73. package/dist/{zettelkasten-vo7psPdT.mjs.map → zettelkasten-m5QPtb-L.mjs.map} +1 -1
  74. package/docs/commands/README.md +5 -0
  75. package/docs/commands/worker.md +74 -0
  76. package/docs/worker.md +132 -1
  77. package/package.json +1 -1
  78. package/src/hooks/ts/pre-tool-use/route-agents-to-worker.ts +2 -2
  79. package/dist/detector-DtLExmHN.mjs +0 -5
  80. package/dist/factory-BXzqRYVZ.mjs +0 -3
  81. package/dist/providers-DUshcB-d.mjs.map +0 -1
  82. package/dist/query-feedback-DhyLOe5S.mjs +0 -3
  83. package/dist/router-1zi8jiNF.mjs +0 -3
  84. /package/dist/{main-resolver-IhZo4pI0.mjs → main-resolver-D6IImXvF.mjs} +0 -0
package/docs/worker.md CHANGED
@@ -265,6 +265,49 @@ A quota failure before the first tool call is re-run on the next provider and
265
265
  logged as `WORKER-REROUTE`. `pai worker providers enable <name>` clears a
266
266
  cooldown by hand.
267
267
 
268
+ ## When the Anthropic plan runs out
269
+
270
+ `pai worker fallback on [provider]` switches the whole machine: every NEW
271
+ Claude Code process — interactive sessions, task-bus sessions, the daemon's
272
+ headless summarizer — runs on that worker provider instead of the Anthropic
273
+ login, until `pai worker fallback off`. Use it when the plan budget is gone
274
+ but work must continue.
275
+
276
+ What `on` does:
277
+
278
+ - Writes the provider into the `env` block of `~/.claude/settings.json`:
279
+ `ANTHROPIC_BASE_URL`, `ANTHROPIC_AUTH_TOKEN`, the three
280
+ `ANTHROPIC_DEFAULT_*_MODEL` pins (fast model as haiku, default as sonnet
281
+ and opus), the provider's own env (`API_TIMEOUT_MS` …), plus
282
+ `ENABLE_TOOL_SEARCH=true` and
283
+ `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1`.
284
+ - Pins the top-level `model` key to the provider's default model.
285
+ - Saves the replaced values under `workers.fallback.saved` in
286
+ `~/.config/pai/config.json` and writes a `FALLBACK-ACTIVE.md` note into the
287
+ workers log dir telling running sessions what to do.
288
+
289
+ Notes:
290
+
291
+ - **The token sits in settings.json.** `on` reads it from the provider's key
292
+ file at switch time; `off` removes it again. That is the price of switching
293
+ every process without touching each one's environment.
294
+ - `off` restores settings.json exactly — only the keys `on` touched change.
295
+ Both files are written atomically; `CLAUDE_SETTINGS_PATH` points `on`/`off`
296
+ at a copy for dry runs.
297
+ - **Running sessions are not switched.** A Claude Code process keeps the
298
+ provider it started with until restarted. `pai worker fallback status`
299
+ lists running sessions (AIBroker registry when populated, else `ps`) and
300
+ the note path; its one-line instruction for each of them: restart the
301
+ session in its project directory, keep the same AIBroker name.
302
+ - The Agent hook is unchanged: subagents keep routing to `pai worker run`
303
+ workers, which set their own per-provider env.
304
+ - `on` is idempotent (re-applying heals an interrupted switch), and switching
305
+ providers while on restores the first switch's savings before saving fresh.
306
+ - MCP: `worker_fallback` (action `on`/`off`/`status`, optional `provider`);
307
+ chat phrases "switch everything to glm", "fallback on", "back to
308
+ anthropic", "fallback off", "is fallback on" are mapped in the Worker
309
+ skill.
310
+
268
311
  ## What a worker is
269
312
 
270
313
  - One `claude -p … --output-format stream-json --verbose` process per call,
@@ -335,6 +378,92 @@ Ctrl-D leaves. The auto-exit countdown never fires while the prompt holds
335
378
  unsent text. Without a TTY (piped output) the pane keeps the plain scrolling
336
379
  behaviour — no prompt row, no ticker, stdin still the operator channel.
337
380
 
381
+ ### Sub-workers and handoffs
382
+
383
+ Any worker may start its own workers: the runner exports `PAI_WORKER_ID` in
384
+ every worker's environment, and a `pai worker run` launched from inside one
385
+ records `parent` in its status — so the forest is visible in `ps` (children
386
+ indented under their parent, `├`/`└` connectors), the status line (`↳` under
387
+ the parent) and each child gets its own follow pane. Handoffs travel **up
388
+ only**, from a child to its parent:
389
+
390
+ ```
391
+ pai worker handoff '{"kind":"proposal","text":"run this on a cheap provider","data":{…}}'
392
+ ```
393
+
394
+ (or the MCP tool `worker_handoff`; kinds `proposal`, `question`, `blocker` —
395
+ `result` is sent automatically when a child finishes). The handoff is appended
396
+ to `<logDir>/<parent>.inbox.jsonl` (durable, ordered) and, when the parent is
397
+ running, also delivered as an operator message `[handoff from <child id>]`. The
398
+ parent sees it in its pane (`◆ from <id> · kind: text`, magenta), `ps` and the
399
+ status line show `◆N` for an inbox with N handoffs, and `replay`/`follow`
400
+ merge them into the transcript by timestamp. There is no sideways channel:
401
+ siblings never see each other, everything goes up.
402
+
403
+ Two caps keep the tree bounded (`workers.tree`):
404
+
405
+ - `maxDepth` (default 2) — how deep sub-workers may nest; a launch one level
406
+ past the cap fails with a message that suggests a handoff instead,
407
+ - `maxChildren` (default 4) — how many children of one parent may run at the
408
+ same time (finished children do not count).
409
+
410
+ Chain stages and planner sub-tasks carry a parent too, but a parent without a
411
+ status file (a chain id) is not a worker and is never capped by depth.
412
+
413
+ ### Worktrees and merge
414
+
415
+ A run whose class writes files (`implement`, `complex`, `plan`) in a git repo,
416
+ with a prompt that is not read-only, gets **its own git worktree** by default:
417
+ `<logDir>/worktrees/<id>` on branch `worker/<id>` from the current HEAD. The
418
+ worker commits its work on that branch (the no-commit rule applies to the main
419
+ branch only — the appended system prompt says so); when git refuses (no
420
+ commits yet, detached setup) the run degrades to in place with a note on
421
+ stderr and in the ledger.
422
+
423
+ ```
424
+ pai worker merge <id> # git merge --no-ff worker/<id> + remove the worktree
425
+ pai worker discard <id> # remove worktree and branch, keep nothing
426
+ ```
427
+
428
+ `ps` marks a worker with an unmerged branch `⎇<commits>` (yellow); the status
429
+ file records `branch`, `commits` and `worktreeDir`. Chains give a worktree to
430
+ the implement stage only; `--worktree` forces one on, `--no-worktree` opts
431
+ out.
432
+
433
+ ### The planner class
434
+
435
+ `--class plan` runs a small orchestration, not one worker:
436
+
437
+ 1. a planner worker reads the repository and writes
438
+ `<logDir>/plans/<planner id>.json` — sub-tasks (`title`, `brief`, `class`,
439
+ `files`, `acceptance`), 5–50 of them, fewer only when the goal names a
440
+ smaller count;
441
+ 2. the runner validates the plan and spawns the sub-tasks as children of the
442
+ planner, at most `workers.tree.maxChildren` at a time;
443
+ 3. each child's structured report arrives in the planner's inbox as a
444
+ `kind: "result"` handoff;
445
+ 4. the run finishes with a summary report (`n/m sub-tasks ok`) and the
446
+ `pai worker merge` lines for any unmerged branches.
447
+
448
+ The planner's prompt carries the prompt rules that make plans executable:
449
+ domain-specific instructions only (real files, real commands), constraints
450
+ over step lists, explicit quantity ranges, no checkbox style.
451
+
452
+ ### Clickr controls (desktop set)
453
+
454
+ The default `mcpSets` ship one set: `desktop = ["clickr"]`. A worker launched
455
+ `--mcp desktop` receives the clickr MCP server — screen control for GUI work
456
+ — and follows the same control handover as a session:
457
+
458
+ ```
459
+ pai worker controls <id> you # hand control of the desktop to the worker
460
+ pai worker controls <id> me # take it back
461
+ ```
462
+
463
+ `controls` runs the `clickr controls you|me` CLI and the worker's screenshot
464
+ and input tools honour it. Control starts with the operator: a worker cannot
465
+ drive the desktop until it is handed over.
466
+
338
467
  ### Context meter
339
468
 
340
469
  Status files carry `contextTokens` (input + cache read + cache creation +
@@ -422,7 +551,9 @@ background instead. Decisions are ledgered (`DENIED-ANTHROPIC-AGENT`,
422
551
  `cost_tier`/`tags`), `worker_classes` (list/set/unset), `worker_run` (start a
423
552
  worker or chain from chat, returns the id immediately), `worker_toggle`,
424
553
  `worker_ps`, `worker_replay`, `worker_say` (message a running worker),
425
- `worker_resume` (continue a finished one) — the same library the CLI calls.
554
+ `worker_resume` (continue a finished one), `worker_handoff` (from inside a
555
+ worker: send a proposal/question/blocker up to its parent) — the same library
556
+ the CLI calls.
426
557
  `worker_providers add` accepts a raw `key`, parks it in
427
558
  `~/.config/pai/keys/<name>` (mode 0600) and stores only the path.
428
559
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tekmidian/pai",
3
- "version": "0.38.0",
3
+ "version": "0.39.1",
4
4
  "description": "PAI Knowledge OS — Personal AI Infrastructure with federated memory and project management",
5
5
  "type": "module",
6
6
  "main": "dist/index.mjs",
@@ -112,10 +112,10 @@ async function main(): Promise<void> {
112
112
  deny(
113
113
  "Agent tool is disabled: subagents run on the configured worker provider, not Anthropic. " +
114
114
  "Delegate with Bash instead, in the background:\n\n" +
115
- `pai worker run --label "${label || "task"}" --role research -p '<full, self-contained task spec>' ` +
115
+ `pai worker run --label "${label || "task"}" --class research -p '<full, self-contained task spec>' ` +
116
116
  "--allowedTools 'Read,Edit,Write,Bash,Grep,Glob' --output-format json\n\n" +
117
117
  "- Run it with run_in_background: true and always with a timeout.\n" +
118
- "- Use --role spotcheck (or implement) as the task demands.\n" +
118
+ "- Use --class spotcheck (or implement) as the task demands.\n" +
119
119
  "- Web research: add WebSearch,WebFetch to --allowedTools.\n" +
120
120
  "- The answer is in the `result` field of the JSON it prints. Review the diff yourself.\n" +
121
121
  "- pai worker ps lists running workers; pai worker follow <id> shows one live.\n" +
@@ -1,5 +0,0 @@
1
- import "./embeddings-DOLZnT1X.mjs";
2
- import "./search-Rpk1cSBC.mjs";
3
- import { t as detectTopicShift } from "./detector-CMap-9vw.mjs";
4
-
5
- export { detectTopicShift };
@@ -1,3 +0,0 @@
1
- import { t as createStorageBackend } from "./factory-DD2T33C9.mjs";
2
-
3
- export { createStorageBackend };