pi-legion 0.16.0 → 2.0.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 (89) hide show
  1. package/CONTRIBUTING.md +58 -0
  2. package/README.md +313 -640
  3. package/agents/advisor.md +7 -5
  4. package/agents/centurion.md +53 -0
  5. package/agents/designer.md +33 -33
  6. package/agents/planner.md +1 -2
  7. package/agents/prototype.md +2 -2
  8. package/agents/reviewer.md +67 -31
  9. package/agents/scout.md +6 -2
  10. package/agents/worker.md +12 -3
  11. package/docs/contracts/esc-abort-v1.md +131 -0
  12. package/docs/contracts/esc-cascade-v2.md +100 -0
  13. package/docs/design.md +44 -25
  14. package/docs/legion-v2-contract.md +461 -0
  15. package/docs/legion-v2-delivery.md +62 -0
  16. package/docs/retire-hardening-contract.md +125 -0
  17. package/docs/subagents-teams.md +76 -0
  18. package/docs/tui-viewer-contract.md +276 -0
  19. package/docs/vexillatio-contract.md +162 -0
  20. package/index.ts +1462 -286
  21. package/package.json +12 -9
  22. package/skills/pi-legion/SKILL.md +74 -96
  23. package/src/agents/agents.ts +6 -11
  24. package/src/agents/overrides.ts +2 -1
  25. package/src/agents/paths.ts +1 -1
  26. package/src/agents/settings.ts +268 -20
  27. package/src/api.ts +47 -48
  28. package/src/{herdr → backends/legacy}/client.ts +14 -69
  29. package/src/{shared → backends/legacy}/cursor-chat.ts +2 -2
  30. package/src/{herdr → backends/legacy}/runner.ts +22 -9
  31. package/src/backends/legacy/types.ts +138 -0
  32. package/src/extension/auto-doctor.ts +144 -0
  33. package/src/extension/budget.ts +2 -2
  34. package/src/extension/child-guard.ts +214 -201
  35. package/src/extension/event-bus.ts +263 -0
  36. package/src/extension/legion-commands.ts +719 -0
  37. package/src/extension/legion-doctor.ts +888 -0
  38. package/src/extension/legion-stop.ts +150 -0
  39. package/src/extension/legion-tools.ts +816 -0
  40. package/src/extension/notify.ts +24 -19
  41. package/src/extension/playbook.ts +20 -89
  42. package/src/extension/recycle.ts +2 -7
  43. package/src/extension/runtime.ts +655 -105
  44. package/src/extension/scout-guard.ts +483 -0
  45. package/src/extension/slash.ts +89 -438
  46. package/src/extension/spawn-hints.ts +79 -0
  47. package/src/extension/summary.ts +17 -58
  48. package/src/legion/budget.ts +165 -0
  49. package/src/legion/db.ts +242 -0
  50. package/src/legion/events.ts +150 -0
  51. package/src/legion/mail.ts +412 -0
  52. package/src/legion/nodes.ts +461 -0
  53. package/src/legion/rebuild.ts +533 -0
  54. package/src/legion/state-machine.ts +313 -0
  55. package/src/legion/usage.ts +101 -0
  56. package/src/runs/acceptance.ts +82 -25
  57. package/src/runs/args.ts +51 -5
  58. package/src/runs/hygiene.ts +335 -0
  59. package/src/runs/orchestrator.ts +790 -1683
  60. package/src/runs/owner.ts +61 -0
  61. package/src/runs/provision.ts +135 -0
  62. package/src/runs/store.ts +44 -17
  63. package/src/runs/verify-queue.ts +195 -0
  64. package/src/shared/name.ts +29 -0
  65. package/src/shared/output-cap.ts +57 -0
  66. package/src/shared/progress.ts +57 -135
  67. package/src/shared/session.ts +243 -171
  68. package/src/shared/types.ts +107 -208
  69. package/src/supervisor/child-memory.ts +140 -0
  70. package/src/supervisor/proc-tree.ts +103 -0
  71. package/src/supervisor/rpc-supervisor.ts +1033 -0
  72. package/src/supervisor/types.ts +153 -0
  73. package/src/supervisor/ui-proxy.ts +226 -0
  74. package/src/tui/chat-items.ts +330 -0
  75. package/src/tui/live-overlay.ts +874 -0
  76. package/src/tui/status.ts +553 -27
  77. package/src/tui/tree-view.ts +808 -0
  78. package/src/tui/viz/canvas.ts +119 -0
  79. package/src/tui/viz/layout.ts +111 -0
  80. package/src/tui/viz/model.ts +123 -0
  81. package/src/tui/viz/palette.ts +188 -0
  82. package/src/tui/viz/panels.ts +530 -0
  83. package/src/tui/viz/railway.ts +313 -0
  84. package/src/tui/viz/rate.ts +211 -0
  85. package/src/tui/viz/view.ts +228 -0
  86. package/src/extension/parent-label.ts +0 -115
  87. package/src/profiles/classify.ts +0 -375
  88. package/src/profiles/profiles.ts +0 -730
  89. package/src/runs/layout.ts +0 -258
