@tekmidian/pai 0.63.0 → 0.65.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. package/ARCHITECTURE.md +3 -0
  2. package/README.md +38 -5
  3. package/dist/{aibroker-client-BYG-GtAg.mjs → aibroker-client-B8c42Lh8.mjs} +1 -1
  4. package/dist/{aibroker-client-BK1h--W_.mjs → aibroker-client-C5Fw7DNz.mjs} +10 -4
  5. package/dist/{aibroker-client-BK1h--W_.mjs.map → aibroker-client-C5Fw7DNz.mjs.map} +1 -1
  6. package/dist/{async-DNVWtQl2.mjs → async-CNn36gm4.mjs} +5 -4
  7. package/dist/async-CNn36gm4.mjs.map +1 -0
  8. package/dist/{auto-route-CF8WNaoy.mjs → auto-route-sLMU-NnM.mjs} +2 -2
  9. package/dist/{auto-route-CF8WNaoy.mjs.map → auto-route-sLMU-NnM.mjs.map} +1 -1
  10. package/dist/{chain-CUfE6WYK.mjs → chain-C8QO8gwj.mjs} +4 -4
  11. package/dist/{chain-CUfE6WYK.mjs.map → chain-C8QO8gwj.mjs.map} +1 -1
  12. package/dist/chunker-BH4i-F2b.mjs +300 -0
  13. package/dist/chunker-BH4i-F2b.mjs.map +1 -0
  14. package/dist/cli/index.mjs +20 -20
  15. package/dist/cli/program.d.mts.map +1 -1
  16. package/dist/cli/program.mjs +20 -20
  17. package/dist/{clusters-Ci1mseh2.mjs → clusters-PgIUYT_v.mjs} +2 -2
  18. package/dist/{clusters-Ci1mseh2.mjs.map → clusters-PgIUYT_v.mjs.map} +1 -1
  19. package/dist/{config-CQCmH_gV.mjs → config-BbLFD7Uf.mjs} +3 -3
  20. package/dist/{config-CQCmH_gV.mjs.map → config-BbLFD7Uf.mjs.map} +1 -1
  21. package/dist/{config-DjXq_W42.mjs → config-YinjgXEJ.mjs} +1 -1
  22. package/dist/{context-handover-cache-DFNnlWv2.mjs → context-handover-cache-mGxq2-8f.mjs} +11 -29
  23. package/dist/context-handover-cache-mGxq2-8f.mjs.map +1 -0
  24. package/dist/daemon/index.mjs +16 -16
  25. package/dist/daemon-CX9JomIJ.mjs +19 -0
  26. package/dist/{daemon-Cex3dT9f.mjs → daemon-D2r1AQqE.mjs} +31 -30
  27. package/dist/{daemon-Cex3dT9f.mjs.map → daemon-D2r1AQqE.mjs.map} +1 -1
  28. package/dist/daemon-mcp/index.mjs +29 -20
  29. package/dist/daemon-mcp/index.mjs.map +1 -1
  30. package/dist/detector-C3Q7mxQU.mjs +3 -0
  31. package/dist/{detector-3g7XuU1r.mjs → detector-CIHEXKsV.mjs} +2 -2
  32. package/dist/{detector-3g7XuU1r.mjs.map → detector-CIHEXKsV.mjs.map} +1 -1
  33. package/dist/{embeddings-DfrYNIng.mjs → embeddings-BbNVXa_0.mjs} +1 -1
  34. package/dist/{embeddings-DfrYNIng.mjs.map → embeddings-BbNVXa_0.mjs.map} +1 -1
  35. package/dist/{embeddings-BNv3TQC5.mjs → embeddings-CDfM63uC.mjs} +1 -1
  36. package/dist/{factory-UO9_DFMN.mjs → factory-CaswxuJ0.mjs} +1 -1
  37. package/dist/{factory-BozZa81q.mjs → factory-y36qGegI.mjs} +13 -13
  38. package/dist/{factory-BozZa81q.mjs.map → factory-y36qGegI.mjs.map} +1 -1
  39. package/dist/{fallback-ktbR0aR7.mjs → fallback-CWDQYmJi.mjs} +1205 -1204
  40. package/dist/fallback-CWDQYmJi.mjs.map +1 -0
  41. package/dist/{federation-db-w8e-sKjp.mjs → federation-db-BTyoufBh.mjs} +2 -2
  42. package/dist/{federation-db-w8e-sKjp.mjs.map → federation-db-BTyoufBh.mjs.map} +1 -1
  43. package/dist/federation-db-HfIFc7FG.mjs +3 -0
  44. package/dist/{helpers-Dj-B314s.mjs → helpers-BRCJg0G3.mjs} +2 -208
  45. package/dist/helpers-BRCJg0G3.mjs.map +1 -0
  46. package/dist/hooks/block-sleep-poll.mjs +36 -11
  47. package/dist/hooks/block-sleep-poll.mjs.map +2 -2
  48. package/dist/hooks/capture-all-events.mjs +3 -17
  49. package/dist/hooks/capture-all-events.mjs.map +3 -3
  50. package/dist/hooks/capture-session-summary.mjs +3 -17
  51. package/dist/hooks/capture-session-summary.mjs.map +3 -3
  52. package/dist/hooks/capture-tool-output.mjs +3 -17
  53. package/dist/hooks/capture-tool-output.mjs.map +3 -3
  54. package/dist/hooks/cleanup-session-files.mjs +3 -17
  55. package/dist/hooks/cleanup-session-files.mjs.map +2 -2
  56. package/dist/hooks/context-compression-hook.mjs +3 -17
  57. package/dist/hooks/context-compression-hook.mjs.map +3 -3
  58. package/dist/hooks/initialize-session.mjs +3 -17
  59. package/dist/hooks/initialize-session.mjs.map +2 -2
  60. package/dist/hooks/inject-observations.mjs +3 -17
  61. package/dist/hooks/inject-observations.mjs.map +2 -2
  62. package/dist/hooks/load-core-context.mjs +4 -22
  63. package/dist/hooks/load-core-context.mjs.map +2 -2
  64. package/dist/hooks/load-project-context.mjs +3 -17
  65. package/dist/hooks/load-project-context.mjs.map +3 -3
  66. package/dist/hooks/mcp-deferred-gate.mjs +3 -17
  67. package/dist/hooks/mcp-deferred-gate.mjs.map +2 -2
  68. package/dist/hooks/observe.mjs +3 -17
  69. package/dist/hooks/observe.mjs.map +2 -2
  70. package/dist/hooks/security-validator.mjs +3 -17
  71. package/dist/hooks/security-validator.mjs.map +3 -3
  72. package/dist/hooks/stop-hook.mjs +3 -17
  73. package/dist/hooks/stop-hook.mjs.map +3 -3
  74. package/dist/hooks/sync-todo-to-md.mjs +3 -17
  75. package/dist/hooks/sync-todo-to-md.mjs.map +2 -2
  76. package/dist/hooks/worker-guard.mjs.map +2 -2
  77. package/dist/hooks/worker-status-line.mjs +4 -4
  78. package/dist/hooks/worker-status-line.mjs.map +2 -2
  79. package/dist/index.d.mts +26 -8
  80. package/dist/index.d.mts.map +1 -1
  81. package/dist/index.mjs +5 -4
  82. package/dist/indexer-backend-Cnc7Tf5C.mjs +5 -0
  83. package/dist/{ipc-client-Dasm515c.mjs → ipc-client-D16Xw6Uo.mjs} +2 -2
  84. package/dist/{ipc-client-Dasm515c.mjs.map → ipc-client-D16Xw6Uo.mjs.map} +1 -1
  85. package/dist/{kg-entity-Cj8Q6YmU.mjs → kg-entity-COTUj1ZC.mjs} +1 -1
  86. package/dist/{kg-entity-Cj8Q6YmU.mjs.map → kg-entity-COTUj1ZC.mjs.map} +1 -1
  87. package/dist/{latent-ideas-BRy6HNwg.mjs → latent-ideas-ByvMjVcb.mjs} +4 -4
  88. package/dist/{latent-ideas-BRy6HNwg.mjs.map → latent-ideas-ByvMjVcb.mjs.map} +1 -1
  89. package/dist/{link-boost-BptbAPuv.mjs → link-boost-UiE-uooT.mjs} +1 -1
  90. package/dist/{link-boost-BptbAPuv.mjs.map → link-boost-UiE-uooT.mjs.map} +1 -1
  91. package/dist/{main-resolver-BIft_FVF.mjs → main-resolver-CDe7DCso.mjs} +6 -6
  92. package/dist/{main-resolver-BIft_FVF.mjs.map → main-resolver-CDe7DCso.mjs.map} +1 -1
  93. package/dist/main-resolver-DI-A7lSO.mjs +7 -0
  94. package/dist/merge-2gqRPFu2.mjs +3 -0
  95. package/dist/{merge-xoyfZQ4W.mjs → merge-DgU9OgZy.mjs} +1 -1
  96. package/dist/{merge-xoyfZQ4W.mjs.map → merge-DgU9OgZy.mjs.map} +1 -1
  97. package/dist/module-paths-DdRzbkUI.mjs +44 -0
  98. package/dist/module-paths-DdRzbkUI.mjs.map +1 -0
  99. package/dist/{neighborhood-D8uscnGy.mjs → neighborhood-CvRHlqdR.mjs} +2 -2
  100. package/dist/{neighborhood-D8uscnGy.mjs.map → neighborhood-CvRHlqdR.mjs.map} +1 -1
  101. package/dist/{note-context-CgffaUMh.mjs → note-context-BrbfUIoP.mjs} +1 -1
  102. package/dist/{note-context-CgffaUMh.mjs.map → note-context-BrbfUIoP.mjs.map} +1 -1
  103. package/dist/{pai-home-CeOIYltV.mjs → pai-home-Cm9rcJgX.mjs} +1 -1
  104. package/dist/{pai-home-CeOIYltV.mjs.map → pai-home-Cm9rcJgX.mjs.map} +1 -1
  105. package/dist/{planner-DAQMTMjP.mjs → planner-8-shIa8t.mjs} +7 -7
  106. package/dist/{planner-DAQMTMjP.mjs.map → planner-8-shIa8t.mjs.map} +1 -1
  107. package/dist/{postgres-CxD6_Dca.mjs → postgres-DYtZg7J7.mjs} +8 -15
  108. package/dist/{postgres-CxD6_Dca.mjs.map → postgres-DYtZg7J7.mjs.map} +1 -1
  109. package/dist/{program-De1GVVM4.mjs → program-DiktbiWa.mjs} +229 -249
  110. package/dist/program-DiktbiWa.mjs.map +1 -0
  111. package/dist/{query-feedback-xz5axTj3.mjs → query-feedback-BIaZTTFO.mjs} +2 -2
  112. package/dist/{query-feedback-xz5axTj3.mjs.map → query-feedback-BIaZTTFO.mjs.map} +1 -1
  113. package/dist/query-feedback-B_iigYj-.mjs +3 -0
  114. package/dist/{registry-db-Bkpbp7Gf.mjs → registry-db-C7voqML9.mjs} +2 -2
  115. package/dist/{registry-db-Bkpbp7Gf.mjs.map → registry-db-C7voqML9.mjs.map} +1 -1
  116. package/dist/registry-db-JHPhA8vF.mjs +3 -0
  117. package/dist/{registry-postgres-B07-hmn8.mjs → registry-postgres-DSrkxqfF.mjs} +2 -2
  118. package/dist/{registry-postgres-B07-hmn8.mjs.map → registry-postgres-DSrkxqfF.mjs.map} +1 -1
  119. package/dist/{registry-sqlite-CkGND_tm.mjs → registry-sqlite-B2436JgX.mjs} +2 -2
  120. package/dist/{registry-sqlite-CkGND_tm.mjs.map → registry-sqlite-B2436JgX.mjs.map} +1 -1
  121. package/dist/{reranker-BS5gqGeF.mjs → reranker-CFiEzHQu.mjs} +1 -1
  122. package/dist/{reranker-CRVawoEh.mjs → reranker-DKv80KO5.mjs} +1 -1
  123. package/dist/{reranker-CRVawoEh.mjs.map → reranker-DKv80KO5.mjs.map} +1 -1
  124. package/dist/router-S6C5BxzZ.mjs +3 -0
  125. package/dist/{router-DjFZIoDl.mjs → router-aqLMvNMg.mjs} +1 -1
  126. package/dist/{router-DjFZIoDl.mjs.map → router-aqLMvNMg.mjs.map} +1 -1
  127. package/dist/{run-CZVCCvXE.mjs → run-DUZRSnIT.mjs} +120 -42
  128. package/dist/run-DUZRSnIT.mjs.map +1 -0
  129. package/dist/{run-env-BE5xyCwy.mjs → run-env-BHWnXqle.mjs} +3 -3
  130. package/dist/{run-env-BE5xyCwy.mjs.map → run-env-BHWnXqle.mjs.map} +1 -1
  131. package/dist/{runtime-paths-BRwDeBEg.mjs → runtime-paths-CHTg3ywb.mjs} +1 -1
  132. package/dist/{runtime-paths-BRwDeBEg.mjs.map → runtime-paths-CHTg3ywb.mjs.map} +1 -1
  133. package/dist/{search-BaTbyWjK.mjs → search-BOSphCJ1.mjs} +2 -2
  134. package/dist/{search-BaTbyWjK.mjs.map → search-BOSphCJ1.mjs.map} +1 -1
  135. package/dist/search-Bf3Kub3F.mjs +3 -0
  136. package/dist/{server-BY6AedmC.mjs → server-DlL1QI2k.mjs} +4 -5
  137. package/dist/server-DlL1QI2k.mjs.map +1 -0
  138. package/dist/{session-keepalive-CWGzLBVU.mjs → session-keepalive-CZUwp5IQ.mjs} +7 -7
  139. package/dist/{session-keepalive-CWGzLBVU.mjs.map → session-keepalive-CZUwp5IQ.mjs.map} +1 -1
  140. package/dist/skills/Art/SKILL.md +1 -1
  141. package/dist/skills/Observability/SKILL.md +4 -4
  142. package/dist/skills/Research/SKILL.md +1 -1
  143. package/dist/{sources-BBe3AZ-W.mjs → sources-DX4ElmrE.mjs} +1 -1
  144. package/dist/{sources-BBe3AZ-W.mjs.map → sources-DX4ElmrE.mjs.map} +1 -1
  145. package/dist/{sqlite-CfKfuggn.mjs → sqlite-BrEu3avy.mjs} +8 -7
  146. package/dist/sqlite-BrEu3avy.mjs.map +1 -0
  147. package/dist/{state-CwlGAKgF.mjs → state-DW8zdweW.mjs} +1 -1
  148. package/dist/{state-n13uPK5B.mjs → state-HyjqTihC.mjs} +1 -1
  149. package/dist/{state-n13uPK5B.mjs.map → state-HyjqTihC.mjs.map} +1 -1
  150. package/dist/{stop-words-ClCwO8mZ.mjs → stop-words-BdQuaE9K.mjs} +1 -1
  151. package/dist/{stop-words-ClCwO8mZ.mjs.map → stop-words-BdQuaE9K.mjs.map} +1 -1
  152. package/dist/{themes-B2v7RNnA.mjs → themes-BgqahYVM.mjs} +3 -3
  153. package/dist/{themes-B2v7RNnA.mjs.map → themes-BgqahYVM.mjs.map} +1 -1
  154. package/dist/tools-BbqQIHPe.mjs +6 -0
  155. package/dist/{tools-DFdPbX-X.mjs → tools-gMGDIpJ9.mjs} +84 -68
  156. package/dist/tools-gMGDIpJ9.mjs.map +1 -0
  157. package/dist/{trace-BRflVyBi.mjs → trace-CmAB7iJZ.mjs} +1 -1
  158. package/dist/{trace-BRflVyBi.mjs.map → trace-CmAB7iJZ.mjs.map} +1 -1
  159. package/dist/{vault-indexer-mCFus_AM.mjs → vault-indexer-Ddq51X20.mjs} +4 -3
  160. package/dist/vault-indexer-Ddq51X20.mjs.map +1 -0
  161. package/dist/{wakeup-DO1O4udw.mjs → wakeup-CZw88uXf.mjs} +3 -3
  162. package/dist/{wakeup-DO1O4udw.mjs.map → wakeup-CZw88uXf.mjs.map} +1 -1
  163. package/dist/{work-queue-worker-BbrC3I_R.mjs → work-queue-worker-DCzfH0d1.mjs} +4 -4
  164. package/dist/{work-queue-worker-BbrC3I_R.mjs.map → work-queue-worker-DCzfH0d1.mjs.map} +1 -1
  165. package/dist/work-queue-worker-Taba_vcA.mjs +11 -0
  166. package/dist/{zettelkasten-BPxSOalU.mjs → zettelkasten-Dwj67e4p.mjs} +4 -4
  167. package/dist/{zettelkasten-BPxSOalU.mjs.map → zettelkasten-Dwj67e4p.mjs.map} +1 -1
  168. package/docker/docker-compose.yml +39 -0
  169. package/docs/commands/README.md +3 -3
  170. package/docs/commands/config.md +3 -3
  171. package/docs/commands/setup.md +9 -2
  172. package/docs/commands/worker.md +2 -2
  173. package/gemini-extension.json +1 -1
  174. package/package.json +3 -2
  175. package/pai-plugin.json +1 -0
  176. package/scripts/build-hooks.mjs +6 -6
  177. package/src/hooks/ts/lib/pai-paths-case.test.ts +12 -0
  178. package/src/hooks/ts/lib/pai-paths-import.test.ts +25 -0
  179. package/src/hooks/ts/lib/pai-paths.ts +5 -28
  180. package/src/hooks/ts/lib/sleep-poll-gate.test.ts +17 -1
  181. package/src/hooks/ts/lib/sleep-poll-gate.ts +21 -9
  182. package/src/hooks/ts/session-start/load-core-context.ts +2 -6
  183. package/src/hooks/ts/session-start/session-start-worker-guard.test.ts +24 -1
  184. package/dist/async-DNVWtQl2.mjs.map +0 -1
  185. package/dist/context-handover-cache-DFNnlWv2.mjs.map +0 -1
  186. package/dist/daemon-C8-uzOuV.mjs +0 -19
  187. package/dist/detector-DgDn56j-.mjs +0 -3
  188. package/dist/fallback-ktbR0aR7.mjs.map +0 -1
  189. package/dist/federation-db-CJDw_Pwq.mjs +0 -3
  190. package/dist/helpers-Dj-B314s.mjs.map +0 -1
  191. package/dist/indexer-backend-BN9rpp9O.mjs +0 -5
  192. package/dist/main-resolver-C9-poMdi.mjs +0 -7
  193. package/dist/merge-BncjJTfb.mjs +0 -3
  194. package/dist/program-De1GVVM4.mjs.map +0 -1
  195. package/dist/query-feedback-COYCnvHQ.mjs +0 -3
  196. package/dist/registry-db-DwXpf7yF.mjs +0 -3
  197. package/dist/router-C5hPk9YP.mjs +0 -3
  198. package/dist/run-CZVCCvXE.mjs.map +0 -1
  199. package/dist/search-BQHL5wDr.mjs +0 -3
  200. package/dist/server-BY6AedmC.mjs.map +0 -1
  201. package/dist/sqlite-CfKfuggn.mjs.map +0 -1
  202. package/dist/tools-B52IvaU6.mjs +0 -6
  203. package/dist/tools-DFdPbX-X.mjs.map +0 -1
  204. package/dist/vault-indexer-mCFus_AM.mjs.map +0 -1
  205. package/dist/work-queue-worker-z-AATZ2t.mjs +0 -11
  206. /package/dist/{indexer-backend-Cc-_NK3q.mjs → indexer-backend-isSLg6yE.mjs} +0 -0
