pi-pier 0.2.7 → 0.3.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 (85) hide show
  1. package/README.md +26 -12
  2. package/package.json +8 -3
  3. package/schemas/efficiency-config.schema.json +77 -0
  4. package/schemas/role-manifest.schema.json +7 -1
  5. package/skills/pi-herdr-workflow/SKILL.md +11 -0
  6. package/src/ansi-text.ts +134 -0
  7. package/src/ask-dialog.ts +308 -0
  8. package/src/ask-user.ts +139 -88
  9. package/src/bootstrap.ts +13 -14
  10. package/src/compact-coordinator.ts +471 -0
  11. package/src/compact-economics-core.ts +328 -0
  12. package/src/config-catalog-core.ts +332 -0
  13. package/src/config-command.ts +388 -0
  14. package/src/dashboard-command.ts +108 -0
  15. package/src/efficiency-config-core.ts +464 -0
  16. package/src/efficiency-store.ts +299 -0
  17. package/src/focus-poller.ts +223 -0
  18. package/src/gc-core.ts +77 -18
  19. package/src/herdr-client.ts +284 -154
  20. package/src/history-store.ts +36 -23
  21. package/src/index-gates.ts +124 -0
  22. package/src/index-locks.ts +29 -16
  23. package/src/index-master.ts +29 -19
  24. package/src/index-notices.ts +35 -11
  25. package/src/index-pipe.ts +17 -7
  26. package/src/index-roles.ts +306 -0
  27. package/src/index-runtime.ts +2 -6
  28. package/src/index-worker.ts +7 -9
  29. package/src/index.ts +425 -388
  30. package/src/jev-client.ts +141 -0
  31. package/src/jev-core.ts +431 -0
  32. package/src/ledger.ts +13 -21
  33. package/src/lock-core.ts +98 -37
  34. package/src/manifest-compose.ts +35 -20
  35. package/src/observation-core.ts +200 -0
  36. package/src/pane-title.ts +19 -38
  37. package/src/pi-surface.ts +34 -22
  38. package/src/pier-options.ts +100 -0
  39. package/src/pipe-channel.ts +65 -52
  40. package/src/platform-paths.ts +19 -52
  41. package/src/{core → plugins}/grid-shape.ts +12 -12
  42. package/src/plugins/heat-plan.ts +158 -0
  43. package/src/plugins/observation.ts +475 -0
  44. package/src/plugins/subagent.ts +728 -0
  45. package/src/{core → plugins}/terminal.ts +237 -123
  46. package/src/{core → plugins}/todo.ts +75 -100
  47. package/src/progress-core.ts +16 -53
  48. package/src/reconcile-core.ts +24 -33
  49. package/src/reducer-core.ts +322 -0
  50. package/src/reducer-invoker.ts +419 -0
  51. package/src/renderers.ts +187 -0
  52. package/src/role-loader.ts +35 -29
  53. package/src/role-manifest.ts +23 -32
  54. package/src/role-state.ts +119 -0
  55. package/src/routing-telemetry.ts +136 -0
  56. package/src/runtime-policy.ts +25 -43
  57. package/src/session-tail.ts +102 -23
  58. package/src/settle-wake-core.ts +55 -22
  59. package/src/slim-frame.ts +29 -124
  60. package/src/stale-core.ts +17 -24
  61. package/src/storage-layout.ts +24 -30
  62. package/src/subagent-core.ts +256 -119
  63. package/src/subagent-gc.ts +131 -69
  64. package/src/subagent-poller.ts +401 -12
  65. package/src/subagent-session.ts +516 -0
  66. package/src/subagent-spawn.ts +651 -28
  67. package/src/swallow.ts +65 -0
  68. package/src/terminal-core.ts +160 -69
  69. package/src/todo-core.ts +62 -113
  70. package/src/todo-read-hook.ts +23 -39
  71. package/src/todo-reminder-core.ts +30 -48
  72. package/src/todo-window.ts +11 -12
  73. package/src/todos-service.ts +27 -35
  74. package/src/tool-error.ts +19 -0
  75. package/src/tool-gate.ts +38 -21
  76. package/src/vocab.ts +55 -25
  77. package/src/core/subagent.ts +0 -839
  78. package/src/git-adapter.ts +0 -104
  79. package/src/notice-buffer.ts +0 -23
  80. package/src/subagent-git-io.ts +0 -80
  81. package/src/subagent-launch.ts +0 -110
  82. package/src/subagent-poll-loop.ts +0 -285
  83. package/src/subagent-port.ts +0 -27
  84. package/src/subagent-scope.ts +0 -39
  85. package/src/subagent-session-io.ts +0 -147