@@ -0,0 +1,103 @@
1
+ import { readFileSync, readdirSync } from "node:fs";
2
+ import type { DescendantInfo } from "./types.ts";
3
+
4
+ const PROC_ROOT = "/proc";
5
+
6
+ interface ProcStat {
7
+ pid: number;
8
+ ppid: number;
9
+ pgid: number;
10
+ }
11
+
12
+ function parseStatId(value: string | undefined): number | null {
13
+ if (value === undefined || !/^\d+$/.test(value)) return null;
14
+ const parsed = Number(value);
15
+ return Number.isFinite(parsed) ? parsed : null;
16
+ }
17
+
18
+ /** Parse the PID, parent PID, and process group from one Linux proc stat row. */
19
+ export function parseProcStatLine(
20
+ line: string,
21
+ ): { pid: number; ppid: number; pgid: number } | null {
22
+ const pidEnd = line.indexOf(" ");
23
+ if (pidEnd <= 0 || line[pidEnd + 1] !== "(") return null;
24
+ const pid = parseStatId(line.slice(0, pidEnd));
25
+ if (pid === null) return null;
26
+
27
+ // comm is parenthesized but may itself contain spaces and parentheses.
28
+ const commEnd = line.lastIndexOf(")");
29
+ if (commEnd <= pidEnd + 1) return null;
30
+ const fields = line.slice(commEnd + 1).trim().split(/\s+/);
31
+ if (fields.length < 3 || !fields[0]) return null;
32
+ const ppid = parseStatId(fields[1]);
33
+ const pgid = parseStatId(fields[2]);
34
+ if (ppid === null || pgid === null) return null;
35
+
36
+ return { pid, ppid, pgid };
37
+ }
38
+
39
+ /**
40
+ * Enumerate every process whose /proc parent chain leads to rootPid.
41
+ * Descendants are returned breadth-first and never include rootPid itself.
42
+ */
43
+ export function enumerateDescendants(rootPid: number): DescendantInfo[] {
44
+ if (process.platform !== "linux" || !Number.isSafeInteger(rootPid) || rootPid <= 0) {
45
+ return [];
46
+ }
47
+
48
+ let entries: string[];
49
+ try {
50
+ entries = readdirSync(PROC_ROOT);
51
+ } catch {
52
+ return [];
53
+ }
54
+
55
+ const processes = new Map<number, ProcStat>();
56
+ for (const entry of entries) {
57
+ if (!/^\d+$/.test(entry)) continue;
58
+ let line: string;
59
+ try {
60
+ line = readFileSync(`${PROC_ROOT}/${entry}/stat`, "utf8");
61
+ } catch {
62
+ // Processes can exit between readdir and reading their stat file.
63
+ continue;
64
+ }
65
+ const stat = parseProcStatLine(line);
66
+ if (stat) processes.set(stat.pid, stat);
67
+ }
68
+
69
+ if (!processes.has(rootPid)) return [];
70
+
71
+ const children = new Map<number, number[]>();
72
+ for (const stat of processes.values()) {
73
+ const siblings = children.get(stat.ppid);
74
+ if (siblings) siblings.push(stat.pid);
75
+ else children.set(stat.ppid, [stat.pid]);
76
+ }
77
+
78
+ const descendants: DescendantInfo[] = [];
79
+ const queue = [rootPid];
80
+ const visited = new Set(queue);
81
+ for (let index = 0; index < queue.length; index += 1) {
82
+ const parentPid = queue[index];
83
+ if (parentPid === undefined) continue;
84
+ for (const pid of children.get(parentPid) ?? []) {
85
+ if (visited.has(pid)) continue;
86
+ visited.add(pid);
87
+ queue.push(pid);
88
+ const stat = processes.get(pid);
89
+ if (stat) descendants.push({ pid: stat.pid, pgid: stat.pgid });
90
+ }
91
+ }
92
+ return descendants;
93
+ }
94
+
95
+ /** Return this process's process group ID when Linux procfs is available. */
96
+ export function currentPgid(): number | null {
97
+ if (process.platform === "win32") return null;
98
+ try {
99
+ return parseProcStatLine(readFileSync(`${PROC_ROOT}/self/stat`, "utf8"))?.pgid ?? null;
100
+ } catch {
101
+ return null;
102
+ }
103
+ }