ftown 0.25.3 → 0.26.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/dist/coordination/board.d.ts +12 -0
  2. package/dist/coordination/board.js +240 -0
  3. package/dist/coordination/board.js.map +1 -0
  4. package/dist/coordination/card-store.d.ts +9 -0
  5. package/dist/coordination/card-store.js +188 -0
  6. package/dist/coordination/card-store.js.map +1 -0
  7. package/dist/coordination/contract.d.ts +236 -0
  8. package/dist/coordination/contract.js +63 -0
  9. package/dist/coordination/contract.js.map +1 -0
  10. package/dist/coordination/format.d.ts +5 -0
  11. package/dist/coordination/format.js +60 -0
  12. package/dist/coordination/format.js.map +1 -0
  13. package/dist/coordination/tree-events.d.ts +31 -0
  14. package/dist/coordination/tree-events.js +226 -0
  15. package/dist/coordination/tree-events.js.map +1 -0
  16. package/dist/coordination/wiring.d.ts +48 -0
  17. package/dist/coordination/wiring.js +143 -0
  18. package/dist/coordination/wiring.js.map +1 -0
  19. package/dist/coordination-cli.d.ts +34 -0
  20. package/dist/coordination-cli.js +460 -0
  21. package/dist/coordination-cli.js.map +1 -0
  22. package/dist/ftown-cli.js +9 -2
  23. package/dist/ftown-cli.js.map +1 -1
  24. package/dist/index.js +30 -7
  25. package/dist/index.js.map +1 -1
  26. package/dist/local-api-server.d.ts +6 -1
  27. package/dist/local-api-server.js +282 -5
  28. package/dist/local-api-server.js.map +1 -1
  29. package/dist/mail-delivery.d.ts +16 -2
  30. package/dist/mail-delivery.js +331 -77
  31. package/dist/mail-delivery.js.map +1 -1
  32. package/dist/mail-store.d.ts +7 -0
  33. package/dist/mail-store.js +71 -1
  34. package/dist/mail-store.js.map +1 -1
  35. package/dist/pull-request-events.d.ts +5 -0
  36. package/dist/pull-request-events.js +21 -1
  37. package/dist/pull-request-events.js.map +1 -1
  38. package/dist/security/bridge/permissions.js +20 -0
  39. package/dist/security/bridge/permissions.js.map +1 -1
  40. package/dist/types.d.ts +5 -1
  41. package/dist/wire-types.d.ts +17 -1
  42. package/dist/wire-types.js +1 -1
  43. package/dist/wire-types.js.map +1 -1
  44. package/package.json +2 -2
  45. package/skills/ftown/SKILL.md +29 -4
  46. package/skills/ftown/references/orchestrator.md +12 -7
  47. package/skills/ftown/references/sessions.md +45 -3
