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.
- package/README.md +26 -12
- package/package.json +8 -3
- package/schemas/efficiency-config.schema.json +77 -0
- package/schemas/role-manifest.schema.json +7 -1
- package/skills/pi-herdr-workflow/SKILL.md +11 -0
- package/src/ansi-text.ts +134 -0
- package/src/ask-dialog.ts +308 -0
- package/src/ask-user.ts +139 -88
- package/src/bootstrap.ts +13 -14
- package/src/compact-coordinator.ts +471 -0
- package/src/compact-economics-core.ts +328 -0
- package/src/config-catalog-core.ts +332 -0
- package/src/config-command.ts +388 -0
- package/src/dashboard-command.ts +108 -0
- package/src/efficiency-config-core.ts +464 -0
- package/src/efficiency-store.ts +299 -0
- package/src/focus-poller.ts +223 -0
- package/src/gc-core.ts +77 -18
- package/src/herdr-client.ts +284 -154
- package/src/history-store.ts +36 -23
- package/src/index-gates.ts +124 -0
- package/src/index-locks.ts +29 -16
- package/src/index-master.ts +29 -19
- package/src/index-notices.ts +35 -11
- package/src/index-pipe.ts +17 -7
- package/src/index-roles.ts +306 -0
- package/src/index-runtime.ts +2 -6
- package/src/index-worker.ts +7 -9
- package/src/index.ts +425 -388
- package/src/jev-client.ts +141 -0
- package/src/jev-core.ts +431 -0
- package/src/ledger.ts +13 -21
- package/src/lock-core.ts +98 -37
- package/src/manifest-compose.ts +35 -20
- package/src/observation-core.ts +200 -0
- package/src/pane-title.ts +19 -38
- package/src/pi-surface.ts +34 -22
- package/src/pier-options.ts +100 -0
- package/src/pipe-channel.ts +65 -52
- package/src/platform-paths.ts +19 -52
- package/src/{core → plugins}/grid-shape.ts +12 -12
- package/src/plugins/heat-plan.ts +158 -0
- package/src/plugins/observation.ts +475 -0
- package/src/plugins/subagent.ts +728 -0
- package/src/{core → plugins}/terminal.ts +237 -123
- package/src/{core → plugins}/todo.ts +75 -100
- package/src/progress-core.ts +16 -53
- package/src/reconcile-core.ts +24 -33
- package/src/reducer-core.ts +322 -0
- package/src/reducer-invoker.ts +419 -0
- package/src/renderers.ts +187 -0
- package/src/role-loader.ts +35 -29
- package/src/role-manifest.ts +23 -32
- package/src/role-state.ts +119 -0
- package/src/routing-telemetry.ts +136 -0
- package/src/runtime-policy.ts +25 -43
- package/src/session-tail.ts +102 -23
- package/src/settle-wake-core.ts +55 -22
- package/src/slim-frame.ts +29 -124
- package/src/stale-core.ts +17 -24
- package/src/storage-layout.ts +24 -30
- package/src/subagent-core.ts +256 -119
- package/src/subagent-gc.ts +131 -69
- package/src/subagent-poller.ts +401 -12
- package/src/subagent-session.ts +516 -0
- package/src/subagent-spawn.ts +651 -28
- package/src/swallow.ts +65 -0
- package/src/terminal-core.ts +160 -69
- package/src/todo-core.ts +62 -113
- package/src/todo-read-hook.ts +23 -39
- package/src/todo-reminder-core.ts +30 -48
- package/src/todo-window.ts +11 -12
- package/src/todos-service.ts +27 -35
- package/src/tool-error.ts +19 -0
- package/src/tool-gate.ts +38 -21
- package/src/vocab.ts +55 -25
- package/src/core/subagent.ts +0 -839
- package/src/git-adapter.ts +0 -104
- package/src/notice-buffer.ts +0 -23
- package/src/subagent-git-io.ts +0 -80
- package/src/subagent-launch.ts +0 -110
- package/src/subagent-poll-loop.ts +0 -285
- package/src/subagent-port.ts +0 -27
- package/src/subagent-scope.ts +0 -39
- 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
|
-
|