@tekmidian/pai 0.41.0 → 0.42.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 (112) hide show
  1. package/dist/aibroker-client-BP74gGwD.mjs +215 -0
  2. package/dist/aibroker-client-BP74gGwD.mjs.map +1 -0
  3. package/dist/aibroker-client-C6m71p6O.mjs +3 -0
  4. package/dist/{auto-route-BwzmlW3W.mjs → auto-route-_5zzJz5q.mjs} +2 -2
  5. package/dist/{auto-route-BwzmlW3W.mjs.map → auto-route-_5zzJz5q.mjs.map} +1 -1
  6. package/dist/{chain-zMjCDW-R.mjs → chain-DGXNoTwc.mjs} +70 -329
  7. package/dist/chain-DGXNoTwc.mjs.map +1 -0
  8. package/dist/cli/index.mjs +12 -10
  9. package/dist/cli/index.mjs.map +1 -1
  10. package/dist/cli/program.mjs +12 -10
  11. package/dist/{clusters-DRHhfli9.mjs → clusters-j0ZuNYp9.mjs} +1 -1
  12. package/dist/{clusters-DRHhfli9.mjs.map → clusters-j0ZuNYp9.mjs.map} +1 -1
  13. package/dist/{config-D1G9IFpn.mjs → config-B64vFg14.mjs} +3 -50
  14. package/dist/config-B64vFg14.mjs.map +1 -0
  15. package/dist/{config-DD52BPB-.mjs → config-C_ErGddD.mjs} +1 -1
  16. package/dist/{config-Dl8lT4Lu.mjs → config-DgzR5sfb.mjs} +2 -2
  17. package/dist/{config-Dl8lT4Lu.mjs.map → config-DgzR5sfb.mjs.map} +1 -1
  18. package/dist/{context-handover-cache-C6_rs7JT.mjs → context-handover-cache-dUnSZwaA.mjs} +4 -4
  19. package/dist/{context-handover-cache-C6_rs7JT.mjs.map → context-handover-cache-dUnSZwaA.mjs.map} +1 -1
  20. package/dist/daemon/index.mjs +13 -12
  21. package/dist/daemon/index.mjs.map +1 -1
  22. package/dist/daemon-CKBkhOsZ.mjs +23 -0
  23. package/dist/{daemon-CpdVUnl_.mjs → daemon-DsvP8KMy.mjs} +357 -27
  24. package/dist/daemon-DsvP8KMy.mjs.map +1 -0
  25. package/dist/daemon-mcp/index.mjs +10 -6
  26. package/dist/daemon-mcp/index.mjs.map +1 -1
  27. package/dist/detector-C-7KRi42.mjs +5 -0
  28. package/dist/{detector-smpCm7ku.mjs → detector-C73Nxm94.mjs} +1 -1
  29. package/dist/{detector-smpCm7ku.mjs.map → detector-C73Nxm94.mjs.map} +1 -1
  30. package/dist/{factory-Bc5EyN54.mjs → factory-DEb9NmHJ.mjs} +7 -7
  31. package/dist/{factory-Bc5EyN54.mjs.map → factory-DEb9NmHJ.mjs.map} +1 -1
  32. package/dist/factory-Dbo8yNPi.mjs +3 -0
  33. package/dist/{fallback-CgQ_x4I7.mjs → fallback-5UJO-RyX.mjs} +5 -4
  34. package/dist/{fallback-CgQ_x4I7.mjs.map → fallback-5UJO-RyX.mjs.map} +1 -1
  35. package/dist/hooks/worker-status-line.mjs +9 -4
  36. package/dist/hooks/worker-status-line.mjs.map +3 -3
  37. package/dist/hooks/worker-supervision.mjs +593 -0
  38. package/dist/hooks/worker-supervision.mjs.map +7 -0
  39. package/dist/{indexer-backend-rohVVKrA.mjs → indexer-backend-BPTzKFZU.mjs} +1 -1
  40. package/dist/{indexer-backend-rohVVKrA.mjs.map → indexer-backend-BPTzKFZU.mjs.map} +1 -1
  41. package/dist/{ipc-client-C7AVpsyv.mjs → ipc-client-BmypMNYk.mjs} +2 -2
  42. package/dist/{ipc-client-C7AVpsyv.mjs.map → ipc-client-BmypMNYk.mjs.map} +1 -1
  43. package/dist/{kg-entity-DbOMPdF9.mjs → kg-entity-r8duqhi9.mjs} +1 -1
  44. package/dist/{kg-entity-DbOMPdF9.mjs.map → kg-entity-r8duqhi9.mjs.map} +1 -1
  45. package/dist/{latent-ideas-iNp5s55R.mjs → latent-ideas-CtSca4qG.mjs} +2 -2
  46. package/dist/{latent-ideas-iNp5s55R.mjs.map → latent-ideas-CtSca4qG.mjs.map} +1 -1
  47. package/dist/{link-boost-NNzADHX_.mjs → link-boost-Bucnz3n8.mjs} +1 -1
  48. package/dist/{link-boost-NNzADHX_.mjs.map → link-boost-Bucnz3n8.mjs.map} +1 -1
  49. package/dist/{main-resolver-CM1IHbuu.mjs → main-resolver-BgIrC-D9.mjs} +4 -214
  50. package/dist/main-resolver-BgIrC-D9.mjs.map +1 -0
  51. package/dist/main-resolver-DXGuygFG.mjs +7 -0
  52. package/dist/{neighborhood-AGL7oXQ2.mjs → neighborhood-CM7Jgb51.mjs} +1 -1
  53. package/dist/{neighborhood-AGL7oXQ2.mjs.map → neighborhood-CM7Jgb51.mjs.map} +1 -1
  54. package/dist/{note-context-BHwYpSFf.mjs → note-context-DCwE2A-M.mjs} +1 -1
  55. package/dist/{note-context-BHwYpSFf.mjs.map → note-context-DCwE2A-M.mjs.map} +1 -1
  56. package/dist/{planner-DsmMRIZR.mjs → planner-BLDJt3ZS.mjs} +6 -5
  57. package/dist/{planner-DsmMRIZR.mjs.map → planner-BLDJt3ZS.mjs.map} +1 -1
  58. package/dist/{postgres-Dwxe290H.mjs → postgres-CtOzfoQU.mjs} +1 -1
  59. package/dist/{postgres-Dwxe290H.mjs.map → postgres-CtOzfoQU.mjs.map} +1 -1
  60. package/dist/{program-Bed-Pd-8.mjs → program-CruRnLtc.mjs} +36 -33
  61. package/dist/{program-Bed-Pd-8.mjs.map → program-CruRnLtc.mjs.map} +1 -1
  62. package/dist/query-feedback-DGoVRaWD.mjs +3 -0
  63. package/dist/{query-feedback-DZfjI34w.mjs → query-feedback-Dqz-HC__.mjs} +1 -1
  64. package/dist/{query-feedback-DZfjI34w.mjs.map → query-feedback-Dqz-HC__.mjs.map} +1 -1
  65. package/dist/router-BTIGZR2_.mjs +3 -0
  66. package/dist/{router-DHracTUC.mjs → router-DD6D4j31.mjs} +1 -1
  67. package/dist/{router-DHracTUC.mjs.map → router-DD6D4j31.mjs.map} +1 -1
  68. package/dist/runtime-paths-rni52zHX.mjs +50 -0
  69. package/dist/runtime-paths-rni52zHX.mjs.map +1 -0
  70. package/dist/scope-NIwCGxRI.mjs +351 -0
  71. package/dist/scope-NIwCGxRI.mjs.map +1 -0
  72. package/dist/{server-BOuAOj9b.mjs → server-Cp7tNzNC.mjs} +19 -2
  73. package/dist/server-Cp7tNzNC.mjs.map +1 -0
  74. package/dist/skills/Worker/SKILL.md +3 -0
  75. package/dist/{sources-ju6AA7lL.mjs → sources-CS43CpuS.mjs} +1 -1
  76. package/dist/{sources-ju6AA7lL.mjs.map → sources-CS43CpuS.mjs.map} +1 -1
  77. package/dist/{sqlite-kFZeWCJ2.mjs → sqlite-Cq3gJcq9.mjs} +1 -1
  78. package/dist/{sqlite-kFZeWCJ2.mjs.map → sqlite-Cq3gJcq9.mjs.map} +1 -1
  79. package/dist/{state-ahFAbD8b.mjs → state-BTa10SOM.mjs} +1 -1
  80. package/dist/{state-ahFAbD8b.mjs.map → state-BTa10SOM.mjs.map} +1 -1
  81. package/dist/{state-DH_mp5Xe.mjs → state-RXepvbnO.mjs} +1 -1
  82. package/dist/{themes-DqhNUUQk.mjs → themes-B7h9YDiy.mjs} +1 -1
  83. package/dist/{themes-DqhNUUQk.mjs.map → themes-B7h9YDiy.mjs.map} +1 -1
  84. package/dist/{tools-COna9vZR.mjs → tools-BW3NLMPk.mjs} +1 -1
  85. package/dist/{tools-CMlHa9lZ.mjs → tools-LlzcV_eK.mjs} +14 -14
  86. package/dist/{tools-CMlHa9lZ.mjs.map → tools-LlzcV_eK.mjs.map} +1 -1
  87. package/dist/{trace-DTP6k4B_.mjs → trace-u4hT-pLD.mjs} +1 -1
  88. package/dist/{trace-DTP6k4B_.mjs.map → trace-u4hT-pLD.mjs.map} +1 -1
  89. package/dist/{vault-indexer-YMH22mLU.mjs → vault-indexer-mata9S7b.mjs} +1 -1
  90. package/dist/{vault-indexer-YMH22mLU.mjs.map → vault-indexer-mata9S7b.mjs.map} +1 -1
  91. package/dist/{work-queue-worker-B3nl8yyn.mjs → work-queue-worker-7Vkli4Yh.mjs} +4 -4
  92. package/dist/{work-queue-worker-B3nl8yyn.mjs.map → work-queue-worker-7Vkli4Yh.mjs.map} +1 -1
  93. package/dist/work-queue-worker-D1p2V-ae.mjs +14 -0
  94. package/dist/{zettelkasten-DDvKRm2V.mjs → zettelkasten-F0D_XfQ4.mjs} +3 -3
  95. package/dist/{zettelkasten-DDvKRm2V.mjs.map → zettelkasten-F0D_XfQ4.mjs.map} +1 -1
  96. package/docs/commands/worker.md +1 -1
  97. package/docs/worker.md +40 -0
  98. package/package.json +1 -1
  99. package/plugins/productivity/hooks/hooks.json +5 -0
  100. package/src/hooks/ts/user-prompt/worker-supervision.ts +123 -0
  101. package/dist/chain-zMjCDW-R.mjs.map +0 -1
  102. package/dist/config-D1G9IFpn.mjs.map +0 -1
  103. package/dist/daemon-BSL9sXxm.mjs +0 -22
  104. package/dist/daemon-CpdVUnl_.mjs.map +0 -1
  105. package/dist/detector-BLVOCiJ_.mjs +0 -5
  106. package/dist/factory-C7ua_3ik.mjs +0 -3
  107. package/dist/main-resolver-CM1IHbuu.mjs.map +0 -1
  108. package/dist/main-resolver-E5WlilhM.mjs +0 -6
  109. package/dist/query-feedback-CGcEiGtY.mjs +0 -3
  110. package/dist/router-CAtyVQud.mjs +0 -3
  111. package/dist/server-BOuAOj9b.mjs.map +0 -1
  112. package/dist/work-queue-worker-BM1GcAAq.mjs +0 -14
