@tekmidian/pai 0.60.1 → 0.62.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 (93) hide show
  1. package/dist/{async-CLvuY7b-.mjs → async-DNVWtQl2.mjs} +2 -2
  2. package/dist/{async-CLvuY7b-.mjs.map → async-DNVWtQl2.mjs.map} +1 -1
  3. package/dist/{chain-CGyAIHo4.mjs → chain-CuaDawK9.mjs} +4 -4
  4. package/dist/{chain-CGyAIHo4.mjs.map → chain-CuaDawK9.mjs.map} +1 -1
  5. package/dist/cli/index.mjs +13 -13
  6. package/dist/cli/program.mjs +13 -13
  7. package/dist/{context-handover-cache-BzM7Qudn.mjs → context-handover-cache-DFNnlWv2.mjs} +4 -4
  8. package/dist/{context-handover-cache-BzM7Qudn.mjs.map → context-handover-cache-DFNnlWv2.mjs.map} +1 -1
  9. package/dist/daemon/index.mjs +10 -10
  10. package/dist/{daemon-B_TodsIS.mjs → daemon-Bf7Eock4.mjs} +45 -24
  11. package/dist/{daemon-B_TodsIS.mjs.map → daemon-Bf7Eock4.mjs.map} +1 -1
  12. package/dist/daemon-bJi1gDkG.mjs +19 -0
  13. package/dist/daemon-mcp/index.mjs +8 -10
  14. package/dist/daemon-mcp/index.mjs.map +1 -1
  15. package/dist/{factory-EUUhSSoq.mjs → factory-BozZa81q.mjs} +3 -3
  16. package/dist/{factory-EUUhSSoq.mjs.map → factory-BozZa81q.mjs.map} +1 -1
  17. package/dist/{factory-DW7BCJJT.mjs → factory-UO9_DFMN.mjs} +1 -1
  18. package/dist/{fallback-CjdakQVu.mjs → fallback-F0TWGVM2.mjs} +11 -13
  19. package/dist/{fallback-CjdakQVu.mjs.map → fallback-F0TWGVM2.mjs.map} +1 -1
  20. package/dist/{helpers-D9WkIf9R.mjs → helpers-Dj-B314s.mjs} +3 -2
  21. package/dist/{helpers-D9WkIf9R.mjs.map → helpers-Dj-B314s.mjs.map} +1 -1
  22. package/dist/hooks/block-sleep-poll.mjs.map +2 -2
  23. package/dist/hooks/context-compression-hook.mjs.map +1 -1
  24. package/dist/hooks/load-project-context.mjs +8513 -133
  25. package/dist/hooks/load-project-context.mjs.map +4 -4
  26. package/dist/hooks/post-compact-inject.mjs.map +1 -1
  27. package/dist/hooks/route-agents-to-worker.mjs +3 -3
  28. package/dist/hooks/route-agents-to-worker.mjs.map +2 -2
  29. package/dist/hooks/security-validator.mjs +58 -58
  30. package/dist/hooks/security-validator.mjs.map +3 -3
  31. package/dist/hooks/stop-hook.mjs +15 -15
  32. package/dist/hooks/stop-hook.mjs.map +3 -3
  33. package/dist/hooks/update-tab-on-action.mjs +14 -12
  34. package/dist/hooks/update-tab-on-action.mjs.map +3 -3
  35. package/dist/hooks/update-tab-titles.mjs +13 -9
  36. package/dist/hooks/update-tab-titles.mjs.map +3 -3
  37. package/dist/hooks/worker-guard.mjs +7859 -0
  38. package/dist/hooks/worker-guard.mjs.map +7 -0
  39. package/dist/hooks/worker-proxy.mjs +3 -3
  40. package/dist/hooks/worker-proxy.mjs.map +2 -2
  41. package/dist/hooks/worker-status-line.mjs +104 -11
  42. package/dist/hooks/worker-status-line.mjs.map +4 -4
  43. package/dist/hooks/worker-supervision.mjs +3 -3
  44. package/dist/hooks/worker-supervision.mjs.map +2 -2
  45. package/dist/index.mjs +1 -1
  46. package/dist/{indexer-backend-DcDtin1O.mjs → indexer-backend-BN9rpp9O.mjs} +2 -2
  47. package/dist/{main-resolver-BFQfU5xo.mjs → main-resolver-BIft_FVF.mjs} +4 -4
  48. package/dist/{main-resolver-BFQfU5xo.mjs.map → main-resolver-BIft_FVF.mjs.map} +1 -1
  49. package/dist/{main-resolver-VMBENifT.mjs → main-resolver-C9-poMdi.mjs} +2 -2
  50. package/dist/{planner-DN967Lvm.mjs → planner-BG9ivPj0.mjs} +6 -6
  51. package/dist/{planner-DN967Lvm.mjs.map → planner-BG9ivPj0.mjs.map} +1 -1
  52. package/dist/{postgres-nvU5pShF.mjs → postgres-CxD6_Dca.mjs} +3 -3
  53. package/dist/{postgres-nvU5pShF.mjs.map → postgres-CxD6_Dca.mjs.map} +1 -1
  54. package/dist/{program-BnsjB57Q.mjs → program-BRvCzhjx.mjs} +249 -82
  55. package/dist/program-BRvCzhjx.mjs.map +1 -0
  56. package/dist/{run-FeM1_UVa.mjs → run-BVQZI79D.mjs} +610 -253
  57. package/dist/run-BVQZI79D.mjs.map +1 -0
  58. package/dist/{run-env-CEHTeIUM.mjs → run-env-BE5xyCwy.mjs} +25 -6
  59. package/dist/run-env-BE5xyCwy.mjs.map +1 -0
  60. package/dist/{server-CekGOJcp.mjs → server-BY6AedmC.mjs} +2 -2
  61. package/dist/{server-CekGOJcp.mjs.map → server-BY6AedmC.mjs.map} +1 -1
  62. package/dist/{session-keepalive-Bc9aT678.mjs → session-keepalive-DJA97K2X.mjs} +4 -4
  63. package/dist/{session-keepalive-Bc9aT678.mjs.map → session-keepalive-DJA97K2X.mjs.map} +1 -1
  64. package/dist/{sqlite-D9p5a4qe.mjs → sqlite-CfKfuggn.mjs} +2 -2
  65. package/dist/{sqlite-D9p5a4qe.mjs.map → sqlite-CfKfuggn.mjs.map} +1 -1
  66. package/dist/{tools-r-7ZG8B5.mjs → tools-B52IvaU6.mjs} +3 -3
  67. package/dist/{tools-qXyHFwNj.mjs → tools-DFdPbX-X.mjs} +2 -2
  68. package/dist/{tools-qXyHFwNj.mjs.map → tools-DFdPbX-X.mjs.map} +1 -1
  69. package/dist/{vault-indexer-DHYBpRZ5.mjs → vault-indexer-mCFus_AM.mjs} +2 -2
  70. package/dist/{vault-indexer-DHYBpRZ5.mjs.map → vault-indexer-mCFus_AM.mjs.map} +1 -1
  71. package/dist/{wakeup-C48hcN6O.mjs → wakeup-DO1O4udw.mjs} +2 -2
  72. package/dist/{wakeup-C48hcN6O.mjs.map → wakeup-DO1O4udw.mjs.map} +1 -1
  73. package/dist/{work-queue-worker-BL4dq5P7.mjs → work-queue-worker-BbrC3I_R.mjs} +2 -2
  74. package/dist/{work-queue-worker-BL4dq5P7.mjs.map → work-queue-worker-BbrC3I_R.mjs.map} +1 -1
  75. package/dist/work-queue-worker-z-AATZ2t.mjs +11 -0
  76. package/docs/commands/README.md +2 -0
  77. package/docs/commands/worker.md +28 -0
  78. package/package.json +2 -2
  79. package/scripts/build-hooks.mjs +6 -5
  80. package/scripts/build-skill-stubs.mjs +6 -5
  81. package/src/hooks/ts/lib/tab-title.ts +18 -0
  82. package/src/hooks/ts/lib/worker-guard.test.ts +188 -0
  83. package/src/hooks/ts/lib/worker-guard.ts +315 -0
  84. package/src/hooks/ts/post-tool-use/update-tab-on-action.ts +3 -20
  85. package/src/hooks/ts/pre-tool-use/worker-guard.ts +75 -0
  86. package/src/hooks/ts/session-start/load-project-context.ts +14 -0
  87. package/src/hooks/ts/stop/stop-hook.ts +4 -15
  88. package/src/hooks/ts/user-prompt/update-tab-titles.ts +2 -10
  89. package/dist/daemon-jviL3VVJ.mjs +0 -19
  90. package/dist/program-BnsjB57Q.mjs.map +0 -1
  91. package/dist/run-FeM1_UVa.mjs.map +0 -1
  92. package/dist/run-env-CEHTeIUM.mjs.map +0 -1
  93. package/dist/work-queue-worker-DVOVcEnO.mjs +0 -11
