@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.
Files changed (47) hide show
  1. package/README.md +113 -8
  2. package/dist/config.d.ts +12 -0
  3. package/dist/config.js +94 -22
  4. package/dist/config.js.map +1 -1
  5. package/dist/core-monitor.d.ts +30 -0
  6. package/dist/core-monitor.js +528 -0
  7. package/dist/core-monitor.js.map +1 -0
  8. package/dist/core-pane-close.d.ts +34 -0
  9. package/dist/core-pane-close.js +335 -0
  10. package/dist/core-pane-close.js.map +1 -0
  11. package/dist/core-worker-layout.d.ts +50 -0
  12. package/dist/core-worker-layout.js +236 -0
  13. package/dist/core-worker-layout.js.map +1 -0
  14. package/dist/herdr-core.d.ts +53 -0
  15. package/dist/herdr-core.js +380 -0
  16. package/dist/herdr-core.js.map +1 -0
  17. package/dist/index.js +60 -14
  18. package/dist/index.js.map +1 -1
  19. package/dist/launcher.d.ts +2 -0
  20. package/dist/launcher.js +59 -3
  21. package/dist/launcher.js.map +1 -1
  22. package/dist/monitor-launcher.d.ts +8 -0
  23. package/dist/monitor-launcher.js +111 -25
  24. package/dist/monitor-launcher.js.map +1 -1
  25. package/dist/pane-close.js +3 -0
  26. package/dist/pane-close.js.map +1 -1
  27. package/dist/reminders.d.ts +28 -0
  28. package/dist/reminders.js +81 -0
  29. package/dist/reminders.js.map +1 -0
  30. package/dist/runtime.d.ts +28 -2
  31. package/dist/runtime.js +139 -11
  32. package/dist/runtime.js.map +1 -1
  33. package/package.json +14 -6
  34. package/references/herdr-core-migration.md +44 -0
  35. package/references/releasing.md +90 -0
  36. package/references/v1-specification.md +11 -8
  37. package/src/config.ts +69 -17
  38. package/src/core-monitor.ts +410 -0
  39. package/src/core-pane-close.ts +328 -0
  40. package/src/core-worker-layout.ts +240 -0
  41. package/src/herdr-core.ts +287 -0
  42. package/src/index.ts +55 -15
  43. package/src/launcher.ts +55 -3
  44. package/src/monitor-launcher.ts +95 -21
  45. package/src/pane-close.ts +2 -0
  46. package/src/reminders.ts +69 -0
  47. 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 in projectDirectory (default root). No assignment, configuration, or registration wait.', Type.Object({ projectDirectory: Type.Optional(Type.String()) })],
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 isCurrent = () => started === generation && runtime === current;
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, id } = await current.state();
78
+ const { config, me } = await current.state();
69
79
  if (!isCurrent() || !me?.coordinator || !config.agents.some(agent => !agent.coordinator))
70
80
  return;
71
- const monitor = await ensureMonitorPane({
72
- root: current.store.root, sessionId: id,
73
- script: fileURLToPath(new URL('../dist/monitor.js', import.meta.url)),
74
- assertCurrent: () => { if (!isCurrent())
75
- throw new Error('Coordinator session changed'); },
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
- const result = await current.tool(operation, args, _id);
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));