@@ -0,0 +1,460 @@
1
+ /**
2
+ * `ftown status | board | events` — coordination phase-A CLI.
3
+ * Thin client over the local coordination API (see coordination/contract.ts).
4
+ */
5
+ import { Command, CommanderError } from 'commander';
6
+ import { api as request, loadPointer } from './cli-client.js';
7
+ import { BOARD_WAIT_CONDITIONS, CARD_LIMITS, CARD_STATES, COORDINATION_ROUTES, } from './coordination/contract.js';
8
+ import { formatBoard, formatBoardRow, formatEvent } from './coordination/format.js';
9
+ export const WAIT_DEFAULT_TIMEOUT_SECONDS = 300;
10
+ export const WAIT_MAX_TIMEOUT_SECONDS = 300;
11
+ const EVENTS_WAIT_CHUNK_SECONDS = 300;
12
+ const STATUS_SET_USAGE = 'Usage: ftown status set [--state <s>] [--headline <t>] [--progress <d>/<t>|--no-progress] ' +
13
+ '[--on human|parent|external|session:<id>] [--text <t>] [--next <t>|--no-next] [--session-id <id>]';
14
+ /** Usage problem: message printed, exit code 2. */
15
+ export class UsageError extends Error {
16
+ usage;
17
+ constructor(message, usage) {
18
+ super(message);
19
+ this.usage = usage;
20
+ this.name = 'UsageError';
21
+ }
22
+ }
23
+ /** Thrown after output has been printed, to carry a non-zero exit code. */
24
+ class ExitError extends Error {
25
+ code;
26
+ constructor(code) {
27
+ super(`exit ${code}`);
28
+ this.code = code;
29
+ this.name = 'ExitError';
30
+ }
31
+ }
32
+ async function defaultApi(method, path, body) {
33
+ return request(loadPointer(), method, path, body);
34
+ }
35
+ function resolveDeps(partial) {
36
+ return {
37
+ api: partial?.api ?? defaultApi,
38
+ now: partial?.now ?? (() => Date.now()),
39
+ env: partial?.env ?? process.env,
40
+ log: partial?.log ?? ((text) => console.log(text)),
41
+ errorLog: partial?.errorLog ?? ((text) => console.error(text)),
42
+ };
43
+ }
44
+ function requireSessionId(explicit, env) {
45
+ const id = (explicit ?? env.FTOWN_SESSION_ID)?.trim();
46
+ if (!id || !/^[A-Za-z0-9_-]{1,200}$/.test(id)) {
47
+ throw new UsageError('Supply a valid --session-id or set FTOWN_SESSION_ID');
48
+ }
49
+ return id;
50
+ }
51
+ function cardPath(sessionId) {
52
+ return COORDINATION_ROUTES.card.replace(':id', encodeURIComponent(sessionId));
53
+ }
54
+ function boardPath(sessionId, query) {
55
+ const params = new URLSearchParams();
56
+ if (query.since !== undefined)
57
+ params.set('since', String(query.since));
58
+ if (query.ready)
59
+ params.set('ready', '1');
60
+ if (query.all)
61
+ params.set('all', '1');
62
+ const qs = params.toString();
63
+ const base = COORDINATION_ROUTES.board.replace(':id', encodeURIComponent(sessionId));
64
+ return qs ? `${base}?${qs}` : base;
65
+ }
66
+ function eventsPath(sessionId, query) {
67
+ const params = new URLSearchParams();
68
+ if (query.since !== undefined)
69
+ params.set('since', String(query.since));
70
+ if (query.limit !== undefined)
71
+ params.set('limit', String(query.limit));
72
+ if (query.waitSeconds !== undefined)
73
+ params.set('waitSeconds', String(query.waitSeconds));
74
+ const qs = params.toString();
75
+ const base = COORDINATION_ROUTES.events.replace(':id', encodeURIComponent(sessionId));
76
+ return qs ? `${base}?${qs}` : base;
77
+ }
78
+ // ───────────────────────── Flag parsing (pure) ─────────────────────────
79
+ export function parseProgress(value) {
80
+ const match = /^(\d+)\/(\d+)$/.exec(value);
81
+ if (!match) {
82
+ throw new UsageError(`--progress must be <done>/<total> (got "${value}")`);
83
+ }
84
+ const done = Number(match[1]);
85
+ const total = Number(match[2]);
86
+ if (total < 1 || total > CARD_LIMITS.progressTotal || done > total) {
87
+ throw new UsageError(`--progress must satisfy 0 <= done <= total and 1 <= total <= ${CARD_LIMITS.progressTotal} (got "${value}")`);
88
+ }
89
+ return { done, total };
90
+ }
91
+ function parseBlockedOn(on, text) {
92
+ if (on === 'human' || on === 'parent' || on === 'external') {
93
+ return { kind: on, text };
94
+ }
95
+ if (on.startsWith('session:')) {
96
+ const ref = on.slice('session:'.length);
97
+ if (!/^[A-Za-z0-9_-]{1,200}$/.test(ref)) {
98
+ throw new UsageError('--on session:<id> requires a valid session id');
99
+ }
100
+ return { kind: 'session', ref, text };
101
+ }
102
+ throw new UsageError('--on must be human, parent, external or session:<id>');
103
+ }
104
+ export function buildCardPatch(flags) {
105
+ const patch = {};
106
+ let touched = false;
107
+ if (flags.state !== undefined) {
108
+ if (!CARD_STATES.includes(flags.state)) {
109
+ throw new UsageError(`--state must be one of: ${CARD_STATES.join(', ')}`);
110
+ }
111
+ patch.state = flags.state;
112
+ touched = true;
113
+ }
114
+ if (flags.headline !== undefined) {
115
+ patch.headline = flags.headline;
116
+ touched = true;
117
+ }
118
+ if (typeof flags.progress === 'string') {
119
+ patch.progress = parseProgress(flags.progress);
120
+ touched = true;
121
+ }
122
+ else if (flags.progress === false) {
123
+ patch.progress = null;
124
+ touched = true;
125
+ }
126
+ if (flags.on !== undefined) {
127
+ if (flags.text === undefined)
128
+ throw new UsageError('--on requires --text');
129
+ patch.blockedOn = parseBlockedOn(flags.on, flags.text);
130
+ touched = true;
131
+ }
132
+ else if (flags.text !== undefined) {
133
+ throw new UsageError('--text requires --on');
134
+ }
135
+ if (typeof flags.next === 'string') {
136
+ patch.next = flags.next;
137
+ touched = true;
138
+ }
139
+ else if (flags.next === false) {
140
+ patch.next = null;
141
+ touched = true;
142
+ }
143
+ if (!touched) {
144
+ throw new UsageError('Nothing to set: supply at least one card field', STATUS_SET_USAGE);
145
+ }
146
+ return patch;
147
+ }
148
+ /** Pure wait-condition evaluation over a fetched board and the events that arrived. */
149
+ export function evaluateWaitCondition(condition, board, events) {
150
+ switch (condition) {
151
+ case 'any-change':
152
+ return events.length > 0;
153
+ case 'any-done':
154
+ return board.cards.some((card) => card.declared?.state === 'done');
155
+ case 'any-blocked':
156
+ return board.cards.some((card) => card.declared?.state === 'blocked');
157
+ case 'all-done':
158
+ return board.cards.length > 0 && board.cards.every((card) => card.declared?.state === 'done');
159
+ case 'any-ready':
160
+ return board.cards.some((card) => card.derived.pr?.state === 'passed' && card.declared?.state !== 'done');
161
+ }
162
+ }
163
+ function parseSince(value) {
164
+ if (value === undefined)
165
+ return undefined;
166
+ if (!/^\d{1,12}$/.test(value))
167
+ throw new UsageError('--since must be a non-negative integer');
168
+ return Number(value);
169
+ }
170
+ function parseLimit(value) {
171
+ if (value === undefined)
172
+ return undefined;
173
+ if (!/^\d+$/.test(value))
174
+ throw new UsageError('--limit must be a whole number between 1 and 500');
175
+ const limit = Number(value);
176
+ if (limit < 1 || limit > 500)
177
+ throw new UsageError('--limit must be between 1 and 500');
178
+ return limit;
179
+ }
180
+ function parseTimeoutSeconds(value) {
181
+ if (value === undefined)
182
+ return WAIT_DEFAULT_TIMEOUT_SECONDS;
183
+ if (!/^\d+$/.test(value)) {
184
+ throw new UsageError(`--timeout must be a whole number of seconds between 1 and ${WAIT_MAX_TIMEOUT_SECONDS}`);
185
+ }
186
+ const seconds = Number(value);
187
+ if (seconds < 1 || seconds > WAIT_MAX_TIMEOUT_SECONDS) {
188
+ throw new UsageError(`--timeout must be between 1 and ${WAIT_MAX_TIMEOUT_SECONDS} seconds`);
189
+ }
190
+ return seconds;
191
+ }
192
+ function parseWaitCondition(value) {
193
+ if (!BOARD_WAIT_CONDITIONS.includes(value)) {
194
+ throw new UsageError(`--until must be one of: ${BOARD_WAIT_CONDITIONS.join(', ')}`);
195
+ }
196
+ return value;
197
+ }
198
+ // ───────────────────────── Output helpers ─────────────────────────
199
+ function printCard(deps, card, json) {
200
+ if (json) {
201
+ deps.log(JSON.stringify(card, null, 2));
202
+ return;
203
+ }
204
+ deps.log(formatBoardRow(card, deps.now()));
205
+ if (card.declared?.next)
206
+ deps.log(`next: ${card.declared.next}`);
207
+ }
208
+ function printBoard(deps, board, json) {
209
+ if (json) {
210
+ deps.log(JSON.stringify(board, null, 2));
211
+ return;
212
+ }
213
+ deps.log(formatBoard(board, deps.now()));
214
+ deps.log(`cursor ${board.cursor}`);
215
+ }
216
+ function printEvents(deps, page, json) {
217
+ if (json) {
218
+ deps.log(JSON.stringify(page, null, 2));
219
+ return;
220
+ }
221
+ for (const event of page.events)
222
+ deps.log(formatEvent(event));
223
+ deps.log(`cursor ${page.cursor}`);
224
+ }
225
+ async function fetchBoard(deps, sessionId, query) {
226
+ return (await deps.api('GET', boardPath(sessionId, query)));
227
+ }
228
+ async function fetchEventsPage(deps, sessionId, query) {
229
+ return (await deps.api('GET', eventsPath(sessionId, query)));
230
+ }
231
+ async function getStatus(deps, opts) {
232
+ const sessionId = requireSessionId(opts.sessionId, deps.env);
233
+ const card = (await deps.api('GET', cardPath(sessionId)));
234
+ printCard(deps, card, opts.json === true);
235
+ }
236
+ async function setStatus(deps, opts) {
237
+ const sessionId = requireSessionId(opts.sessionId, deps.env);
238
+ const patch = buildCardPatch(opts);
239
+ const card = (await deps.api('PUT', cardPath(sessionId), patch));
240
+ printCard(deps, card, opts.json === true);
241
+ }
242
+ async function clearStatus(deps, opts) {
243
+ const sessionId = requireSessionId(opts.sessionId, deps.env);
244
+ const data = await deps.api('DELETE', cardPath(sessionId));
245
+ if (opts.json === true)
246
+ deps.log(JSON.stringify(data, null, 2));
247
+ else
248
+ deps.log(`card cleared for ${sessionId}`);
249
+ }
250
+ function statusProgram(deps) {
251
+ const program = new Command()
252
+ .name('ftown status')
253
+ .description("Show or update this session's status card");
254
+ program.exitOverride();
255
+ program.configureOutput({
256
+ writeOut: (text) => deps.log(text.trimEnd()),
257
+ writeErr: (text) => deps.errorLog(text.trimEnd()),
258
+ });
259
+ program
260
+ .option('--json', 'Machine-readable JSON output')
261
+ .option('--plain', 'Human-readable output (default)')
262
+ .option('--session-id <id>', 'Target session; defaults to FTOWN_SESSION_ID')
263
+ .action(async (opts) => {
264
+ await getStatus(deps, opts);
265
+ });
266
+ program
267
+ .command('set')
268
+ .description('Update the status card')
269
+ .option('--state <s>', `Card state: ${CARD_STATES.join(' | ')}`)
270
+ .option('--headline <t>', 'One-line headline')
271
+ .option('--progress <done/total>', 'Progress, e.g. 3/7')
272
+ .option('--no-progress', 'Clear progress')
273
+ .option('--on <kind>', 'Blocked on: human | parent | external | session:<id>')
274
+ .option('--text <t>', 'Blocked-on detail (required with --on)')
275
+ .option('--next <t>', 'Next step')
276
+ .option('--no-next', 'Clear next step')
277
+ .option('--json', 'Machine-readable JSON output')
278
+ .option('--plain', 'Human-readable output (default)')
279
+ .option('--session-id <id>', 'Target session; defaults to FTOWN_SESSION_ID')
280
+ .action(async (opts) => {
281
+ await setStatus(deps, opts);
282
+ });
283
+ program
284
+ .command('clear')
285
+ .description('Clear the status card')
286
+ .option('--json', 'Machine-readable JSON output')
287
+ .option('--plain', 'Human-readable output (default)')
288
+ .option('--session-id <id>', 'Target session; defaults to FTOWN_SESSION_ID')
289
+ .action(async (opts) => {
290
+ await clearStatus(deps, opts);
291
+ });
292
+ return program;
293
+ }
294
+ async function waitForBoard(deps, sessionId, query, condition, timeoutSeconds, json) {
295
+ // Conditions are evaluated only on events past the starting cursor, and
296
+ // always on an unfiltered board; the user-filtered board is what prints.
297
+ const start = await fetchBoard(deps, sessionId, {});
298
+ let cursor = start.cursor;
299
+ const timeoutMs = timeoutSeconds * 1000;
300
+ const deadline = deps.now() + timeoutMs;
301
+ let remainingMs = timeoutMs;
302
+ while (remainingMs > 0) {
303
+ const waitSeconds = Math.min(Math.ceil(remainingMs / 1000), EVENTS_WAIT_CHUNK_SECONDS);
304
+ const page = await fetchEventsPage(deps, sessionId, { since: cursor, waitSeconds });
305
+ cursor = page.cursor;
306
+ if (page.events.length > 0) {
307
+ const board = await fetchBoard(deps, sessionId, {});
308
+ if (evaluateWaitCondition(condition, board, page.events)) {
309
+ printBoard(deps, await fetchBoard(deps, sessionId, query), json);
310
+ return;
311
+ }
312
+ remainingMs = Math.min(remainingMs, deadline - deps.now());
313
+ }
314
+ else {
315
+ remainingMs -= waitSeconds * 1000;
316
+ const wallRemaining = deadline - deps.now();
317
+ if (wallRemaining < remainingMs)
318
+ remainingMs = wallRemaining;
319
+ }
320
+ }
321
+ printBoard(deps, await fetchBoard(deps, sessionId, query), json);
322
+ throw new ExitError(3);
323
+ }
324
+ async function runBoardCommand(deps, opts) {
325
+ const sessionId = requireSessionId(opts.sessionId, deps.env);
326
+ const since = parseSince(opts.since);
327
+ if (opts.wait && opts.until === undefined)
328
+ throw new UsageError('--wait requires --until <condition>');
329
+ if (!opts.wait && opts.until !== undefined)
330
+ throw new UsageError('--until requires --wait');
331
+ if (opts.timeout !== undefined && !opts.wait)
332
+ throw new UsageError('--timeout requires --wait');
333
+ const timeoutSeconds = parseTimeoutSeconds(opts.timeout);
334
+ const condition = opts.until === undefined ? undefined : parseWaitCondition(opts.until);
335
+ const query = { since, ready: opts.ready === true, all: opts.all === true };
336
+ const json = opts.json === true;
337
+ if (!opts.wait) {
338
+ printBoard(deps, await fetchBoard(deps, sessionId, query), json);
339
+ return;
340
+ }
341
+ await waitForBoard(deps, sessionId, query, condition, timeoutSeconds, json);
342
+ }
343
+ function boardProgram(deps) {
344
+ const program = new Command()
345
+ .name('ftown board')
346
+ .description("Child-session board for this session's tree");
347
+ program.exitOverride();
348
+ program.configureOutput({
349
+ writeOut: (text) => deps.log(text.trimEnd()),
350
+ writeErr: (text) => deps.errorLog(text.trimEnd()),
351
+ });
352
+ program
353
+ .option('--json', 'Machine-readable JSON output')
354
+ .option('--plain', 'Human-readable output (default)')
355
+ .option('--since <n>', 'Only children with tree events after this seq')
356
+ .option('--ready', 'Only merge-ready children')
357
+ .option('--all', 'Include archived/completed children')
358
+ .option('--wait', 'Wait until --until condition is met')
359
+ .option('--until <cond>', `Wait condition: ${BOARD_WAIT_CONDITIONS.join(' | ')}`)
360
+ .option('--timeout <s>', `With --wait: give up after this many seconds (1-${WAIT_MAX_TIMEOUT_SECONDS}, default ${WAIT_DEFAULT_TIMEOUT_SECONDS})`)
361
+ .option('--session-id <id>', 'Target session; defaults to FTOWN_SESSION_ID')
362
+ .action(async (opts) => {
363
+ await runBoardCommand(deps, opts);
364
+ });
365
+ return program;
366
+ }
367
+ async function waitForEvents(deps, sessionId, since, limit, timeoutSeconds, json) {
368
+ // Without --since, wait only for events from the current head (board cursor).
369
+ let cursor = since ?? (await fetchBoard(deps, sessionId, {})).cursor;
370
+ const timeoutMs = timeoutSeconds * 1000;
371
+ const deadline = deps.now() + timeoutMs;
372
+ let remainingMs = timeoutMs;
373
+ let lastPage = { events: [], cursor };
374
+ while (remainingMs > 0) {
375
+ const waitSeconds = Math.min(Math.ceil(remainingMs / 1000), EVENTS_WAIT_CHUNK_SECONDS);
376
+ const page = await fetchEventsPage(deps, sessionId, { since: cursor, limit, waitSeconds });
377
+ lastPage = page;
378
+ cursor = page.cursor;
379
+ if (page.events.length > 0) {
380
+ printEvents(deps, page, json);
381
+ return;
382
+ }
383
+ remainingMs -= waitSeconds * 1000;
384
+ const wallRemaining = deadline - deps.now();
385
+ if (wallRemaining < remainingMs)
386
+ remainingMs = wallRemaining;
387
+ }
388
+ printEvents(deps, lastPage, json);
389
+ throw new ExitError(3);
390
+ }
391
+ async function runEventsCommand(deps, opts) {
392
+ const sessionId = requireSessionId(opts.sessionId, deps.env);
393
+ const since = parseSince(opts.since);
394
+ const limit = parseLimit(opts.limit);
395
+ if (opts.timeout !== undefined && !opts.wait)
396
+ throw new UsageError('--timeout requires --wait');
397
+ const timeoutSeconds = parseTimeoutSeconds(opts.timeout);
398
+ const json = opts.json === true;
399
+ if (!opts.wait) {
400
+ printEvents(deps, await fetchEventsPage(deps, sessionId, { since, limit }), json);
401
+ return;
402
+ }
403
+ await waitForEvents(deps, sessionId, since, limit, timeoutSeconds, json);
404
+ }
405
+ function eventsProgram(deps) {
406
+ const program = new Command()
407
+ .name('ftown events')
408
+ .description("Tree event log for this session's tree");
409
+ program.exitOverride();
410
+ program.configureOutput({
411
+ writeOut: (text) => deps.log(text.trimEnd()),
412
+ writeErr: (text) => deps.errorLog(text.trimEnd()),
413
+ });
414
+ program
415
+ .option('--json', 'Machine-readable JSON output')
416
+ .option('--plain', 'Human-readable output (default)')
417
+ .option('--since <n>', 'Only events with seq greater than n')
418
+ .option('--limit <n>', 'Max events (1-500)')
419
+ .option('--wait', 'Wait for new events')
420
+ .option('--timeout <s>', `With --wait: give up after this many seconds (1-${WAIT_MAX_TIMEOUT_SECONDS}, default ${WAIT_DEFAULT_TIMEOUT_SECONDS})`)
421
+ .option('--session-id <id>', 'Target session; defaults to FTOWN_SESSION_ID')
422
+ .action(async (opts) => {
423
+ await runEventsCommand(deps, opts);
424
+ });
425
+ return program;
426
+ }
427
+ // ───────────────────────── entry points ─────────────────────────
428
+ async function runProgram(group, program, argv, deps) {
429
+ try {
430
+ await program.parseAsync(argv, { from: 'user' });
431
+ return 0;
432
+ }
433
+ catch (error) {
434
+ if (error instanceof CommanderError)
435
+ return error.exitCode === 0 ? 0 : 2;
436
+ if (error instanceof ExitError)
437
+ return error.code;
438
+ if (error instanceof UsageError) {
439
+ deps.errorLog(`ftown ${group}: ${error.message}`);
440
+ if (error.usage)
441
+ deps.errorLog(error.usage);
442
+ return 2;
443
+ }
444
+ deps.errorLog(`ftown ${group}: ${error instanceof Error ? error.message : String(error)}`);
445
+ return 1;
446
+ }
447
+ }
448
+ export async function runStatus(argv, deps) {
449
+ const resolved = resolveDeps(deps);
450
+ return runProgram('status', statusProgram(resolved), argv, resolved);
451
+ }
452
+ export async function runBoard(argv, deps) {
453
+ const resolved = resolveDeps(deps);
454
+ return runProgram('board', boardProgram(resolved), argv, resolved);
455
+ }
456
+ export async function runEvents(argv, deps) {
457
+ const resolved = resolveDeps(deps);
458
+ return runProgram('events', eventsProgram(resolved), argv, resolved);
459
+ }
460
+ //# sourceMappingURL=coordination-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coordination-cli.js","sourceRoot":"","sources":["../src/coordination-cli.ts"],"names":[],"mappings":"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"}
package/dist/ftown-cli.js CHANGED
@@ -6,11 +6,12 @@ import { runSetup } from './setup.js';
6
6
  import { runStart } from './start-commands.js';