@@ -8,7 +8,7 @@
8
8
  */
9
9
 
10
10
  import { isWorkerSession } from "../lib/worker-session.js";
11
- import { execSync } from 'child_process';
11
+ import { setTabTitle } from "../lib/tab-title.js";
12
12
 
13
13
  // Action tools that warrant a tab title update
14
14
  const ACTION_TOOLS = new Set([
@@ -60,24 +60,6 @@ async function readStdinWithTimeout(timeout: number = 3000): Promise<string> {
60
60
  });
61
61
  }
62
62
 
63
- /**
64
- * Update Kitty tab title using escape codes
65
- */
66
- function setTabTitle(title: string): void {
67
- try {
68
- // Truncate to reasonable length
69
- const truncated = title.length > 50 ? title.slice(0, 47) + '...' : title;
70
- const escaped = truncated.replace(/'/g, "'\\''");
71
-
72
- // Multiple escape sequences for compatibility
73
- execSync(`printf '\\033]0;${escaped}\\007' >&2`, { stdio: ['pipe', 'pipe', 'inherit'] });
74
- execSync(`printf '\\033]2;${escaped}\\007' >&2`, { stdio: ['pipe', 'pipe', 'inherit'] });
75
- execSync(`printf '\\033]30;${escaped}\\007' >&2`, { stdio: ['pipe', 'pipe', 'inherit'] });
76
- } catch {
77
- // Silently fail - don't interrupt Claude's work
78
- }
79
- }
80
-
81
63
  /**
82
64
  * Generate a human-readable title from tool input
83
65
  */
@@ -135,7 +117,8 @@ async function main() {
135
117
 
136
118
  // Generate and set title
137
119
  const title = generateTitle(data.tool_name, data.tool_input);
138
- setTabTitle(title);
120
+ const truncated = title.length > 50 ? title.slice(0, 47) + '...' : title;
121
+ setTabTitle(truncated);
139
122
 
140
123
  process.exit(0);
141
124
  } catch {
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * worker-guard.ts — PreToolUse (Bash|Edit|Write|MultiEdit|NotebookEdit)
5
+ *
6
+ * Worker-only (PAI_WORKER=1) enforcement of the git/worktree rules every
7
+ * worker spec used to repeat in prose and workers still broke: no symlinks
8
+ * out of the worktree, no repo copies, no push/publish/tag/version, no
9
+ * tree-rewriting git in a shared checkout, no cd into the main checkout,
10
+ * no Notes/TODO.md or live config writes, no `bun test` on a vitest repo.
11
+ * A no-op in interactive sessions.
12
+ *
13
+ * This file is only I/O: read stdin, gather the git context, print the
14
+ * decision. The decision lives in lib/worker-guard.ts and is tested there
15
+ * and through this entry.
16
+ */
17
+
18
+ import { execFileSync } from "node:child_process";
19
+ import { readFileSync } from "node:fs";
20
+ import { homedir } from "node:os";
21
+ import { dirname, join } from "node:path";
22
+ import { renderDecision } from "../lib/sleep-poll-gate.js";
23
+ import { decideWorkerGuard, type WorkerGuardContext, type WorkerGuardInput } from "../lib/worker-guard.js";
24
+
25
+ function git(cwd: string, args: string[]): string | null {
26
+ try {
27
+ return execFileSync("git", ["-C", cwd, ...args], { encoding: "utf8", timeout: 5_000, stdio: ["ignore", "pipe", "ignore"] }).trim();
28
+ } catch {
29
+ return null;
30
+ }
31
+ }
32
+
33
+ function buildContext(cwd: string): WorkerGuardContext {
34
+ const worktreeRoot = git(cwd, ["rev-parse", "--show-toplevel"]);
35
+ const gitDir = git(cwd, ["rev-parse", "--absolute-git-dir"]);
36
+ const common = git(cwd, ["rev-parse", "--path-format=absolute", "--git-common-dir"]);
37
+ const inWorktree = !!gitDir && !!common && gitDir !== common;
38
+ return {
39
+ cwd,
40
+ home: homedir(),
41
+ worktreeRoot,
42
+ inWorktree,
43
+ mainCheckout: inWorktree && common ? dirname(common) : null,
44
+ testScript: () => {
45
+ try {
46
+ const pkg = JSON.parse(readFileSync(join(worktreeRoot ?? cwd, "package.json"), "utf8"));
47
+ return typeof pkg?.scripts?.test === "string" ? pkg.scripts.test : null;
48
+ } catch {
49
+ return null;
50
+ }
51
+ },
52
+ };
53
+ }
54
+
55
+ async function main(): Promise<void> {
56
+ let text = "";
57
+ try {
58
+ for await (const chunk of process.stdin) text += chunk;
59
+ } catch {
60
+ return;
61
+ }
62
+ if (!text.trim()) return;
63
+
64
+ let input: WorkerGuardInput;
65
+ try {
66
+ input = JSON.parse(text) as WorkerGuardInput;
67
+ } catch {
68
+ return;
69
+ }
70
+
71
+ const decision = decideWorkerGuard(input, process.env, () => buildContext(input.cwd || process.cwd()));
72
+ if (decision.decision === "deny") process.stdout.write(renderDecision(decision) + "\n");
73
+ }
74
+
75
+ main().catch(() => process.exit(0));
@@ -16,6 +16,9 @@
16
16
  * - Sending ntfy.sh notifications
17
17
  */
18
18
 
19
+ import { readWorkersSection } from '../../../workers/config.js';
20
+ import { workersLogDir } from '../../../workers/paths.js';
21
+ import { pendingResults } from '../../../workers/pending.js';
19
22
  import { isWorkerSession } from "../lib/worker-session.js";
20
23
  import { existsSync, readdirSync, readFileSync, statSync } from 'fs';
21
24
  import { join, basename, dirname, resolve } from 'path';
@@ -492,6 +495,17 @@ ${paiProjectBlock ? `\n${paiProjectBlock}` : ''}
492
495
  // Output to stdout for Claude to receive
493
496
  console.log(reminder);
494
497
 
498
+ // Unmerged finished worker results in this repo: one line, none when zero
499
+ try {
500
+ const { workers } = readWorkersSection();
501
+ const pending = pendingResults(workersLogDir(workers), cwd);
502
+ if (pending.length) {
503
+ console.log(`${pending.length} finished worker result(s) not merged in this repo: ${pending.map((r) => r.id).join(', ')} — run \`pai worker pending\``);
504
+ }
505
+ } catch {
506
+ // no workers config or not a git repo: stay silent
507
+ }
508
+
495
509
  // 8.5. INJECT THE PAUSE CHECKPOINT
496
510
  //
497
511
  // `pai pause` writes the handover to TODO.md under `## Continue`. Until now
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { isWorkerSession } from "../lib/worker-session.js";
4
+ import { setTabTitle } from "../lib/tab-title.js";
4
5
  import { readFileSync, writeFileSync, mkdirSync, existsSync, unlinkSync } from 'fs';
5
6
  import { join, basename, dirname } from 'path';
6
7
  import { connect } from 'net';
@@ -599,11 +600,7 @@ async function executeDirectly(
599
600
 
600
601
  if (tabTitle) {
601
602
  try {
602
- const escapedTitle = tabTitle.replace(/'/g, "'\\''");
603
- const { execSync } = await import('child_process');
604
- execSync(`printf '\\033]0;${escapedTitle}\\007' >&2`);
605
- execSync(`printf '\\033]2;${escapedTitle}\\007' >&2`);
606
- execSync(`printf '\\033]30;${escapedTitle}\\007' >&2`);
603
+ setTabTitle(tabTitle);
607
604
  console.error(`Tab title set to: "${tabTitle}"`);
608
605
  } catch (e) {
609
606
  console.error(`Failed to set tab title: ${e}`);
@@ -856,11 +853,7 @@ async function main() {
856
853
  }
857
854
  if (tabTitle) {
858
855
  try {
859
- const { execSync } = await import('child_process');
860
- const escapedTitle = tabTitle.replace(/'/g, "'\\''");
861
- execSync(`printf '\\033]0;${escapedTitle}\\007' >&2`);
862
- execSync(`printf '\\033]2;${escapedTitle}\\007' >&2`);
863
- execSync(`printf '\\033]30;${escapedTitle}\\007' >&2`);
856
+ setTabTitle(tabTitle);
864
857
  console.error(`Tab title set to: "${tabTitle}"`);
865
858
  } catch (e) {
866
859
  console.error(`Failed to set tab title: ${e}`);
@@ -876,11 +869,7 @@ async function main() {
876
869
  const persistentName = await getPersistentTabName();
877
870
  if (persistentName) {
878
871
  try {
879
- const { execSync } = await import('child_process');
880
- const escaped = persistentName.replace(/'/g, "'\\''");
881
- execSync(`printf '\\033]0;${escaped}\\007' >&2`);
882
- execSync(`printf '\\033]2;${escaped}\\007' >&2`);
883
- execSync(`printf '\\033]30;${escaped}\\007' >&2`);
872
+ setTabTitle(persistentName);
884
873
  process.stderr.write(`\x1b]2;${persistentName.slice(0, 50)}\x07`);
885
874
  console.error(`Tab title re-asserted to persistent name: "${persistentName}"`);
886
875
  } catch (e) {
@@ -7,7 +7,7 @@
7
7
  */
8
8
 
9
9
  import { isWorkerSession } from "../lib/worker-session.js";
10
- import { execSync } from 'child_process';
10
+ import { setTabTitle } from "../lib/tab-title.js";
11
11
 
12
12
  interface HookInput {
13
13
  session_id: string;
@@ -69,15 +69,7 @@ async function main() {
69
69
  }
70
70
 
71
71
  // Set initial tab title with recycle emoji
72
- try {
73
- const titleWithEmoji = '♻️ ' + tabTitle;
74
- const escapedTitle = titleWithEmoji.replace(/'/g, "'\\''");
75
- execSync(`printf '\\033]0;${escapedTitle}\\007' >&2`);
76
- execSync(`printf '\\033]2;${escapedTitle}\\007' >&2`);
77
- execSync(`printf '\\033]30;${escapedTitle}\\007' >&2`);
78
- } catch (e) {
79
- // Silently fail
80
- }
72
+ setTabTitle('♻️ ' + tabTitle);
81
73
 
82
74
  process.exit(0);
83
75
  } catch (error) {
@@ -1,19 +0,0 @@
1
- import "./utils-C9HsYDpO.mjs";
2
- import "./migrate-BD7D8EEh.mjs";
3
- import "./factory-EUUhSSoq.mjs";
4
- import "./wakeup-C48hcN6O.mjs";
5
- import "./context-handover-cache-BzM7Qudn.mjs";
6
- import "./config-CQCmH_gV.mjs";
7
- import "./run-env-CEHTeIUM.mjs";
8
- import "./run-FeM1_UVa.mjs";
9
- import "./server-CekGOJcp.mjs";
10
- import "./state-n13uPK5B.mjs";
11
- import "./aibroker-client-BK1h--W_.mjs";
12
- import "./session-keepalive-Bc9aT678.mjs";
13
- import "./embeddings-DfrYNIng.mjs";
14
- import { t as serve } from "./daemon-B_TodsIS.mjs";
15
- import "./router-DjFZIoDl.mjs";
16
- import "./tools-qXyHFwNj.mjs";
17
- import "./work-queue-worker-BL4dq5P7.mjs";
18
-
19
- export { serve };