@@ -1,6 +1,6 @@
1
- import { i as getRegistryBackend } from "./factory-BozZa81q.mjs";
2
- import { E as readWorkersSection, O as resolveModelCapability, T as providerKeyPath, b as isModelCapability, d as NATIVE_ANTHROPIC_MODELS, g as classModelCapability, h as assertProviderRunnable, k as resolveProviderKey, m as WorkersConfigError, n as claudeCommand, t as buildRunEnv } from "./run-env-BE5xyCwy.mjs";
3
- import { _ as statusPath, d as resolveTarget, f as setCooldown, g as panesDir, h as ledgerPath, i as capabilityForRun, m as eventsPath, n as ensureProxyRunning, o as isQuotaFailure, p as ensureNoMcpConfig, s as nextAutoProvider, t as DEFAULT_PROXY_PORT, u as resolveCapabilityRun, v as workersLogDir } from "./server-BY6AedmC.mjs";
1
+ import { i as getRegistryBackend } from "./factory-y36qGegI.mjs";
2
+ import { E as readWorkersSection, O as resolveModelCapability, T as providerKeyPath, b as isModelCapability, d as NATIVE_ANTHROPIC_MODELS, g as classModelCapability, h as assertProviderRunnable, k as resolveProviderKey, m as WorkersConfigError, n as claudeCommand, t as buildRunEnv } from "./run-env-BHWnXqle.mjs";
3
+ import { _ as statusPath, d as resolveTarget, f as setCooldown, g as panesDir, h as ledgerPath, i as capabilityForRun, m as eventsPath, n as ensureProxyRunning, o as isQuotaFailure, p as ensureNoMcpConfig, s as nextAutoProvider, t as DEFAULT_PROXY_PORT, u as resolveCapabilityRun, v as workersLogDir } from "./server-DlL1QI2k.mjs";
4
4
  import { appendFileSync, closeSync, existsSync, lstatSync, mkdirSync, mkdtempSync, openSync, readFileSync, readdirSync, readlinkSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
5
5
  import { homedir, platform, tmpdir } from "node:os";
6
6
  import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
@@ -233,6 +233,7 @@ function parseRunnerArgs(argv) {
233
233
  let callerModel = false;
234
234
  let callerMcpConfig = false;
235
235
  let callerSystemPrompt = false;
236
+ const callerSystemPrompts = [];
236
237
  let callerTools = false;
237
238
  const mcp = [];
238
239
  const allowedTools = [];
@@ -254,7 +255,13 @@ function parseRunnerArgs(argv) {
254
255
  } else if (a.startsWith("--output-format=")) {
255
256
  const v = a.slice(16);
256
257
  if (v === "json" || v === "stream-json") outputFormat = v;
257
- } else if (a === "--verbose") {} else if (a === "--mcp") {
258
+ } else if (a === "--verbose") {} else if (a === "--append-system-prompt") {
259
+ callerSystemPrompt = true;
260
+ if (i + 1 < argv.length) callerSystemPrompts.push(argv[++i]);
261
+ } else if (a.startsWith("--append-system-prompt=")) {
262
+ callerSystemPrompt = true;
263
+ callerSystemPrompts.push(a.slice(23));
264
+ } else if (a === "--mcp") {
258
265
  const v = argv[i + 1];
259
266
  if (v !== void 0 && !v.startsWith("-")) {
260
267
  mcp.push(v);
@@ -277,8 +284,6 @@ function parseRunnerArgs(argv) {
277
284
  if (a.startsWith("--model=")) callerModel = true;
278
285
  if (a === "--mcp-config") callerMcpConfig = true;
279
286
  if (a.startsWith("--mcp-config=")) callerMcpConfig = true;
280
- if (a === "--append-system-prompt") callerSystemPrompt = true;
281
- if (a.startsWith("--append-system-prompt=")) callerSystemPrompt = true;
282
287
  if (a === "--tools") callerTools = true;
283
288
  if (a.startsWith("--tools=")) callerTools = true;
284
289
  if (prompt === null && !a.startsWith("-") && rest.length > 0 && (rest[rest.length - 1] === "-p" || rest[rest.length - 1] === "--print")) prompt = a;
@@ -294,12 +299,22 @@ function parseRunnerArgs(argv) {
294
299
  callerModel,
295
300
  callerMcpConfig,
296
301
  callerSystemPrompt,
302
+ callerSystemPrompts,
297
303
  callerTools,
298
304
  mcp,
299
305
  allowedTools
300
306
  };
301
307
  }
302
308
  /**
309
+ * The one --append-system-prompt flag for a spawn: claude keeps only the LAST
310
+ * occurrence, so every piece is joined (blank line between) into a single flag.
311
+ * Empty parts are dropped; no parts, no flag.
312
+ */
313
+ function appendSystemPromptArgs(parts) {
314
+ const text = parts.filter((p) => p.trim()).join("\n\n");
315
+ return text ? ["--append-system-prompt", text] : [];
316
+ }
317
+ /**
303
318
  * Turn `-p "<prompt>"` into bare `-p` (same for --print): for stream-json
304
319
  * stdin runs the prompt moves to the first user message on stdin, so the
305
320
  * value must not stay on the command line. Only prompt values directly
@@ -1338,14 +1353,20 @@ function gcWorktrees(logDir, olderThanHours = 24, dryRun = false, now = Date.now
1338
1353
  const out = [];
1339
1354
  const root = worktreesDir(logDir);
1340
1355
  const known = /* @__PURE__ */ new Set();
1341
- const archive = (id, dir, repo, st) => {
1356
+ const archive = (id, dir, st) => {
1342
1357
  const target = `refs/pai-archive/${id}`;
1343
1358
  if (dryRun) return void out.push({
1344
1359
  id,
1345
1360
  archive: target
1346
1361
  });
1347
1362
  try {
1348
- if (!repo) throw new Error("not a git worktree");
1363
+ let repo;
1364
+ try {
1365
+ const raw = git(dir, ["rev-parse", "--git-common-dir"]);
1366
+ repo = isAbsolute(raw) ? raw : resolve(dir, raw);
1367
+ } catch {
1368
+ throw new Error("not a git worktree");
1369
+ }
1349
1370
  const label = `archive: leftover state of worker ${id}`;
1350
1371
  if (uncommittedPaths(dir).length) {
1351
1372
  const res = salvageUncommitted(dir, label);
@@ -1424,7 +1445,7 @@ function gcWorktrees(logDir, olderThanHours = 24, dryRun = false, now = Date.now
1424
1445
  continue;
1425
1446
  }
1426
1447
  if (end > cutoff) continue;
1427
- archive(st.id, st.worktreeDir, st.cwd, st);
1448
+ archive(st.id, st.worktreeDir, st);
1428
1449
  }
1429
1450
  if (existsSync(root)) for (const ent of readdirSync(root, { withFileTypes: true })) {
1430
1451
  if (!ent.isDirectory() || known.has(ent.name) || existsSync(statusPath(logDir, ent.name))) continue;
@@ -1434,14 +1455,7 @@ function gcWorktrees(logDir, olderThanHours = 24, dryRun = false, now = Date.now
1434
1455
  } catch {
1435
1456
  continue;
1436
1457
  }
1437
- let repo = null;
1438
- try {
1439
- const raw = git(dir, ["rev-parse", "--git-common-dir"]);
1440
- repo = isAbsolute(raw) ? raw : resolve(dir, raw);
1441
- } catch {
1442
- repo = null;
1443
- }
1444
- archive(ent.name, dir, repo, null);
1458
+ archive(ent.name, dir, null);
1445
1459
  }
1446
1460
  if (!dryRun) for (const repo of new Set(loadStatuses(logDir).map((s) => s.cwd))) try {
1447
1461
  git(repo, ["worktree", "prune"]);
@@ -2200,12 +2214,51 @@ function absoluteCliPath() {
2200
2214
  if (argv1.endsWith("pai")) return argv1;
2201
2215
  return "pai";
2202
2216
  }
2217
+ /** The one place that decides where a follow pane opens: tmux (any OS) > iTerm2 (macOS) > nowhere. */
2218
+ function paneBackend(env = process.env, platform = process.platform) {
2219
+ if (env.TMUX) return "tmux";
2220
+ if (platform === "darwin" && env.ITERM_SESSION_ID) return "iterm";
2221
+ return "none";
2222
+ }
2223
+ function noPaneMessage(wid) {
2224
+ return `no pane support here, use: pai worker follow${wid ? ` ${wid}` : ""}`;
2225
+ }
2226
+ /** Split the current tmux window horizontally (right-hand column) and run cmd in it, focus stays put. */
2227
+ function tmuxSplit(cmd) {
2228
+ const target = process.env.TMUX_PANE ? ["-t", process.env.TMUX_PANE] : [];
2229
+ try {
2230
+ execFileSync("tmux", [
2231
+ "split-window",
2232
+ "-h",
2233
+ "-d",
2234
+ "-l",
2235
+ "40%",
2236
+ ...target,
2237
+ cmd
2238
+ ], { stdio: "pipe" });
2239
+ } catch (e) {
2240
+ const err = e;
2241
+ throw new Error(`pai worker pane: tmux split-window failed: ${(err.stderr?.toString() || err.message || "").trim().slice(0, 200)}`);
2242
+ }
2243
+ }
2203
2244
  /** Open (or only report on) the stacked follow pane of one worker. */
2204
2245
  async function openPaneForWorker(logDir, config, wid, term) {
2205
2246
  if (workerPaneOpen(wid)) return {
2206
2247
  message: `pane for ${wid} already open`,
2207
2248
  session: null
2208
2249
  };
2250
+ const backend = paneBackend();
2251
+ if (backend === "none") return {
2252
+ message: noPaneMessage(wid),
2253
+ session: null
2254
+ };
2255
+ if (backend === "tmux") {
2256
+ tmuxSplit(followCommand(wid, config.pane.autoExitSecs));
2257
+ return {
2258
+ message: `pane opened for ${wid}`,
2259
+ session: null
2260
+ };
2261
+ }
2209
2262
  const uid = itermUuid(term);
2210
2263
  const regPath = join(panesDir(logDir), `${scopeKey(term)}.json`);
2211
2264
  const reg = loadRegistry(regPath);
@@ -2259,6 +2312,7 @@ async function windowBoundsLine(term) {
2259
2312
  */
2260
2313
  async function checkPaneForWorker(wid, fontSize, term) {
2261
2314
  const lines = [workerPaneOpen(wid) ? `pane for ${wid} open` : `no pane for ${wid}`];
2315
+ if (paneBackend() !== "iterm") return lines.join("\n");
2262
2316
  lines.push(await windowBoundsLine(term));
2263
2317
  const path = dynamicProfilePath();
2264
2318
  if (existsSync(path)) {
@@ -2281,6 +2335,13 @@ async function checkPaneForWorker(wid, fontSize, term) {
2281
2335
  * with the running command, so names cannot serve as idempotence).
2282
2336
  */
2283
2337
  async function openFollowPane(logDir, _config, term, checkOnly) {
2338
+ const backend = paneBackend();
2339
+ if (backend === "none") return noPaneMessage();
2340
+ if (backend === "tmux") {
2341
+ if (checkOnly) return "no follow pane";
2342
+ tmuxSplit(`${process.execPath} ${absoluteCliPath()} worker follow`);
2343
+ return "follow pane opened";
2344
+ }
2284
2345
  const uid = itermUuid(term);
2285
2346
  const out = (await osascript(TAB_TTYS_SCRIPT, [uid])).stdout.trim();
2286
2347
  if (out === "notfound") throw new Error("pai worker pane: no open iTerm2 session matches ITERM_SESSION_ID");
@@ -2399,7 +2460,9 @@ function operatorSocketPath(logDir, id) {
2399
2460
  }
2400
2461
  /**
2401
2462
  * The runner's side: listen on the worker socket, hand every received line to
2402
- * `onLine`. Returns the server (close it when the run ends; the socket file is
2463
+ * `onLine`. It acknowledges with "ok" only when `onLine` returns without a
2464
+ * string; a returned string (or a throw) is the failure reason, sent back as
2465
+ * `err <reason>` so `say` never reports ok for a message nobody received. Returns the server (close it when the run ends; the socket file is
2403
2466
  * unlinked on close, best effort).
2404
2467
  */
2405
2468
  function createOperatorServer(logDir, id, onLine) {
@@ -2409,14 +2472,20 @@ function createOperatorServer(logDir, id, onLine) {
2409
2472
  } catch {}
2410
2473
  const server = createServer((socket) => {
2411
2474
  let buf = "";
2412
- socket.on("data", (chunk) => {
2475
+ socket.on("error", () => {});
2476
+ socket.on("data", async (chunk) => {
2413
2477
  buf += chunk.toString("utf8");
2414
2478
  let nl;
2415
2479
  while ((nl = buf.indexOf("\n")) >= 0) {
2416
2480
  const line = buf.slice(0, nl).replace(/\r$/, "");
2417
2481
  buf = buf.slice(nl + 1);
2418
- if (line.trim()) onLine(line);
2419
- socket.write("ok\n");
2482
+ let failure;
2483
+ if (line.trim()) try {
2484
+ failure = await onLine(line);
2485
+ } catch (e) {
2486
+ failure = e.message;
2487
+ }
2488
+ if (!socket.destroyed) socket.write(typeof failure === "string" && failure ? `err ${failure.replace(/\n/g, " ")}\n` : "ok\n");
2420
2489
  }
2421
2490
  });
2422
2491
  });
@@ -2430,7 +2499,7 @@ function createOperatorServer(logDir, id, onLine) {
2430
2499
  }
2431
2500
  /**
2432
2501
  * `pai worker say <id> "<text>"`: forward one line to a running worker.
2433
- * Resolves "ok", rejects with a clear message when the worker is not running.
2502
+ * Resolves "ok" only once the worker acknowledged delivery; rejects with the reason otherwise.
2434
2503
  */
2435
2504
  function sayToWorker(logDir, id, text, timeoutMs = 4e3) {
2436
2505
  const status = loadStatus(logDir, id);
@@ -2449,10 +2518,13 @@ function sayToWorker(logDir, id, text, timeoutMs = 4e3) {
2449
2518
  sock.once("connect", () => {
2450
2519
  sock.write(text.replace(/\n/g, " ") + "\n");
2451
2520
  });
2452
- sock.once("data", () => {
2521
+ sock.once("data", (d) => {
2453
2522
  sock.end();
2454
- resolve("ok");
2523
+ const reply = d.toString("utf8").trim();
2524
+ if (reply === "ok") resolve("ok");
2525
+ else reject(/* @__PURE__ */ new Error(`worker ${id} did not take the message: ${reply.replace(/^err /, "") || "no acknowledgement"}`));
2455
2526
  });
2527
+ sock.once("close", () => fail(/* @__PURE__ */ new Error("connection closed before the worker acknowledged")));
2456
2528
  });
2457
2529
  }
2458
2530
 
@@ -2857,10 +2929,10 @@ function fullContractPrompt(format) {
2857
2929
  "report.",
2858
2930
  "No narration, no timestamps, no greetings, no summaries of what you read; act, verify, then stop.",
2859
2931
  "Never sleep-poll: no `sleep N` over 60 seconds, anywhere in a command — standalone, after `&&`/`||`/",
2860
- "`;`/`|`, or inside a loop or subshell. Ending your turn ends this process, so a background job gets",
2861
- "no later wake-up here: run the long command in the FOREGROUND with a Bash timeout up to 600000 ms;",
2862
- "if it can run longer than that, start it in the background and wait with a foreground loop that ends",
2863
- "when the job ends: `while kill -0 <pid> 2>/dev/null; do sleep 15; done`.",
2932
+ "`;`/`|`, or inside a loop or subshell — and the sleeps of one command add up (`sleep 58; sleep 58` is",
2933
+ "116 s). Ending your turn ends this process, so a background job gets no later wake-up here:",
2934
+ "run_in_background is denied. Run the long command in the FOREGROUND with a Bash timeout up to 600000 ms",
2935
+ "and split longer jobs into steps that each fit it.",
2864
2936
  ...fileNotInlineBlock(),
2865
2937
  "",
2866
2938
  `Operator messages: a user turn starting with ${OPERATOR_MARK} was typed by the operator while you`,
@@ -2903,7 +2975,7 @@ function promptTrailer(format) {
2903
2975
  return format === "ag2" ? "\n\nFinal message: one AG2 R message only, no prose (format in system prompt)." : "\n\nFinal message: a JSON object only, no prose before or after, no code fence (format in system prompt).";
2904
2976
  }
2905
2977
  /** The exact text sent to resend a final message that failed AG2 validation. */
2906
- const AG2_REASK_TEXT = "Your final message was not a valid AG2 R message. Resend it now as a single AG2 R message only: first line R, then i=id r=result G=+ (gate, if r=+) t=tests(Name+) c=path summary p=proof z=the answer/note. No prose.";
2978
+ const AG2_REASK_TEXT = "Your final message was not a valid AG2 R message. Resend it now as a single AG2 R message only, no prose, no code fence. Minimal example (one key=value per line, first line R):\nR\ni=task-id\nr=+\nG=+\nc=path summary\nt=Name+\np=proof command\nz=the answer, one line\n(r is + - ~ ? !; r=+ needs G=+ and p; when r is not +, add y=why.)";
2907
2979
  /** The full-contract AG2 prompt — the keepalive path's identical-construction baseline. */
2908
2980
  const WORKER_CONTRACT_PROMPT = fullContractPrompt("ag2");
2909
2981
  /**
@@ -3433,7 +3505,7 @@ async function runWorker(opts) {
3433
3505
  if (gc?.length) process.stderr.write(`pai worker: archived ${gc.length} leftover worktree(s) (pai worker gc)\n`);
3434
3506
  } catch {}
3435
3507
  if (opts.className === "plan" && !opts._planner) {
3436
- const { runPlanner } = await import("./planner-DAQMTMjP.mjs");
3508
+ const { runPlanner } = await import("./planner-8-shIa8t.mjs");
3437
3509
  return runPlanner(opts);
3438
3510
  }
3439
3511
  const parent = launchParent(opts.parent);
@@ -3809,7 +3881,7 @@ async function executeImageRun(a) {
3809
3881
  * ledger line). Fire-and-forget, never blocks the worker.
3810
3882
  */
3811
3883
  async function announcePane(logDir, config, wid, term, noPane, ledger) {
3812
- const skip = !noPane ? !config.pane.enabled ? "workers.pane.enabled is false" : process.env.PAI_WORKER_AUTOPANE === "0" ? "PAI_WORKER_AUTOPANE=0" : !term ? "not in iTerm2 (no ITERM_SESSION_ID)" : null : "--no-pane";
3884
+ const skip = !noPane ? !config.pane.enabled ? "workers.pane.enabled is false" : process.env.PAI_WORKER_AUTOPANE === "0" ? "PAI_WORKER_AUTOPANE=0" : paneBackend() === "none" ? "no tmux ($TMUX) or iTerm2 (ITERM_SESSION_ID) here" : null : "--no-pane";
3813
3885
  if (skip) {
3814
3886
  process.stderr.write(`[pai worker] no pane for ${wid}: ${skip}\n`);
3815
3887
  return;
@@ -3902,12 +3974,12 @@ async function executeRun(a) {
3902
3974
  let cmd = [...claudeCmd];
3903
3975
  cmd.push(...modelFlagArgs(headless, model, Boolean(parsed.callerModel)));
3904
3976
  cmd.push(...chromeArgs, ...mcpArgs, ...toolArgs, ...toolsFlag, ...restArgs);
3905
- if (headless) {
3906
- cmd.push("--output-format", "stream-json", "--verbose", "--input-format", "stream-json");
3907
- if (!parsed.callerSystemPrompt) cmd.push("--append-system-prompt", workerContractPrompt(a.className, a.reportFormat));
3908
- if (worktree) cmd.push("--append-system-prompt", worktreeSystemPrompt(wid, worktree.branch, worktree.dir, worktree.snapshot));
3909
- else cmd.push("--append-system-prompt", inPlaceSystemPrompt());
3910
- }
3977
+ if (headless) cmd.push("--output-format", "stream-json", "--verbose", "--input-format", "stream-json");
3978
+ cmd.push(...appendSystemPromptArgs([
3979
+ ...headless && !parsed.callerSystemPrompt ? [workerContractPrompt(a.className, a.reportFormat)] : [],
3980
+ ...headless ? [worktree ? worktreeSystemPrompt(wid, worktree.branch, worktree.dir, worktree.snapshot) : inPlaceSystemPrompt()] : [],
3981
+ ...parsed.callerSystemPrompts
3982
+ ]));
3911
3983
  cmd = ensureToolSearch(cmd);
3912
3984
  if (a.printCmd) {
3913
3985
  console.log(JSON.stringify({
@@ -3994,7 +4066,9 @@ async function executeRun(a) {
3994
4066
  }) + "\n");
3995
4067
  } catch {}
3996
4068
  };
3997
- const operatorServer = headless ? createOperatorServer(logDir, wid, (text) => {
4069
+ const operatorServer = headless ? createOperatorServer(logDir, wid, async (text) => {
4070
+ const stdin = proc.stdin;
4071
+ if (!stdin || !stdin.writable || stdin.writableEnded) return "the worker's stdin is already closed (its turn ended) — use: pai worker resume";
3998
4072
  operatorInFlight += 1;
3999
4073
  if (closeTimer) {
4000
4074
  clearTimeout(closeTimer);
@@ -4005,9 +4079,13 @@ async function executeRun(a) {
4005
4079
  text,
4006
4080
  handoff: isHandoffMessage(text)
4007
4081
  });
4008
- try {
4009
- proc.stdin?.write(stdinUserMessage(operatorUserText(text)) + "\n");
4010
- } catch {}
4082
+ return new Promise((resolve) => {
4083
+ try {
4084
+ stdin.write(stdinUserMessage(operatorUserText(text)) + "\n", (e) => resolve(e ? `write to the worker failed: ${e.message}` : void 0));
4085
+ } catch (e) {
4086
+ resolve(`write to the worker failed: ${e.message}`);
4087
+ }
4088
+ });
4011
4089
  }) : null;
4012
4090
  let killed = false;
4013
4091
  const cleanup = () => {
@@ -4595,4 +4673,4 @@ function resultFromOutput(out) {
4595
4673
 
4596
4674
  //#endregion
4597
4675
  export { expandMcpNames as $, ledgerSummary as A, loadStatuses as B, discardWorker as C, uncommittedPaths as D, mergeWorker as E, contextPercent as F, setWorkerLabel as G, nowStamp as H, elapsedOf as I, parseRunnerArgs as J, waitForTerminalStatus as K, isChatPane as L, ageOf as M, alive as N, worktreesDir as O, contextLabel as P, describeMcp as Q, isLive as R, workerInScope as S, git as T, ownsPid as U, newWorkerId as V, saveStatus as W, pinNotices as X, shortText as Y, projectLaunchConfig as Z, itermForClaudeSession as _, parseWorkerReport as a, sessionMapPath as b, readInbox as c, checkPaneForWorker as d, openFollowPane as f, currentTabKey as g, markControlsHeld as h, usageContextTokens as i, UNLABELED as j, appendLedger as k, sayToWorker as l, clickrControlsArgv as m, runWorker as n, renderReport as o, openPaneForWorker as p, longInlinePromptHint as q, testProvider as r, handoffFromInside as s, printResult as t, workerDepth as u, itermUuid as v, gcWorktrees as w, sessionTag as x, resolveSession as y, loadStatus as z };
4598
- //# sourceMappingURL=run-CZVCCvXE.mjs.map
4676
+ //# sourceMappingURL=run-DUZRSnIT.mjs.map