@comput/pi-intercom 0.6.1 → 0.9.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.
- package/README.md +113 -8
- package/dist/config.d.ts +12 -0
- package/dist/config.js +94 -22
- package/dist/config.js.map +1 -1
- package/dist/core-monitor.d.ts +30 -0
- package/dist/core-monitor.js +528 -0
- package/dist/core-monitor.js.map +1 -0
- package/dist/core-pane-close.d.ts +34 -0
- package/dist/core-pane-close.js +335 -0
- package/dist/core-pane-close.js.map +1 -0
- package/dist/core-worker-layout.d.ts +50 -0
- package/dist/core-worker-layout.js +236 -0
- package/dist/core-worker-layout.js.map +1 -0
- package/dist/herdr-core.d.ts +53 -0
- package/dist/herdr-core.js +380 -0
- package/dist/herdr-core.js.map +1 -0
- package/dist/index.js +60 -14
- package/dist/index.js.map +1 -1
- package/dist/launcher.d.ts +2 -0
- package/dist/launcher.js +59 -3
- package/dist/launcher.js.map +1 -1
- package/dist/monitor-launcher.d.ts +8 -0
- package/dist/monitor-launcher.js +111 -25
- package/dist/monitor-launcher.js.map +1 -1
- package/dist/pane-close.js +3 -0
- package/dist/pane-close.js.map +1 -1
- package/dist/reminders.d.ts +28 -0
- package/dist/reminders.js +81 -0
- package/dist/reminders.js.map +1 -0
- package/dist/runtime.d.ts +28 -2
- package/dist/runtime.js +139 -11
- package/dist/runtime.js.map +1 -1
- package/package.json +14 -6
- package/references/herdr-core-migration.md +44 -0
- package/references/releasing.md +90 -0
- package/references/v1-specification.md +11 -8
- package/src/config.ts +69 -17
- package/src/core-monitor.ts +410 -0
- package/src/core-pane-close.ts +328 -0
- package/src/core-worker-layout.ts +240 -0
- package/src/herdr-core.ts +287 -0
- package/src/index.ts +55 -15
- package/src/launcher.ts +55 -3
- package/src/monitor-launcher.ts +95 -21
- package/src/pane-close.ts +2 -0
- package/src/reminders.ts +69 -0
- package/src/runtime.ts +122 -12
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
import { execFile, spawn } from 'node:child_process';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { createConnection } from 'node:net';
|
|
4
|
+
import { isAbsolute, join } from 'node:path';
|
|
5
|
+
import { homedir } from 'node:os';
|
|
6
|
+
import { lstat } from 'node:fs/promises';
|
|
7
|
+
const failure = (message) => new Error(`PiIntercom Herdr core: ${message}`);
|
|
8
|
+
const MAX_BYTES = 1024 * 1024;
|
|
9
|
+
const CORE_VERSION = '0.1.18';
|
|
10
|
+
const object = (value) => value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
11
|
+
const identity = (value) => object(value) && typeof value.id === 'string' && value.id.length > 0 &&
|
|
12
|
+
value.id.length <= 256 && typeof value.name === 'string';
|
|
13
|
+
const statusValid = (value) => object(value) && value.version === CORE_VERSION && identity(value.core) &&
|
|
14
|
+
Number.isSafeInteger(value.pid) && value.pid > 0;
|
|
15
|
+
const sameCore = (a, b) => a.id === b.id && a.name === b.name;
|
|
16
|
+
const READ_METHODS = new Set(['hello', 'server.status', 'terminal.get', 'terminal.list', 'doc.get']);
|
|
17
|
+
/** Resolve only documented Unix defaults. An existing config may override the
|
|
18
|
+
* socket, so require explicit HC_SOCKET rather than silently ignoring that file. */
|
|
19
|
+
export async function defaultCoreEndpoint(env = process.env, home = homedir(), uid = process.getuid?.()) {
|
|
20
|
+
if (env.HC_SOCKET !== undefined) {
|
|
21
|
+
if (!env.HC_SOCKET || !isAbsolute(env.HC_SOCKET) || env.HC_SOCKET.includes('\0'))
|
|
22
|
+
throw failure('invalid explicit HC_SOCKET');
|
|
23
|
+
return env.HC_SOCKET;
|
|
24
|
+
}
|
|
25
|
+
const session = env.HC_SESSION ?? 'default';
|
|
26
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(session) || session.trim() !== session || session.length > 64)
|
|
27
|
+
throw failure('unsupported HC_SESSION; set explicit HC_SOCKET');
|
|
28
|
+
const config = join(env.XDG_CONFIG_HOME || join(home, '.config'), 'herdr-core', 'config.toml');
|
|
29
|
+
try {
|
|
30
|
+
await lstat(config);
|
|
31
|
+
throw failure('core config may override socket; set explicit HC_SOCKET');
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
if (error.code !== 'ENOENT')
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
let runtime = env.XDG_RUNTIME_DIR;
|
|
38
|
+
if (!runtime && uid !== undefined) {
|
|
39
|
+
const candidate = `/run/user/${uid}`;
|
|
40
|
+
try {
|
|
41
|
+
if ((await lstat(candidate)).isDirectory())
|
|
42
|
+
runtime = candidate;
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
if (error.code !== 'ENOENT')
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const base = runtime ? join(runtime, 'herdr-core') : join(env.XDG_STATE_HOME || join(home, '.local', 'state'), 'herdr-core', session);
|
|
50
|
+
if (!isAbsolute(base))
|
|
51
|
+
throw failure('core endpoint root must be absolute');
|
|
52
|
+
return join(base, `${session}.sock`);
|
|
53
|
+
}
|
|
54
|
+
function cliStatus() {
|
|
55
|
+
return new Promise((resolve, reject) => {
|
|
56
|
+
execFile('hc', ['server', 'status', '--json'], { windowsHide: true, timeout: 3000, maxBuffer: MAX_BYTES, encoding: 'utf8' }, (error, stdout) => {
|
|
57
|
+
if (error)
|
|
58
|
+
return reject(failure('existing core status preflight failed'));
|
|
59
|
+
try {
|
|
60
|
+
resolve(JSON.parse(stdout));
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
reject(failure('invalid core status preflight'));
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/** One bounded, sequential operation on ONE verified connection; never reconnects.
|
|
69
|
+
* Core v0.1.18 schema hello + server.status bind protocol, version, permanent core
|
|
70
|
+
* identity and (with CLI preflight) pid before the callback can send requests.
|
|
71
|
+
* This is not cryptographic authentication or a boot nonce; local endpoint access
|
|
72
|
+
* is the upstream trust boundary. The call handle expires with the callback.
|
|
73
|
+
*
|
|
74
|
+
* IMPORTANT: v0.1.18 cli.rs/server + platform/unix.rs status_may_start_core() show
|
|
75
|
+
* `hc server status` ITSELF autostarts on Unix. Unix therefore connects directly
|
|
76
|
+
* via HC_SOCKET or documented defaults (only when no config override can exist),
|
|
77
|
+
* without starting a process.
|
|
78
|
+
* Public contract: herdr-core v0.1.18 schema/README.md "Connecting" and
|
|
79
|
+
* docs/security.md "State and endpoints". No undocumented endpoint discovery.
|
|
80
|
+
* On Windows only, status is require_existing; preflight precedes hc connect.
|
|
81
|
+
* That check is NOT atomic start avoidance: core could disappear before connect.
|
|
82
|
+
* Use an explicit endpoint even on Windows when strict no-autostart is required.
|
|
83
|
+
*/
|
|
84
|
+
export async function withCoreSession(operation, options = {}) {
|
|
85
|
+
const timeoutMs = options.timeoutMs ?? 10000;
|
|
86
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0 || timeoutMs > 10000)
|
|
87
|
+
throw failure('invalid session deadline');
|
|
88
|
+
let input, output, cleanup;
|
|
89
|
+
let closed = false, fatal, mutationAttempted = false;
|
|
90
|
+
let pending;
|
|
91
|
+
let rejectSession;
|
|
92
|
+
const failed = new Promise((_, reject) => { rejectSession = reject; });
|
|
93
|
+
const close = () => {
|
|
94
|
+
if (closed)
|
|
95
|
+
return;
|
|
96
|
+
closed = true;
|
|
97
|
+
try {
|
|
98
|
+
cleanup?.();
|
|
99
|
+
}
|
|
100
|
+
catch { /* Closing our transport must not mask the result. */ }
|
|
101
|
+
};
|
|
102
|
+
const fail = (reason) => {
|
|
103
|
+
if (closed || fatal)
|
|
104
|
+
return;
|
|
105
|
+
fatal = Object.assign(failure(`${reason}; session unusable; ${mutationAttempted ? 'outcome uncertain; ' : ''}do not replay`), { uncertain: mutationAttempted });
|
|
106
|
+
pending?.reject(fatal);
|
|
107
|
+
pending = undefined;
|
|
108
|
+
rejectSession(fatal);
|
|
109
|
+
close();
|
|
110
|
+
};
|
|
111
|
+
const timer = setTimeout(() => fail('operation timed out'), timeoutMs);
|
|
112
|
+
let methods, requests = 0, bytes = 0, buffer = '';
|
|
113
|
+
const decoder = new TextDecoder('utf-8', { fatal: true });
|
|
114
|
+
const call = (method, params) => {
|
|
115
|
+
if (closed || fatal)
|
|
116
|
+
return Promise.reject(fatal ?? failure('session is closed; do not replay'));
|
|
117
|
+
if (pending || ++requests > 64 || (methods && !methods.has(method))) {
|
|
118
|
+
fail('concurrent, excessive or unsupported API request');
|
|
119
|
+
return Promise.reject(fatal);
|
|
120
|
+
}
|
|
121
|
+
const id = randomUUID();
|
|
122
|
+
let request;
|
|
123
|
+
try {
|
|
124
|
+
request = `${JSON.stringify({ jsonrpc: '2.0', id, method, params })}\n`;
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
fail('invalid API request');
|
|
128
|
+
return Promise.reject(fatal);
|
|
129
|
+
}
|
|
130
|
+
if (Buffer.byteLength(request) > MAX_BYTES) {
|
|
131
|
+
fail('API request exceeded limit');
|
|
132
|
+
return Promise.reject(fatal);
|
|
133
|
+
}
|
|
134
|
+
return new Promise((resolve, reject) => {
|
|
135
|
+
pending = { id, resolve, reject };
|
|
136
|
+
if (!READ_METHODS.has(method))
|
|
137
|
+
mutationAttempted = true;
|
|
138
|
+
try {
|
|
139
|
+
input.write(request, error => { if (error)
|
|
140
|
+
fail('API request transport failed'); });
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
fail('API request transport failed');
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
};
|
|
147
|
+
const run = async () => {
|
|
148
|
+
let before;
|
|
149
|
+
const endpoint = options.endpoint ?? process.env.HC_SOCKET ?? (!options.startClient && process.platform !== 'win32' ? await defaultCoreEndpoint() : undefined);
|
|
150
|
+
if (options.startClient || !endpoint) {
|
|
151
|
+
if (options.startClient && !options.readStatus)
|
|
152
|
+
throw failure('test client requires status preflight');
|
|
153
|
+
if (!options.startClient && process.platform !== 'win32')
|
|
154
|
+
throw failure('explicit HC_SOCKET required: Unix hc server status/connect may autostart; no client started');
|
|
155
|
+
before = await (options.readStatus ?? cliStatus)();
|
|
156
|
+
if (closed)
|
|
157
|
+
throw fatal;
|
|
158
|
+
if (!statusValid(before))
|
|
159
|
+
throw failure('unsupported core status/version; no client started');
|
|
160
|
+
const child = options.startClient ? options.startClient() : spawn('hc', ['connect'], { windowsHide: true, stdio: ['pipe', 'pipe', 'pipe'] });
|
|
161
|
+
input = child.stdin;
|
|
162
|
+
output = child.stdout;
|
|
163
|
+
cleanup = () => { child.stdin.destroy(); child.stdout.destroy(); child.stderr.destroy(); child.kill(); };
|
|
164
|
+
child.on('error', () => fail('could not start hc API client'));
|
|
165
|
+
child.on('close', () => fail('API client ended without operation completion'));
|
|
166
|
+
child.stderr.on('error', () => fail('API diagnostic transport failed'));
|
|
167
|
+
child.stderr.on('data', () => { }); // Never expose process diagnostics or credentials.
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
if (!isAbsolute(endpoint) || endpoint.includes('\0'))
|
|
171
|
+
throw failure('explicit absolute local core endpoint required');
|
|
172
|
+
const socket = createConnection(endpoint);
|
|
173
|
+
input = output = socket;
|
|
174
|
+
cleanup = () => { socket.destroy(); };
|
|
175
|
+
socket.on('close', () => fail('API connection closed'));
|
|
176
|
+
}
|
|
177
|
+
input.on('error', () => fail('API request transport failed'));
|
|
178
|
+
output.on('error', () => fail('API response transport failed'));
|
|
179
|
+
output.on('end', () => fail('API response EOF; operation not completed'));
|
|
180
|
+
output.on('data', (chunk) => {
|
|
181
|
+
if (closed)
|
|
182
|
+
return;
|
|
183
|
+
if (!pending)
|
|
184
|
+
return fail('unsolicited API response data');
|
|
185
|
+
bytes += chunk.length;
|
|
186
|
+
if (bytes > MAX_BYTES)
|
|
187
|
+
return fail('API response exceeded operation limit');
|
|
188
|
+
try {
|
|
189
|
+
buffer += decoder.decode(chunk, { stream: true });
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
return fail('invalid API response UTF-8');
|
|
193
|
+
}
|
|
194
|
+
const end = buffer.indexOf('\n');
|
|
195
|
+
if (end < 0)
|
|
196
|
+
return;
|
|
197
|
+
try {
|
|
198
|
+
decoder.decode();
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
return fail('invalid trailing API response UTF-8');
|
|
202
|
+
}
|
|
203
|
+
const line = buffer.slice(0, end);
|
|
204
|
+
// Sequential request/reply only: reject unsolicited/trailing data, including
|
|
205
|
+
// a partial next response, BEFORE allowing the callback's next mutation.
|
|
206
|
+
if (buffer.slice(end + 1).trim())
|
|
207
|
+
return fail('trailing API response data');
|
|
208
|
+
buffer = '';
|
|
209
|
+
let message;
|
|
210
|
+
try {
|
|
211
|
+
message = JSON.parse(line);
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
return fail('invalid API response');
|
|
215
|
+
}
|
|
216
|
+
if (!object(message) || !pending || message.id !== pending.id)
|
|
217
|
+
return fail('uncorrelated API response');
|
|
218
|
+
if (message.jsonrpc !== '2.0' || Object.hasOwn(message, 'error') || !Object.hasOwn(message, 'result'))
|
|
219
|
+
return fail('API rejected request');
|
|
220
|
+
const current = pending;
|
|
221
|
+
pending = undefined;
|
|
222
|
+
current.resolve(message.result);
|
|
223
|
+
});
|
|
224
|
+
const hello = await call('hello', { generation: 1, framed: false });
|
|
225
|
+
if (!object(hello) || hello.generation !== 1 || hello.version !== CORE_VERSION || hello.framed !== false ||
|
|
226
|
+
!identity(hello.core) || !Array.isArray(hello.methods) || !hello.methods.every((v) => typeof v === 'string') ||
|
|
227
|
+
!Array.isArray(hello.features) || !hello.features.every((v) => typeof v === 'string') ||
|
|
228
|
+
(before && !sameCore(hello.core, before.core)))
|
|
229
|
+
throw failure('unsupported or changed core handshake');
|
|
230
|
+
methods = new Set(hello.methods);
|
|
231
|
+
const status = await call('server.status', {});
|
|
232
|
+
if (!statusValid(status) || !sameCore(status.core, hello.core) || (before && status.pid !== before.pid))
|
|
233
|
+
throw failure('core instance changed before operation');
|
|
234
|
+
const result = await operation(call);
|
|
235
|
+
if (fatal)
|
|
236
|
+
throw fatal; // Catching a request failure never rehabilitates a session.
|
|
237
|
+
if (pending) {
|
|
238
|
+
fail('callback left an unfinished API request');
|
|
239
|
+
throw fatal;
|
|
240
|
+
}
|
|
241
|
+
return result;
|
|
242
|
+
};
|
|
243
|
+
try {
|
|
244
|
+
return await Promise.race([run(), failed]);
|
|
245
|
+
}
|
|
246
|
+
catch (error) {
|
|
247
|
+
if (mutationAttempted && !(error instanceof Error && 'uncertain' in error)) {
|
|
248
|
+
throw Object.assign(failure('operation failed after mutation; outcome uncertain; do not replay'), { uncertain: true, cause: error });
|
|
249
|
+
}
|
|
250
|
+
throw error;
|
|
251
|
+
}
|
|
252
|
+
finally {
|
|
253
|
+
clearTimeout(timer);
|
|
254
|
+
close();
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
/** Standalone compatibility API: one call per bounded session. Multi-call operations
|
|
258
|
+
* MUST use withCoreSession, not repeated coreCall invocations. */
|
|
259
|
+
export const coreCall = (method, params) => withCoreSession(call => call(method, params));
|
|
260
|
+
export function terminalAddress(value) {
|
|
261
|
+
if (typeof value !== 'string' || (!/^t[0-9a-z]+$/.test(value) || value.trim() !== value))
|
|
262
|
+
throw failure('explicit local HC_TERMINAL_ID required');
|
|
263
|
+
}
|
|
264
|
+
/** SOURCE-BACKED PRIVATE FORMAT, not a stable app API or production-readiness claim.
|
|
265
|
+
* herdr-app v0.1.13 src/mirror.rs Document/SharedSpace/SharedTab and src/layout.rs
|
|
266
|
+
* Node/Kind/Content define this opaque core doc. There is NO app-version handshake:
|
|
267
|
+
* core 0.1.18 alone cannot establish app compatibility. An upstream versioned
|
|
268
|
+
* layout contract is still needed. Tested subset: rows/columns, terminal/mod blocks,
|
|
269
|
+
* and mod-only floats (src/layout.rs Float), whose IDs are checked too. Reject
|
|
270
|
+
* stacks, terminal floats and dynamic context/agent content anywhere, including
|
|
271
|
+
* unrelated tabs, rather than silently miss aliases.
|
|
272
|
+
* Unknown metadata is preserved verbatim, not interpreted as a layout extension.
|
|
273
|
+
* Private focus state is separate and is never inferred or changed here. */
|
|
274
|
+
export function locateTerminalTab(document, terminal) {
|
|
275
|
+
terminalAddress(terminal);
|
|
276
|
+
if (!object(document) || !Array.isArray(document.spaces) || document.spaces.length > 256)
|
|
277
|
+
throw failure('unsupported app layout document');
|
|
278
|
+
const matches = [];
|
|
279
|
+
const ids = new Set();
|
|
280
|
+
let count = 0;
|
|
281
|
+
const unique = (id) => {
|
|
282
|
+
if (typeof id !== 'string' || !id || id.length > 256 || ids.has(id))
|
|
283
|
+
throw failure('ambiguous layout identity');
|
|
284
|
+
ids.add(id);
|
|
285
|
+
};
|
|
286
|
+
for (const space of document.spaces) {
|
|
287
|
+
if (!object(space))
|
|
288
|
+
throw failure('unsupported layout space');
|
|
289
|
+
unique(space.id);
|
|
290
|
+
if (!Array.isArray(space.tabs) || space.tabs.length > 512)
|
|
291
|
+
throw failure('invalid layout tabs');
|
|
292
|
+
for (const tab of space.tabs) {
|
|
293
|
+
if (!object(tab))
|
|
294
|
+
throw failure('unsupported layout tab');
|
|
295
|
+
unique(tab.id);
|
|
296
|
+
if (typeof tab.name !== 'string')
|
|
297
|
+
throw failure('invalid tab name');
|
|
298
|
+
const visit = (node, depth) => {
|
|
299
|
+
if (++count > 4096 || depth > 64 || !object(node) || typeof node.id !== 'string')
|
|
300
|
+
throw failure('layout bounds exceeded');
|
|
301
|
+
// The app uses the tab ID again for its root container.
|
|
302
|
+
if (node !== tab.root || node.id !== tab.id)
|
|
303
|
+
unique(node.id);
|
|
304
|
+
if (Object.hasOwn(node, 'floating')) {
|
|
305
|
+
if (!Array.isArray(node.floating))
|
|
306
|
+
throw failure('unsupported floating layout; no layout changes');
|
|
307
|
+
for (const floating of node.floating) {
|
|
308
|
+
if (++count > 4096 || !object(floating) || !object(floating.content) ||
|
|
309
|
+
typeof floating.content.mod !== 'string' || ['terminal', 'tab', 'context', 'agent'].some(key => Object.hasOwn(floating.content, key)) ||
|
|
310
|
+
['children', 'floating', 'type'].some(key => Object.hasOwn(floating, key)) ||
|
|
311
|
+
(Object.hasOwn(floating, 'edge') && !['top', 'right', 'bottom', 'left'].includes(floating.edge)) ||
|
|
312
|
+
(Object.hasOwn(floating, 'align') && !['start', 'center', 'end'].includes(floating.align))) {
|
|
313
|
+
throw failure('unsupported floating layout (only mod floats supported); no layout changes');
|
|
314
|
+
}
|
|
315
|
+
unique(floating.id);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
if (node.type === 'block') {
|
|
319
|
+
if (Object.hasOwn(node, 'children') || !object(node.content))
|
|
320
|
+
throw failure('unsupported block shape');
|
|
321
|
+
const tags = ['terminal', 'mod', 'tab', 'context', 'agent'].filter(key => Object.hasOwn(node.content, key));
|
|
322
|
+
if (tags.length !== 1 || !['terminal', 'mod'].includes(tags[0]) || typeof node.content[tags[0]] !== 'string')
|
|
323
|
+
throw failure('unsupported block content');
|
|
324
|
+
if (tags[0] === 'terminal')
|
|
325
|
+
terminalAddress(node.content.terminal);
|
|
326
|
+
if (node.content.terminal === terminal)
|
|
327
|
+
matches.push({ space, tab, pane: node });
|
|
328
|
+
}
|
|
329
|
+
else if (['row', 'column'].includes(node.type) && Array.isArray(node.children) && !Object.hasOwn(node, 'content')) {
|
|
330
|
+
for (const child of node.children)
|
|
331
|
+
visit(child, depth + 1);
|
|
332
|
+
}
|
|
333
|
+
else
|
|
334
|
+
throw failure('unsupported layout node (only row/column/block supported)');
|
|
335
|
+
};
|
|
336
|
+
visit(tab.root, 0);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
if (matches.length !== 1)
|
|
340
|
+
throw failure('terminal does not map to exactly one app pane; no layout changes');
|
|
341
|
+
return matches[0];
|
|
342
|
+
}
|
|
343
|
+
/** Change only the owning tab name using the app's optimistic document protocol.
|
|
344
|
+
* Success proves shared state, not that an attached Windows window has rendered it. */
|
|
345
|
+
export async function renameCoreTab(terminal, name, call) {
|
|
346
|
+
terminalAddress(terminal);
|
|
347
|
+
if (typeof name !== 'string' || !name.trim() || name.length > 128 || /[\x00-\x1f\x7f]/.test(name))
|
|
348
|
+
throw failure('invalid worker tab name');
|
|
349
|
+
// Default production rename is one operation, never a chain of reconnecting calls.
|
|
350
|
+
// An injected call remains supported for tests or an enclosing withCoreSession.
|
|
351
|
+
if (!call || call === coreCall)
|
|
352
|
+
return withCoreSession(session => renameCoreTab(terminal, name, session));
|
|
353
|
+
const record = await call('terminal.get', { terminal });
|
|
354
|
+
if (record?.address !== terminal || record.state !== 'live' || !Number.isSafeInteger(record.created_ms) || record.created_ms <= 0)
|
|
355
|
+
throw failure('worker terminal identity is not live');
|
|
356
|
+
const snapshot = await call('doc.get', { name: 'herdr-app' });
|
|
357
|
+
if (!Number.isSafeInteger(snapshot?.version) || snapshot.version < 0 || !snapshot.value)
|
|
358
|
+
throw failure('app layout unavailable');
|
|
359
|
+
const value = structuredClone(snapshot.value);
|
|
360
|
+
const { space, tab, pane } = locateTerminalTab(value, terminal);
|
|
361
|
+
if (record.labels?.['herdr.space'] !== space.id || record.labels?.['herdr.tab'] !== tab.id)
|
|
362
|
+
throw failure('terminal labels disagree with actual app layout');
|
|
363
|
+
if (tab.name === name)
|
|
364
|
+
return;
|
|
365
|
+
tab.name = name;
|
|
366
|
+
const fresh = await call('terminal.get', { terminal });
|
|
367
|
+
if (fresh?.address !== terminal || fresh.state !== 'live' || fresh.created_ms !== record.created_ms ||
|
|
368
|
+
fresh.labels?.['herdr.space'] !== space.id || fresh.labels?.['herdr.tab'] !== tab.id)
|
|
369
|
+
throw failure('terminal identity changed before rename');
|
|
370
|
+
const written = await call('doc.set', { name: 'herdr-app', version: snapshot.version, value });
|
|
371
|
+
if (!Number.isSafeInteger(written?.version) || written.version !== snapshot.version + 1)
|
|
372
|
+
throw failure('layout write acknowledgment uncertain; do not replay');
|
|
373
|
+
const observed = await call('doc.get', { name: 'herdr-app' });
|
|
374
|
+
if (!Number.isSafeInteger(observed?.version) || observed.version < written.version)
|
|
375
|
+
throw failure('layout readback version not confirmed; do not replay');
|
|
376
|
+
const target = locateTerminalTab(observed?.value, terminal);
|
|
377
|
+
if (target.space.id !== space.id || target.tab.id !== tab.id || target.pane.id !== pane.id || target.tab.name !== name)
|
|
378
|
+
throw failure('tab rename not confirmed; do not replay');
|
|
379
|
+
}
|
|
380
|
+
//# sourceMappingURL=herdr-core.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"herdr-core.js","sourceRoot":"","sources":["../src/herdr-core.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -5,12 +5,12 @@ import { getAgentDir, SessionManager, SettingsManager, truncateHead, withFileMut
|
|
|
5
5
|
import { ConfigStore } from './config.js';
|
|
6
6
|
import { Intercom, UNSUPPORTED_CANCELLATION } from './runtime.js';
|
|
7
7
|
import { launchers } from './launcher.js';
|
|
8
|
-
import { ensureMonitorPane } from './monitor-launcher.js';
|
|
8
|
+
import { ensureMonitorPane, closeMonitorPane } from './monitor-launcher.js';
|
|
9
9
|
import { createActivityTracker } from './activity.js';
|
|
10
10
|
import { createCloseProvider } from './pane-close.js';
|
|
11
11
|
const to = Type.Object({ to: Type.String({ minLength: 1, maxLength: 128 }) });
|
|
12
12
|
const tools = [
|
|
13
|
-
['create_worker', 'Coordinator only. Launch one anonymous worker
|
|
13
|
+
['create_worker', 'Coordinator only. Launch one anonymous worker at the coordinator root. projectDirectory defaults to root and must resolve to that same directory; subfolder launches cannot use a parent config and are refused. No assignment, configuration, or registration wait.', Type.Object({ projectDirectory: Type.Optional(Type.String()) })],
|
|
14
14
|
['configure_worker', 'Coordinator only. Write explicit reported connection details and responsibility to config. Does not notify, reload, or start work. Use reload_worker separately.', Type.Object({ sessionId: Type.String(), port: Type.Integer({ minimum: 1, maximum: 65535 }), projectDirectory: Type.String(), name: Type.String({ minLength: 1, maxLength: 128 }), description: Type.String({ minLength: 1, maxLength: 4096 }) })],
|
|
15
15
|
['reload_worker', 'Coordinator only. Ask worker to reread responsibility and synchronize names. NOT Pi extension reload, cancellation, restart, or work assignment.', to],
|
|
16
16
|
['send', 'Configured sessions only. Send an explicit work/progress/findings message by recipient name. Idle delivery starts a turn; busy delivery steers at supported boundaries. Receipt is not an agent reply. Progress questions do not cancel assignments.', Type.Object({ to: Type.String(), message: Type.String({ minLength: 1, maxLength: 48000 }) })],
|
|
@@ -18,12 +18,16 @@ const tools = [
|
|
|
18
18
|
['list', 'Configured sessions only. Read current saved names, responsibilities, session IDs, roles and ports. No live probing. Output limited to 50 KiB/2000 lines; full data remains in config.json.', Type.Object({})],
|
|
19
19
|
['request_status', 'Coordinator only. Ask worker extension to send an independent sessionId/port/busy report without a model turn on worker. No synchronous status reply.', to],
|
|
20
20
|
['report_work', 'Configured, responsibility-loaded workers only. Store one public report (blocked, needs_decision, ready_for_review) and notify the coordinator; clear retires it. Summary required except clear (omit or empty). Never include private reasoning, credentials, raw tool payloads, or secrets. Receipt is not approval, verified completion, or permission for follow-up work.', Type.Object({ status: Type.String({ enum: ['blocked', 'needs_decision', 'ready_for_review', 'clear'] }), summary: Type.Optional(Type.String({ maxLength: 2000 })) })],
|
|
21
|
+
['stop_reminders', 'Coordinator only. Disable the five-minute orchestration reminders until the next worker-directed call. Use when there is genuinely nothing to follow up on. Stops only reminders, not workers, close jobs or model work. Reminder state is session-local and clears on shutdown/reload.', Type.Object({})],
|
|
21
22
|
['report_status', 'Worker only (including anonymous). Send runtime sessionId/port/busy report to coordinator. This is NOT registration and creates no config entry.', Type.Object({})],
|
|
22
23
|
['stop_worker', UNSUPPORTED_CANCELLATION, to],
|
|
23
24
|
['close_worker', 'Coordinator only. Begin a background save-handoff-and-close job for a configured worker in Linux Herdr. Requests a public summary, saves it in config, waits for successful tool persistence and final turn settlement, then attempts one verified pane close. Returns job acceptance, not completion. Registration/session history are retained. Check worker_status/list for closeJob; failure/timeout/uncertainty never authorizes retry. Not graceful abort or an all-descendants termination guarantee; Windows/non-Herdr unsupported.', to],
|
|
24
25
|
['report_handoff', 'Configured worker only, in response to its pending close request. Submit the matching jobId and concise public resume handoff (current work, completed work, unfinished items, blockers, next step). Never include secrets, private reasoning or raw tool payloads. Saved receipt is not closure: finish the response and wait; the extension requires final turn settlement before pane closure.', Type.Object({ jobId: Type.String({ minLength: 1, maxLength: 128 }), summary: Type.String({ minLength: 1, maxLength: 4000 }) })],
|
|
25
|
-
['resume_worker', 'Coordinator only. Resume saved session/name/responsibility after the user explicitly confirms the old session was closed: set confirmClosed:true only for that confirmation, never infer it from disconnected status. A matching live health endpoint blocks launch. In-flight/uncertain attempts are fenced until worker status arrives; otherwise inspect process and reload coordinator before considering retry. No cross-process uniqueness guarantee, automatic assignment, replacement or removal.', Type.Object({ to: Type.String({ minLength: 1, maxLength: 128 }), confirmClosed: Type.Boolean() })],
|
|
26
|
+
['resume_worker', 'Coordinator only. Resume saved session/name/responsibility after the user explicitly confirms the old session was closed: set confirmClosed:true only for that confirmation, never infer it from disconnected status. A matching live health endpoint blocks launch. In-flight/uncertain attempts are fenced until worker status arrives; otherwise inspect process and reload coordinator before considering retry. Saved subfolder launches are refused rather than relocated, because a worker cannot use a parent config. No cross-process uniqueness guarantee, automatic assignment, replacement or removal.', Type.Object({ to: Type.String({ minLength: 1, maxLength: 128 }), confirmClosed: Type.Boolean() })],
|
|
26
27
|
['remove_worker', 'Coordinator only. Remove config entry only; never stop process or delete session files. A running worker must be explicitly closed before removal. Retain registration to resume it later; remove only to forget it. Pending or uncertain close jobs block removal.', to],
|
|
28
|
+
['open_monitor', "Coordinator only. Open or reuse the owned status monitor, including with no workers. Explicit placement is required: ask the user if unknown; never guess or fall back to saved settings. Currently supported: 'coordinator-tab' (pane above the coordinator in its current tab), 'new-tab' (separate tab). Does not assign worker work or change saved settings.", Type.Object({ placement: Type.String({ minLength: 1 }) })],
|
|
29
|
+
['close_monitor', 'Coordinator only. Close only the verified owned status monitor pane, not a worker, coordinator or whole tab. Does not change saved auto-open settings.', Type.Object({})],
|
|
30
|
+
['configure_monitor', "Coordinator only. Persist autoOpen and/or placement for future monitor openings. At least one setting is required. Currently supported placement values: 'coordinator-tab' (pane above the coordinator in its current tab), 'new-tab' (separate tab). Does not open, close or move panes.", Type.Object({ autoOpen: Type.Optional(Type.Boolean()), placement: Type.Optional(Type.String({ minLength: 1 })) }, { minProperties: 1, additionalProperties: false })],
|
|
27
31
|
['set_multiplexer', 'Coordinator only. Set herdr (default, Windows/Linux) or none (separate visible Windows terminals; unsupported on Linux) for future launches. Never move/restart existing workers or fall back.', Type.Object({ multiplexer: Type.String({ enum: ['herdr', 'none'] }) })],
|
|
28
32
|
];
|
|
29
33
|
// Launchers pass no --session-dir. Match child Pi's env > per-cwd settings >
|
|
@@ -43,6 +47,10 @@ class PiConfigStore extends ConfigStore {
|
|
|
43
47
|
}
|
|
44
48
|
}
|
|
45
49
|
export default function intercomExtension(pi) {
|
|
50
|
+
pi.registerFlag('intercom-root', {
|
|
51
|
+
type: 'string',
|
|
52
|
+
description: 'Explicit Intercom root must equal this session cwd; parent configuration is never allowed, even with this flag.',
|
|
53
|
+
});
|
|
46
54
|
let runtime;
|
|
47
55
|
let context;
|
|
48
56
|
let generation = 0;
|
|
@@ -54,25 +62,28 @@ export default function intercomExtension(pi) {
|
|
|
54
62
|
extension: fileURLToPath(import.meta.url),
|
|
55
63
|
sessionExists: async (cwd, id) => (await SessionManager.list(cwd, resumeSessionDirectory(cwd))).some(s => s.id === id),
|
|
56
64
|
});
|
|
65
|
+
let monitorAutoEpoch = 0;
|
|
57
66
|
let monitorTask;
|
|
58
67
|
async function ensureCoordinatorMonitor(current, ctx, started) {
|
|
59
|
-
const
|
|
68
|
+
const epoch = monitorAutoEpoch;
|
|
69
|
+
const isCurrent = () => started === generation && runtime === current && epoch === monitorAutoEpoch;
|
|
60
70
|
if (!isCurrent())
|
|
61
71
|
return;
|
|
62
|
-
if (monitorTask?.runtime === current && monitorTask.generation === started) {
|
|
72
|
+
if (monitorTask?.runtime === current && monitorTask.generation === started && monitorTask.epoch === epoch) {
|
|
63
73
|
monitorTask.dirty = true;
|
|
64
74
|
return monitorTask.promise;
|
|
65
75
|
}
|
|
66
76
|
const check = async () => {
|
|
67
77
|
try {
|
|
68
|
-
const { config, me
|
|
78
|
+
const { config, me } = await current.state();
|
|
69
79
|
if (!isCurrent() || !me?.coordinator || !config.agents.some(agent => !agent.coordinator))
|
|
70
80
|
return;
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
81
|
+
const settings = await current.getMonitorSettings();
|
|
82
|
+
if (!isCurrent() || !settings.autoOpen)
|
|
83
|
+
return;
|
|
84
|
+
const monitor = await current.autoOpenMonitor(() => {
|
|
85
|
+
if (!isCurrent())
|
|
86
|
+
throw new Error('Automatic monitor request superseded');
|
|
76
87
|
});
|
|
77
88
|
if (isCurrent())
|
|
78
89
|
ctx.ui.notify(`Intercom status monitor: ${monitor.outcome}${monitor.pane ? ` (${monitor.pane})` : ''}`, 'info');
|
|
@@ -82,7 +93,7 @@ export default function intercomExtension(pi) {
|
|
|
82
93
|
ctx.ui.notify(String(error), 'warning');
|
|
83
94
|
}
|
|
84
95
|
};
|
|
85
|
-
const task = { runtime: current, generation: started, dirty: false, promise: Promise.resolve() };
|
|
96
|
+
const task = { runtime: current, generation: started, epoch, dirty: false, promise: Promise.resolve() };
|
|
86
97
|
monitorTask = task;
|
|
87
98
|
task.promise = (async () => {
|
|
88
99
|
do {
|
|
@@ -111,6 +122,11 @@ export default function intercomExtension(pi) {
|
|
|
111
122
|
throw new Error('PiIntercom requires Windows or Linux interactive Pi. No resources started.');
|
|
112
123
|
if (!ctx.isProjectTrusted())
|
|
113
124
|
throw new Error('PiIntercom requires project trust before honoring shared project configuration.');
|
|
125
|
+
// Flags become available at session_start, not extension factory time. Never
|
|
126
|
+
// infer workspace authority from ancestors or inherited environment values.
|
|
127
|
+
const workspaceRoot = pi.getFlag('intercom-root');
|
|
128
|
+
if (workspaceRoot !== undefined && typeof workspaceRoot !== 'string')
|
|
129
|
+
throw new Error('PiIntercom: intercom-root must be an explicit absolute path.');
|
|
114
130
|
runtime = new Intercom({
|
|
115
131
|
cwd: ctx.cwd,
|
|
116
132
|
sessionId: () => context.sessionManager.getSessionId(),
|
|
@@ -122,7 +138,25 @@ export default function intercomExtension(pi) {
|
|
|
122
138
|
pi.setSessionName(name); await launcher.syncName(name); },
|
|
123
139
|
notify: text => ctx.ui.notify(text, 'info'),
|
|
124
140
|
}, {
|
|
125
|
-
launch: launcher.launch, store: root => new PiConfigStore(root),
|
|
141
|
+
launch: launcher.launch, store: root => new PiConfigStore(root), workspaceRoot,
|
|
142
|
+
monitor: {
|
|
143
|
+
open: request => ensureMonitorPane({ ...request,
|
|
144
|
+
script: fileURLToPath(new URL('../dist/monitor.js', import.meta.url)),
|
|
145
|
+
assertCurrent: () => {
|
|
146
|
+
request.assertCurrent();
|
|
147
|
+
if (started !== generation || runtime !== current)
|
|
148
|
+
throw new Error('Coordinator session changed');
|
|
149
|
+
},
|
|
150
|
+
}),
|
|
151
|
+
close: request => closeMonitorPane({ ...request,
|
|
152
|
+
script: fileURLToPath(new URL('../dist/monitor.js', import.meta.url)),
|
|
153
|
+
assertCurrent: () => {
|
|
154
|
+
request.assertCurrent();
|
|
155
|
+
if (started !== generation || runtime !== current)
|
|
156
|
+
throw new Error('Coordinator session changed');
|
|
157
|
+
},
|
|
158
|
+
}),
|
|
159
|
+
},
|
|
126
160
|
closeProvider: createCloseProvider({
|
|
127
161
|
sessionId: () => context.sessionManager.getSessionId(),
|
|
128
162
|
sessionFile: () => context.sessionManager.getSessionFile(),
|
|
@@ -229,13 +263,25 @@ export default function intercomExtension(pi) {
|
|
|
229
263
|
for (const [operation, description, parameters] of tools) {
|
|
230
264
|
pi.registerTool({
|
|
231
265
|
name: `intercom_${operation}`, label: `Intercom ${operation}`, description, parameters,
|
|
266
|
+
// Handoff readiness requires this call's successful transcript tool result.
|
|
267
|
+
// Pi1.x enforces model-only for nested calls;0.84 ignores this optional field
|
|
268
|
+
// and has no nested-tool API. Never substitute a parent result as proof.
|
|
269
|
+
exposure: operation === 'report_handoff' ? 'model-only' : 'direct',
|
|
232
270
|
async execute(_id, args, signal, _update, ctx) {
|
|
233
271
|
signal?.throwIfAborted();
|
|
234
272
|
context = ctx;
|
|
235
273
|
if (!runtime)
|
|
236
274
|
throw new Error('PiIntercom not initialized; inspect startup error.');
|
|
237
275
|
const current = runtime, started = generation;
|
|
238
|
-
|
|
276
|
+
if (operation === 'close_monitor') {
|
|
277
|
+
const state = await current.state();
|
|
278
|
+
if (started !== generation || runtime !== current)
|
|
279
|
+
throw new Error('Coordinator session changed');
|
|
280
|
+
if (!state.me?.coordinator)
|
|
281
|
+
throw new Error('PiIntercom: coordinator permission required');
|
|
282
|
+
monitorAutoEpoch++; // Fence prior automatic passes; lock refusal never schedules a retry.
|
|
283
|
+
}
|
|
284
|
+
const result = await current.tool(operation, args, _id, signal);
|
|
239
285
|
if (operation === 'configure_worker')
|
|
240
286
|
await ensureCoordinatorMonitor(current, ctx, started);
|
|
241
287
|
const output = truncateHead(JSON.stringify(result, null, 2));
|