7
7
  import { runSecurity } from './security-cli.js';
8
8
  import { runQuotaCli } from './quota-cli.js';
9
+ import { runBoard, runEvents, runStatus } from './coordination-cli.js';
9
10
  import { executeCli, isCliEntry } from './cli-entry.js';
10
11
  export { isCliEntry } from './cli-entry.js';
11
12
  export function usage() {
12
13
  return `Usage: ftown [bridge options]
13
- ftown <setup|start|sessions|harness|env|security|quota> [args...]
14
+ ftown <setup|start|sessions|harness|env|security|quota|status|board|events> [args...]
14
15
 
15
16
  With no subcommand, start the bridge. Run setup explicitly before the first start.
16
17
 
@@ -21,7 +22,10 @@ Subcommands:
21
22
  harness Inspect and drive the local ftown-bridge harness
22
23
  security Pair browsers and inspect/revoke encrypted endpoints
23
24
  env Manage per-provider machine tokens (~/.ftown/env.json)
24
- quota Subscription quota left, routing advice and model lists per harness (--json for agents)`;
25
+ quota Subscription quota left, routing advice and model lists per harness (--json for agents)
26
+ status Own status card: show, set or clear
27
+ board Child-session board for this session's tree
28
+ events Tree event log for this session's tree`;
25
29
  }