@@ -0,0 +1,593 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/hooks/ts/user-prompt/worker-supervision.ts
4
+ import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
5
+ import { join as join3 } from "node:path";
6
+
7
+ // src/hooks/ts/lib/worker-session.ts
8
+ function isWorkerSession(env = process.env) {
9
+ return env.PAI_WORKER === "1";
10
+ }
11
+
12
+ // src/workers/config.ts
13
+ import { homedir as homedir2 } from "node:os";
14
+ import { join as join2 } from "node:path";
15
+
16
+ // src/config/json-store.ts
17
+ import {
18
+ existsSync,
19
+ readFileSync,
20
+ writeFileSync,
21
+ copyFileSync,
22
+ renameSync,
23
+ unlinkSync,
24
+ mkdirSync
25
+ } from "node:fs";
26
+ function readJsonStrict(path, label = path) {
27
+ if (!existsSync(path)) return {};
28
+ let raw;
29
+ try {
30
+ raw = readFileSync(path, "utf8");
31
+ } catch (e) {
32
+ throw new Error(
33
+ `Could not read ${label}: ${e instanceof Error ? e.message : String(e)}
34
+ Refusing to continue \u2014 writing now would replace its contents with ours alone.`
35
+ );
36
+ }
37
+ try {
38
+ return JSON.parse(raw);
39
+ } catch (e) {
40
+ throw new Error(
41
+ `${label} exists but is not valid JSON: ${e instanceof Error ? e.message : String(e)}
42
+ Refusing to continue \u2014 overwriting it would destroy whatever it holds.
43
+ Repair the file, or move it aside and re-run this command.`
44
+ );
45
+ }
46
+ }
47
+
48
+ // src/daemon/config.ts
49
+ import { homedir, userInfo } from "node:os";
50
+ import { join } from "node:path";
51
+
52
+ // src/notifications/types.ts
53
+ var DEFAULT_ROUTING = {
54
+ error: ["whatsapp", "macos", "ntfy", "cli"],
55
+ completion: ["whatsapp", "macos", "ntfy", "cli"],
56
+ info: ["cli"],
57
+ progress: ["cli"],
58
+ debug: []
59
+ };
60
+ var DEFAULT_CHANNELS = {
61
+ ntfy: {
62
+ enabled: false,
63
+ url: void 0,
64
+ priority: "default"
65
+ },
66
+ whatsapp: {
67
+ enabled: true,
68
+ recipient: void 0
69
+ },
70
+ macos: {
71
+ enabled: true
72
+ },
73
+ voice: {
74
+ enabled: false,
75
+ voiceName: "bm_george"
76
+ },
77
+ cli: {
78
+ enabled: true
79
+ }
80
+ };
81
+ var DEFAULT_NOTIFICATION_CONFIG = {
82
+ mode: "auto",
83
+ channels: DEFAULT_CHANNELS,
84
+ routing: DEFAULT_ROUTING
85
+ };
86
+
87
+ // src/tasks/types.ts
88
+ var DEFAULT_TASK_CONFIG = {
89
+ enabled: false,
90
+ providers: {
91
+ todoist: {
92
+ enabled: false
93
+ }
94
+ },
95
+ autoDispatch: false
96
+ };
97
+
98
+ // src/runtime-paths.ts
99
+ function paiSocketPath() {
100
+ return process.env.PAI_SOCKET_PATH ?? "/tmp/pai.sock";
101
+ }
102
+
103
+ // src/daemon/config.ts
104
+ function perUserDbName() {
105
+ const username = userInfo().username;
106
+ const safe = username.replace(/[^a-zA-Z0-9_]/g, "_").toLowerCase();
107
+ return `pai_${safe}`;
108
+ }
109
+ function perUserConnectionString() {
110
+ const db = perUserDbName();
111
+ return `postgresql://pai:pai@localhost:5432/${db}`;
112
+ }
113
+ var DEFAULTS = {
114
+ socketPath: paiSocketPath(),
115
+ indexIntervalSecs: 300,
116
+ embedIntervalSecs: 600,
117
+ embedOnStartup: false,
118
+ storageBackend: "sqlite",
119
+ postgres: {
120
+ connectionString: perUserConnectionString(),
121
+ maxConnections: 5,
122
+ connectionTimeoutMs: 5e3
123
+ },
124
+ embeddingModel: "Snowflake/snowflake-arctic-embed-m-v1.5",
125
+ logLevel: "info",
126
+ notifications: DEFAULT_NOTIFICATION_CONFIG,
127
+ tasks: DEFAULT_TASK_CONFIG,
128
+ // Deliberately empty. An install must not guess who the user is: a wrong
129
+ // guess here is an address that can be mailed without review.
130
+ identity: { selfEmails: [] },
131
+ search: {
132
+ mode: "keyword",
133
+ rerank: true,
134
+ recencyBoostDays: 90,
135
+ defaultLimit: 10,
136
+ snippetLength: 200
137
+ }
138
+ };
139
+ var CONFIG_DIR = join(homedir(), ".config", "pai");
140
+ var CONFIG_FILE = join(CONFIG_DIR, "config.json");
141
+
142
+ // src/workers/config.ts
143
+ var MODEL_TIERS = ["haiku", "sonnet", "opus"];
144
+ var PROVIDER_TAGS = [
145
+ "code",
146
+ "vision",
147
+ "image-gen",
148
+ "long-context",
149
+ "fast",
150
+ "reasoning"
151
+ ];
152
+ var MODEL_CAPABILITIES = ["default", "fast", "image"];
153
+ function isModelCapability(v) {
154
+ return MODEL_CAPABILITIES.includes(v);
155
+ }
156
+ var DEFAULT_LOG_DIR = "~/.claude/logs/workers";
157
+ var DEFAULT_PANE = {
158
+ enabled: true,
159
+ fontSize: 13,
160
+ autoExitSecs: 60
161
+ };
162
+ var DEFAULT_ROUTING2 = {
163
+ order: [],
164
+ cooldownMinutes: 30,
165
+ retryOnQuota: true
166
+ };
167
+ var DEFAULT_TREE = {
168
+ maxDepth: 2,
169
+ maxChildren: 4
170
+ };
171
+ var DEFAULT_MCP_SETS = {
172
+ desktop: ["clickr"]
173
+ };
174
+ function defaultWorkersConfig() {
175
+ return {
176
+ enabled: false,
177
+ active: null,
178
+ providers: {},
179
+ classes: {},
180
+ mcpSets: { ...DEFAULT_MCP_SETS },
181
+ pane: { ...DEFAULT_PANE },
182
+ logDir: DEFAULT_LOG_DIR,
183
+ routing: { ...DEFAULT_ROUTING2, order: [] },
184
+ tree: { ...DEFAULT_TREE },
185
+ fallback: null
186
+ };
187
+ }
188
+ var WorkersConfigError = class extends Error {
189
+ };
190
+ function bad(path, why) {
191
+ throw new WorkersConfigError(`workers${path}: ${why}`);
192
+ }
193
+ function str(v) {
194
+ return typeof v === "string" ? v : "";
195
+ }
196
+ function parseProvider(name, raw) {
197
+ if (typeof raw !== "object" || raw === null) bad(`.providers.${name}`, "must be an object");
198
+ const p = raw;
199
+ const protocol = p.protocol === void 0 ? "anthropic" : str(p.protocol);
200
+ if (protocol !== "anthropic" && protocol !== "openai") {
201
+ bad(`.providers.${name}.protocol`, `"${str(p.protocol)}" is neither "anthropic" nor "openai"`);
202
+ }
203
+ const engine = p.engine === void 0 ? "claude" : str(p.engine);
204
+ if (engine !== "claude" && engine !== "codex") {
205
+ bad(`.providers.${name}.engine`, `"${str(p.engine)}" is neither "claude" nor "codex"`);
206
+ }
207
+ const baseUrl = str(p.baseUrl);
208
+ if (!baseUrl && protocol !== "openai") bad(`.providers.${name}.baseUrl`, "is required");
209
+ const keyFile = p.keyFile === void 0 || p.keyFile === null || str(p.keyFile) === "" ? null : str(p.keyFile);
210
+ const modelsRaw = p.models === void 0 ? {} : p.models;
211
+ if (typeof modelsRaw !== "object" || modelsRaw === null) {
212
+ bad(`.providers.${name}.models`, "must be an object");
213
+ }
214
+ const m = modelsRaw;
215
+ const defaultModel = str(m.default);
216
+ if (!defaultModel) bad(`.providers.${name}.models.default`, "is required");
217
+ const models = { default: defaultModel };
218
+ for (const key of Object.keys(m)) {
219
+ if (key === "default") continue;
220
+ if (!isModelCapability(key)) {
221
+ bad(
222
+ `.providers.${name}.models.${key}`,
223
+ `"${key}" is not a model capability (from: ${MODEL_CAPABILITIES.join(", ")})`
224
+ );
225
+ }
226
+ const id = str(m[key]);
227
+ if (!id) bad(`.providers.${name}.models.${key}`, "must be a non-empty model id");
228
+ models[key] = id;
229
+ }
230
+ let modelTiers;
231
+ if (p.modelTiers !== void 0) {
232
+ if (typeof p.modelTiers !== "object" || p.modelTiers === null || Array.isArray(p.modelTiers)) {
233
+ bad(`.providers.${name}.modelTiers`, "must be an object of model id \u2192 haiku | sonnet | opus");
234
+ }
235
+ modelTiers = {};
236
+ for (const [id, tier] of Object.entries(p.modelTiers)) {
237
+ if (typeof tier !== "string" || !MODEL_TIERS.includes(tier)) {
238
+ bad(
239
+ `.providers.${name}.modelTiers.${id}`,
240
+ `must be "haiku", "sonnet" or "opus" (got ${JSON.stringify(tier)})`
241
+ );
242
+ }
243
+ modelTiers[id] = tier;
244
+ }
245
+ }
246
+ const env = {};
247
+ if (p.env !== void 0) {
248
+ if (typeof p.env !== "object" || p.env === null || Array.isArray(p.env)) {
249
+ bad(`.providers.${name}.env`, "must be an object of string values");
250
+ }
251
+ for (const [k, v] of Object.entries(p.env)) {
252
+ if (typeof v !== "string") bad(`.providers.${name}.env.${k}`, "must be a string");
253
+ env[k] = v;
254
+ }
255
+ }
256
+ const quotaSkipAt = p.quotaSkipAt === void 0 ? void 0 : p.quotaSkipAt;
257
+ if (quotaSkipAt !== void 0) {
258
+ if (typeof quotaSkipAt !== "number" || quotaSkipAt < 0 || quotaSkipAt > 100) {
259
+ bad(`.providers.${name}.quotaSkipAt`, "must be a number between 0 and 100");
260
+ }
261
+ }
262
+ const contextWindow = p.contextWindow === void 0 ? void 0 : p.contextWindow;
263
+ if (contextWindow !== void 0) {
264
+ if (typeof contextWindow !== "number" || contextWindow <= 0) {
265
+ bad(`.providers.${name}.contextWindow`, "must be a positive number of tokens");
266
+ }
267
+ }
268
+ const upstreamUrl = str(p.upstreamUrl);
269
+ if (protocol === "openai" && !upstreamUrl) {
270
+ bad(`.providers.${name}.upstreamUrl`, `is required for protocol "openai" (the Chat Completions base, e.g. "https://api.openai.com/v1")`);
271
+ }
272
+ const costTier = p.costTier === void 0 ? void 0 : p.costTier;
273
+ if (costTier !== void 0) {
274
+ if (typeof costTier !== "number" || !Number.isInteger(costTier) || costTier < 1 || costTier > 5) {
275
+ bad(`.providers.${name}.costTier`, "must be an integer 1 (cheapest) \u2026 5 (most expensive)");
276
+ }
277
+ }
278
+ let tags;
279
+ if (p.tags !== void 0) {
280
+ if (!Array.isArray(p.tags) || p.tags.some((x) => typeof x !== "string")) {
281
+ bad(`.providers.${name}.tags`, `must be an array of tags from: ${PROVIDER_TAGS.join(", ")}`);
282
+ }
283
+ for (const t of p.tags) {
284
+ if (!PROVIDER_TAGS.includes(t)) {
285
+ bad(`.providers.${name}.tags`, `"${t}" is not a tag (from: ${PROVIDER_TAGS.join(", ")})`);
286
+ }
287
+ }
288
+ tags = p.tags;
289
+ }
290
+ return {
291
+ enabled: p.enabled === void 0 ? true : p.enabled === true,
292
+ protocol,
293
+ baseUrl,
294
+ keyFile,
295
+ models,
296
+ ...modelTiers ? { modelTiers } : {},
297
+ env,
298
+ ...str(p.note) ? { note: str(p.note) } : {},
299
+ ...upstreamUrl ? { upstreamUrl } : {},
300
+ ...engine !== "claude" ? { engine } : {},
301
+ ...str(p.quotaProbe) ? { quotaProbe: str(p.quotaProbe) } : {},
302
+ ...quotaSkipAt !== void 0 ? { quotaSkipAt } : {},
303
+ ...contextWindow !== void 0 ? { contextWindow } : {},
304
+ ...costTier !== void 0 ? { costTier } : {},
305
+ ...tags ? { tags } : {}
306
+ };
307
+ }
308
+ function parseWorkersConfig(raw) {
309
+ const d = defaultWorkersConfig();
310
+ if (raw === void 0 || raw === null) return d;
311
+ if (typeof raw !== "object" || Array.isArray(raw)) {
312
+ bad("", "section must be an object");
313
+ }
314
+ const w = raw;
315
+ const providers = {};
316
+ if (w.providers !== void 0) {
317
+ if (typeof w.providers !== "object" || w.providers === null || Array.isArray(w.providers)) {
318
+ bad(".providers", "must be an object keyed by provider name");
319
+ }
320
+ for (const [name, p] of Object.entries(w.providers)) {
321
+ providers[name] = parseProvider(name, p);
322
+ }
323
+ }
324
+ const classes = {};
325
+ const classesRaw = w.classes !== void 0 ? w.classes : w.roles;
326
+ if (classesRaw !== void 0) {
327
+ if (typeof classesRaw !== "object" || classesRaw === null || Array.isArray(classesRaw)) {
328
+ bad(w.classes !== void 0 ? ".classes" : ".roles", "must be an object of class \u2192 provider[/alias] or {provider, mcp, maxCostTier, requireTags, order}");
329
+ }
330
+ for (const [cls, target] of Object.entries(classesRaw)) {
331
+ if (typeof target === "object" && target !== null && !Array.isArray(target)) {
332
+ const o = target;
333
+ const provider = str(o.provider);
334
+ if (o.provider !== void 0 && (!provider || provider.includes(" "))) {
335
+ bad(`.classes.${cls}.provider`, `invalid provider "${provider}"`);
336
+ }
337
+ let mcp;
338
+ if (o.mcp !== void 0) {
339
+ if (!Array.isArray(o.mcp) || o.mcp.some((x) => typeof x !== "string")) {
340
+ bad(`.classes.${cls}.mcp`, "must be an array of MCP server or set names");
341
+ }
342
+ mcp = o.mcp;
343
+ }
344
+ let maxCostTier;
345
+ if (o.maxCostTier !== void 0) {
346
+ if (typeof o.maxCostTier !== "number" || !Number.isInteger(o.maxCostTier) || o.maxCostTier < 1 || o.maxCostTier > 5) {
347
+ bad(`.classes.${cls}.maxCostTier`, "must be an integer 1 \u2026 5");
348
+ }
349
+ maxCostTier = o.maxCostTier;
350
+ }
351
+ let requireTags;
352
+ if (o.requireTags !== void 0) {
353
+ if (!Array.isArray(o.requireTags) || o.requireTags.some((x) => typeof x !== "string")) {
354
+ bad(`.classes.${cls}.requireTags`, `must be an array of tags from: ${PROVIDER_TAGS.join(", ")}`);
355
+ }
356
+ for (const t of o.requireTags) {
357
+ if (!PROVIDER_TAGS.includes(t)) {
358
+ bad(`.classes.${cls}.requireTags`, `"${t}" is not a tag (from: ${PROVIDER_TAGS.join(", ")})`);
359
+ }
360
+ }
361
+ requireTags = o.requireTags;
362
+ }
363
+ let order;
364
+ if (o.order !== void 0) {
365
+ if (!Array.isArray(o.order) || o.order.some((x) => typeof x !== "string")) {
366
+ bad(`.classes.${cls}.order`, "must be an array of provider names");
367
+ }
368
+ order = o.order;
369
+ }
370
+ const obj = {
371
+ ...provider ? { provider } : {},
372
+ ...mcp ? { mcp } : {},
373
+ ...maxCostTier !== void 0 ? { maxCostTier } : {},
374
+ ...requireTags ? { requireTags } : {},
375
+ ...order ? { order } : {}
376
+ };
377
+ classes[cls] = Object.keys(obj).length ? obj : {};
378
+ } else {
379
+ const t = str(target);
380
+ if (!t || t.includes(" ")) bad(`.classes.${cls}`, `invalid target "${t}"`);
381
+ classes[cls] = t;
382
+ }
383
+ }
384
+ }
385
+ const mcpSets = { ...DEFAULT_MCP_SETS };
386
+ if (w.mcpSets !== void 0) {
387
+ if (typeof w.mcpSets !== "object" || w.mcpSets === null || Array.isArray(w.mcpSets)) {
388
+ bad(".mcpSets", "must be an object of set name \u2192 [server names]");
389
+ }
390
+ for (const [setName, servers] of Object.entries(w.mcpSets)) {
391
+ if (!Array.isArray(servers) || servers.some((x) => typeof x !== "string")) {
392
+ bad(`.mcpSets.${setName}`, "must be an array of MCP server names");
393
+ }
394
+ mcpSets[setName] = servers;
395
+ }
396
+ }
397
+ let pane = { ...DEFAULT_PANE };
398
+ if (w.pane !== void 0) {
399
+ if (typeof w.pane !== "object" || w.pane === null) bad(".pane", "must be an object");
400
+ const pc = w.pane;
401
+ if (pc.enabled !== void 0 && typeof pc.enabled !== "boolean") bad(".pane.enabled", "must be boolean");
402
+ if (pc.fontSize !== void 0 && (typeof pc.fontSize !== "number" || pc.fontSize <= 0)) {
403
+ bad(".pane.fontSize", "must be a positive number of points");
404
+ }
405
+ if (pc.autoExitSecs !== void 0 && typeof pc.autoExitSecs !== "number") {
406
+ bad(".pane.autoExitSecs", "must be a number");
407
+ }
408
+ pane = {
409
+ enabled: pc.enabled === void 0 ? DEFAULT_PANE.enabled : pc.enabled === true,
410
+ fontSize: pc.fontSize === void 0 ? DEFAULT_PANE.fontSize : pc.fontSize,
411
+ autoExitSecs: pc.autoExitSecs === void 0 ? DEFAULT_PANE.autoExitSecs : pc.autoExitSecs
412
+ };
413
+ }
414
+ let routing = { ...DEFAULT_ROUTING2, order: [] };
415
+ if (w.routing !== void 0) {
416
+ if (typeof w.routing !== "object" || w.routing === null) bad(".routing", "must be an object");
417
+ const r = w.routing;
418
+ if (r.order !== void 0) {
419
+ if (!Array.isArray(r.order) || r.order.some((x) => typeof x !== "string")) {
420
+ bad(".routing.order", "must be an array of provider names");
421
+ }
422
+ routing.order = r.order;
423
+ }
424
+ if (r.cooldownMinutes !== void 0 && typeof r.cooldownMinutes !== "number") {
425
+ bad(".routing.cooldownMinutes", "must be a number");
426
+ }
427
+ if (r.retryOnQuota !== void 0 && typeof r.retryOnQuota !== "boolean") {
428
+ bad(".routing.retryOnQuota", "must be boolean");
429
+ }
430
+ routing = {
431
+ order: routing.order,
432
+ cooldownMinutes: r.cooldownMinutes === void 0 ? DEFAULT_ROUTING2.cooldownMinutes : r.cooldownMinutes,
433
+ retryOnQuota: r.retryOnQuota === void 0 ? DEFAULT_ROUTING2.retryOnQuota : r.retryOnQuota === true
434
+ };
435
+ }
436
+ let tree = { ...DEFAULT_TREE };
437
+ if (w.tree !== void 0) {
438
+ if (typeof w.tree !== "object" || w.tree === null || Array.isArray(w.tree)) {
439
+ bad(".tree", "must be an object");
440
+ }
441
+ const t = w.tree;
442
+ if (t.maxDepth !== void 0) {
443
+ if (typeof t.maxDepth !== "number" || !Number.isInteger(t.maxDepth) || t.maxDepth < 0) {
444
+ bad(".tree.maxDepth", "must be a non-negative integer");
445
+ }
446
+ }
447
+ if (t.maxChildren !== void 0) {
448
+ if (typeof t.maxChildren !== "number" || !Number.isInteger(t.maxChildren) || t.maxChildren < 1) {
449
+ bad(".tree.maxChildren", "must be a positive integer");
450
+ }
451
+ }
452
+ tree = {
453
+ maxDepth: t.maxDepth === void 0 ? DEFAULT_TREE.maxDepth : t.maxDepth,
454
+ maxChildren: t.maxChildren === void 0 ? DEFAULT_TREE.maxChildren : t.maxChildren
455
+ };
456
+ }
457
+ const active = w.active === void 0 || w.active === null ? null : str(w.active);
458
+ if (active !== null && active !== "auto" && !(active in providers)) {
459
+ }
460
+ let fallback = null;
461
+ if (w.fallback !== void 0 && w.fallback !== null) {
462
+ if (typeof w.fallback !== "object" || Array.isArray(w.fallback)) {
463
+ bad(".fallback", "must be an object (written by `pai worker fallback on`)");
464
+ }
465
+ const f = w.fallback;
466
+ const provider = str(f.provider);
467
+ if (!provider) bad(".fallback.provider", "is required");
468
+ const savedRaw = f.saved;
469
+ if (typeof savedRaw !== "object" || savedRaw === null || Array.isArray(savedRaw)) {
470
+ bad(".fallback.saved", "must be an object");
471
+ }
472
+ const s = savedRaw;
473
+ if (typeof s.env !== "object" || s.env === null || Array.isArray(s.env)) {
474
+ bad(".fallback.saved.env", "must be an object of env key \u2192 previous value or null");
475
+ }
476
+ const env = {};
477
+ for (const [k, v] of Object.entries(s.env)) {
478
+ env[k] = v === null || typeof v === "string" ? v : null;
479
+ }
480
+ if (s.model !== null && s.model !== void 0 && typeof s.model !== "string") {
481
+ bad(".fallback.saved.model", "must be a string or null");
482
+ }
483
+ fallback = {
484
+ provider,
485
+ saved: {
486
+ env,
487
+ model: typeof s.model === "string" ? s.model : null,
488
+ envExisted: s.envExisted === true
489
+ },
490
+ on: str(f.on) || (/* @__PURE__ */ new Date(0)).toISOString()
491
+ };
492
+ }
493
+ return {
494
+ enabled: w.enabled === void 0 ? d.enabled : w.enabled === true,
495
+ active,
496
+ providers,
497
+ classes,
498
+ mcpSets,
499
+ pane,
500
+ logDir: str(w.logDir) || d.logDir,
501
+ routing,
502
+ tree,
503
+ fallback
504
+ };
505
+ }
506
+ function readWorkersSection(path = CONFIG_FILE) {
507
+ const raw = readJsonStrict(path, "~/.config/pai/config.json");
508
+ return { raw, workers: parseWorkersConfig(raw.workers) };
509
+ }
510
+ function expandHome(p) {
511
+ if (p === "~" || p.startsWith("~/")) return join2(homedir2(), p.slice(1));
512
+ return p;
513
+ }
514
+
515
+ // src/workers/paths.ts
516
+ function workersLogDir(config) {
517
+ return expandHome(config.logDir);
518
+ }
519
+
520
+ // src/hooks/ts/user-prompt/worker-supervision.ts
521
+ function readCursor(path) {
522
+ try {
523
+ return Math.max(0, Number(readFileSync2(path, "utf8").trim()) || 0);
524
+ } catch {
525
+ return 0;
526
+ }
527
+ }
528
+ function main() {
529
+ if (isWorkerSession()) return;
530
+ let raw = "";
531
+ try {
532
+ raw = readFileSync2(0, "utf8");
533
+ } catch {
534
+ return;
535
+ }
536
+ if (!raw.trim()) return;
537
+ let input;
538
+ try {
539
+ input = JSON.parse(raw);
540
+ } catch {
541
+ return;
542
+ }
543
+ const session = input.session_id;
544
+ if (!session) return;
545
+ let logDir;
546
+ try {
547
+ logDir = workersLogDir(readWorkersSection().workers);
548
+ } catch {
549
+ return;
550
+ }
551
+ const dir = join3(logDir, "supervision");
552
+ const eventsPath = join3(dir, `${session}.events`);
553
+ const cursorPath = join3(dir, `${session}.cursor`);
554
+ if (!existsSync2(eventsPath)) return;
555
+ let lines;
556
+ try {
557
+ lines = readFileSync2(eventsPath, "utf8").split("\n").filter((l) => l.trim());
558
+ } catch {
559
+ return;
560
+ }
561
+ const fresh = lines.slice(readCursor(cursorPath));
562
+ if (fresh.length === 0) return;
563
+ let pushedIds = /* @__PURE__ */ new Set();
564
+ try {
565
+ pushedIds = new Set(
566
+ readFileSync2(join3(dir, `${session}.pushed`), "utf8").split("\n").map((l) => l.trim()).filter(Boolean)
567
+ );
568
+ } catch {
569
+ }
570
+ const texts = fresh.map((l) => {
571
+ try {
572
+ const ev = JSON.parse(l);
573
+ if (ev.id && pushedIds.has(ev.id)) return null;
574
+ return ev.text ?? null;
575
+ } catch {
576
+ return null;
577
+ }
578
+ }).filter((t) => t !== null);
579
+ try {
580
+ writeFileSync2(cursorPath, String(lines.length), "utf8");
581
+ } catch {
582
+ }
583
+ if (texts.length === 0) return;
584
+ process.stdout.write(
585
+ `<system-reminder>
586
+ WORKER EVENTS (delivered by the daemon's supervision \u2014 no polling needed):
587
+ ` + texts.join("\n") + `
588
+ </system-reminder>
589
+ `
590
+ );
591
+ }
592
+ main();
593
+ //# sourceMappingURL=worker-supervision.mjs.map