@@ -1,147 +0,0 @@
1
- /**
2
- * Child-session JSONL I/O: path resolution, settlement text, liveness probes.
3
- *
4
- * Why: pollLoop, foreground wait, and revive all shared the same candidate
5
- * order (reported path/id before recent-file fallback, excluding the parent
6
- * session). Keeping it in one adapter prevents settlement text from crossing sessions.
7
- */
8
- import { stat as statCb } from 'node:fs';
9
- import { promisify } from 'node:util';
10
- import type { HerdrClientLike } from './herdr-client.ts';
11
- import {
12
- hasAssistantAfter,
13
- hasPendingToolCall,
14
- lastAssistantText,
15
- listSessionFiles,
16
- readSessionFile,
17
- sessionFileById,
18
- } from './session-tail.ts';
19
- import type { AliveProbe } from './subagent-core.ts';
20
-
21
- const statAsync = promisify(statCb);
22
-
23
- export interface SessionIoHost {
24
- client: HerdrClientLike;
25
- getSessionId: () => string;
26
- sessionsDir: () => string;
27
- }
28
-
29
- export interface SessionIo {
30
- resolveSessionFileCandidates(paneId: string, cwd: string): Promise<string[]>;
31
- resolveSessionFile(paneId: string, cwd: string): Promise<string | null>;
32
- collectFinalText(paneId: string, cwd: string, sinceTs: number, attempts?: number): Promise<string | null>;
33
- readAskFlag(paneId: string): Promise<string | null>;
34
- probeAlive(paneId: string, cwd: string): Promise<AliveProbe>;
35
- subSessionState(paneId: string, cwd: string, sinceTs: number): Promise<{ text: string | null; pendingTool: boolean; activity: boolean }>;
36
- }
37
-
38
- export function createSessionIo(h: SessionIoHost): SessionIo {
39
- async function resolveSessionFileCandidates(paneId: string, cwd: string): Promise<string[]> {
40
- const out: string[] = [];
41
- try {
42
- const reported = await h.client.getAgentSessionPath(paneId);
43
- if (reported) {
44
- if (/\.jsonl$/.test(reported)) out.push(reported);
45
- else {
46
- const byId = sessionFileById(cwd, h.sessionsDir(), reported);
47
- if (byId) out.push(byId);
48
- }
49
- }
50
- } catch {
51
- /* Reports may be unavailable during startup. */
52
- }
53
- const ownSession = h.getSessionId();
54
- for (const f of listSessionFiles(cwd, h.sessionsDir(), 4)) {
55
- if (f !== ownSession && !out.includes(f)) out.push(f);
56
- }
57
- return out;
58
- }
59
-
60
- async function resolveSessionFile(paneId: string, cwd: string): Promise<string | null> {
61
- for (const file of await resolveSessionFileCandidates(paneId, cwd)) {
62
- if (readSessionFile(file)) return file;
63
- }
64
- return null;
65
- }
66
-
67
- async function collectFinalText(
68
- paneId: string,
69
- cwd: string,
70
- sinceTs: number,
71
- attempts = 12,
72
- ): Promise<string | null> {
73
- for (let i = 0; i < attempts; i++) {
74
- for (const file of await resolveSessionFileCandidates(paneId, cwd)) {
75
- const entries = readSessionFile(file);
76
- if (!entries) continue;
77
- const r = lastAssistantText(entries, { sinceTs });
78
- if (r?.text) return r.text;
79
- }
80
- const wait = Promise.withResolvers<void>();
81
- setTimeout(wait.resolve, 500);
82
- await wait.promise;
83
- }
84
- return null;
85
- }
86
-
87
- async function readAskFlag(paneId: string): Promise<string | null> {
88
- try {
89
- const a = (await h.client.listAgents()).find((x) => x.paneId === paneId);
90
- const v = a?.tokens?.['pi-ask'];
91
- return typeof v === 'string' && v ? v : null;
92
- } catch {
93
- return null;
94
- }
95
- }
96
-
97
- async function probeAlive(paneId: string, cwd: string): Promise<AliveProbe> {
98
- const probe: AliveProbe = { paneExists: false, agentStatus: null, lastActivityMs: null };
99
- try {
100
- const agents = await h.client.listAgents();
101
- const a = agents.find((x) => x.paneId === paneId);
102
- probe.paneExists = a != null;
103
- probe.agentStatus = a?.status ?? null;
104
- } catch {
105
- /* Fall back to session activity when agent.list is unavailable. */
106
- }
107
- for (const file of await resolveSessionFileCandidates(paneId, cwd)) {
108
- try {
109
- const mtime = (await statAsync(file)).mtimeMs;
110
- if (probe.lastActivityMs == null || mtime > probe.lastActivityMs) probe.lastActivityMs = mtime;
111
- } catch {
112
- /* Session files can disappear during candidate scanning. */
113
- }
114
- }
115
- return probe;
116
- }
117
-
118
- async function subSessionState(
119
- paneId: string,
120
- cwd: string,
121
- sinceTs: number,
122
- ): Promise<{ text: string | null; pendingTool: boolean; activity: boolean }> {
123
- for (const file of await resolveSessionFileCandidates(paneId, cwd)) {
124
- const entries = readSessionFile(file);
125
- // readSessionFile returns null when the path is missing or unreadable.
126
- // herdr often reports a .jsonl path before the worker creates the file;
127
- // waitAgent(idle) then returns immediately and this path used to throw
128
- // `Cannot read properties of null (reading 'length')` (session 01a055c5).
129
- if (!entries?.length) continue;
130
- const r = lastAssistantText(entries, { sinceTs });
131
- if (r?.text) return { text: r.text, pendingTool: false, activity: true };
132
- if (hasPendingToolCall(entries, sinceTs)) return { text: null, pendingTool: true, activity: true };
133
- if (hasAssistantAfter(entries, sinceTs)) return { text: null, pendingTool: false, activity: true };
134
- }
135
- return { text: null, pendingTool: false, activity: false };
136
- }
137
-
138
- return {
139
- resolveSessionFileCandidates,
140
- resolveSessionFile,
141
- collectFinalText,
142
- readAskFlag,
143
- probeAlive,
144
- subSessionState,
145
- };
146
- }
147
-