26
30
  export async function runFtown(argv, start = runStart) {
27
31
  const [group, ...args] = argv;
@@ -37,6 +41,9 @@ export async function runFtown(argv, start = runStart) {
37
41
  case 'env': return runEnv(args);
38
42
  case 'security': return runSecurity(args);
39
43
  case 'quota': return runQuotaCli(args);
44
+ case 'status': return runStatus(args);
45
+ case 'board': return runBoard(args);
46
+ case 'events': return runEvents(args);
40
47
  case 'setup': return runSetup(args);
41
48
  case 'start': return start(args);
42
49
  default:
@@ -1 +1 @@
1
- {"version":3,"file":"ftown-cli.js","sourceRoot":"","sources":["../src/ftown-cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5C,MAAM,UAAU,KAAK;IACnB,OAAO;;;;;;;;;;;;qGAY4F,CAAC;AACtG,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAc,EAAE,QAA6C,QAAQ;IAClG,MAAM,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IAC9B,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAAC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;QAAC,OAAO,CAAC,CAAC;IAAC,CAAC;IACjF,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC;IACxD,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,UAAU,CAAC,CAAC,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC;QAC1C,KAAK,SAAS,CAAC,CAAC,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC;QACxC,KAAK,KAAK,CAAC,CAAC,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC;QAChC,KAAK,UAAU,CAAC,CAAC,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC;QAC1C,KAAK,OAAO,CAAC,CAAC,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC;QACvC,KAAK,OAAO,CAAC,CAAC,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC;QACpC,KAAK,OAAO,CAAC,CAAC,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC;QACjC;YAAS,OAAO,CAAC,KAAK,CAAC,8BAA8B,KAAK,GAAG,CAAC,CAAC;YAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;YAAC,OAAO,CAAC,CAAC;IACnG,CAAC;AACH,CAAC;AAED,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACjD,KAAK,UAAU,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzD,CAAC"}
1
+ {"version":3,"file":"ftown-cli.js","sourceRoot":"","sources":["../src/ftown-cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5C,MAAM,UAAU,KAAK;IACnB,OAAO;;;;;;;;;;;;;;;oDAe2C,CAAC;AACrD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAc,EAAE,QAA6C,QAAQ;IAClG,MAAM,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IAC9B,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAAC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;QAAC,OAAO,CAAC,CAAC;IAAC,CAAC;IACjF,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC;IACxD,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,UAAU,CAAC,CAAC,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC;QAC1C,KAAK,SAAS,CAAC,CAAC,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC;QACxC,KAAK,KAAK,CAAC,CAAC,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC;QAChC,KAAK,UAAU,CAAC,CAAC,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC;QAC1C,KAAK,OAAO,CAAC,CAAC,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC;QACvC,KAAK,QAAQ,CAAC,CAAC,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC;QACtC,KAAK,OAAO,CAAC,CAAC,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC;QACpC,KAAK,QAAQ,CAAC,CAAC,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC;QACtC,KAAK,OAAO,CAAC,CAAC,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC;QACpC,KAAK,OAAO,CAAC,CAAC,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC;QACjC;YAAS,OAAO,CAAC,KAAK,CAAC,8BAA8B,KAAK,GAAG,CAAC,CAAC;YAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;YAAC,OAAO,CAAC,CAAC;IACnG,CAAC;AACH,CAAC;AAED,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACjD,KAAK,UAAU,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzD,CAAC"}
package/dist/index.js CHANGED
@@ -33,6 +33,7 @@ import { createRealModelRoutingService } from './quota/routing-service.js';
33
33
  import { PullRequestStatusService } from './pull-request-status.js';
34
34
  import { createPrReviewService } from './pull-request-review.js';
35
35
  import { PullRequestEventWatcher } from './pull-request-events.js';
36
+ import { createCoordination } from './coordination/wiring.js';
36
37
  import { removeFtownSession } from './remove-ftown-session.js';
37
38
  import { SessionResurrection, shouldResurrectStoredSession } from './session-resurrection.js';
38
39
  import { createTerminalOutput } from './terminal-output.js';
@@ -747,18 +748,40 @@ export async function runBridge(argv, commandName = 'ftown-bridge') {
747
748
  onSubagentIdle: (signal, isCurrent) => localApiServer.notifyIdleParent(signal, isCurrent),
748
749
  });
749
750
  localApiServer.setAttentionStore(attentionStore);
751
+ const mailStore = new MailStore((sessionId) => store.sessionDir(sessionId));
752
+ localApiServer.setMailStore(mailStore);
753
+ const pullRequestStatuses = new PullRequestStatusService();
754
+ const coordination = createCoordination({
755
+ store,
756
+ attention: attentionStore,
757
+ prStatus: async (url) => (await pullRequestStatuses.get([url])).statuses[0] ?? null,
758
+ mail: mailStore,
759
+ publishSession: (session) => { void centrifugo.publishSessionUpdate(userId, session); },
760
+ now: Date.now,
761
+ });
762
+ localApiServer.setCoordination(coordination);
750
763
  const stopPushSessionObserver = centrifugo.onLocalPublication((channel, data) => {
751
764
  if (channel !== `sessions:updates#${userId}` || !data || typeof data !== 'object')
752
765
  return;
753
766
  const update = data;
754
- if (update.type === 'session_update' && update.session?.id && update.session.status !== 'running') {
755
- void attentionStore.cancelIdleNotification(update.session.id).catch(() => { });
767
+ if (update.type === 'session_update' && update.session?.id) {
768
+ if (update.session.status === 'running') {
769
+ coordination.onSessionStart(update.session.id);
770
+ }
771
+ else {
772
+ void attentionStore.cancelIdleNotification(update.session.id).catch(() => { });
773
+ }
756
774
  }
757
775
  });
758
- const mailStore = new MailStore((sessionId) => store.sessionDir(sessionId));
759
- localApiServer.setMailStore(mailStore);
776
+ const handleSessionExit = (sid) => {
777
+ unregisterSession(sid);
778
+ void coordination.onSessionExit(sid).catch((err) => {
779
+ console.warn(`[Bridge] Failed to emit exit event for ${sid}:`, err instanceof Error ? err.message : String(err));
780
+ });
781
+ };
760
782
  const notifyScriptPath = canonicalNotifyPath();
761
783
  const wireTerminalInput = (sessionId) => {
784
+ coordination.onSessionStart(sessionId);
762
785
  centrifugo.subscribeToTerminalInput(userId, sessionId, (sid, data) => { runner.write(sid, data); }, (sid, cols, rows) => { handleClientResize(sid, cols, rows); }, (sid) => { publishScreenDump(sid); });
763
786
  };
764
787
  const sessionFactoryDeps = {
@@ -786,7 +809,7 @@ export async function runBridge(argv, commandName = 'ftown-bridge') {
786
809
  lifecycle: {
787
810
  publishSessionUpdate: (session) => centrifugo.publishSessionUpdate(userId, session),
788
811
  publishHookEvent: (sid, event) => centrifugo.publishHookEvent(userId, sid, event),
789
- unregisterSession: (sid) => unregisterSession(sid),
812
+ unregisterSession: handleSessionExit,
790
813
  collectUsage: (session) => collectSessionUsage(session),
791
814
  },
792
815
  });
@@ -824,18 +847,18 @@ export async function runBridge(argv, commandName = 'ftown-bridge') {
824
847
  collectUsage: (session) => collectSessionUsage(session),
825
848
  publishSyntheticStop: (sid, reason) => pump.publishSyntheticStop(sid, reason),
826
849
  withSessionWrite: (sid, task) => pump.withSessionWrite(sid, task),
827
- unregisterSession: (sid) => unregisterSession(sid),
850
+ unregisterSession: handleSessionExit,
828
851
  flushTerminalBuffer: (sid) => pump.flush(sid),
829
852
  destroyTerminal: (sid) => terminalManager.destroy(sid),
830
853
  });
831
854
  localApiServer.setSessionController(sessionController);
832
- const pullRequestStatuses = new PullRequestStatusService();
833
855
  const pullRequestReview = createPrReviewService({ bridgeId, loadSession: id => sessionController.get(id), revalidate: principal => security.policy.revalidate(principal, 'read') });
834
856
  const pullRequestEvents = new PullRequestEventWatcher({ bridgeId, store,
835
857
  withSessionMutation: (id, task) => pump.withSessionWrite(id, task),
836
858
  statusService: pullRequestStatuses, mailStore,
837
859
  notifyCommitted: (session, sender) => localApiServer.notifyCommittedMail(session, sender, true),
838
860
  });
861
+ pullRequestEvents.setTreeEventEmitter((session, kind, summary, ref) => coordination.emit(session, kind, summary, ref));
839
862
  pullRequestEvents.start();
840
863
  const updateHome = realpathSync(homedir());
841
864
  const stagingRoot = join(updateHome, '.ftown', 'updates');