ftown 0.25.2 → 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 (108) hide show
  1. package/dist/command-rpc.d.ts +3 -0
  2. package/dist/command-rpc.js +41 -0
  3. package/dist/command-rpc.js.map +1 -1
  4. package/dist/coordination/board.d.ts +12 -0
  5. package/dist/coordination/board.js +240 -0
  6. package/dist/coordination/board.js.map +1 -0
  7. package/dist/coordination/card-store.d.ts +9 -0
  8. package/dist/coordination/card-store.js +188 -0
  9. package/dist/coordination/card-store.js.map +1 -0
  10. package/dist/coordination/contract.d.ts +236 -0
  11. package/dist/coordination/contract.js +63 -0
  12. package/dist/coordination/contract.js.map +1 -0
  13. package/dist/coordination/format.d.ts +5 -0
  14. package/dist/coordination/format.js +60 -0
  15. package/dist/coordination/format.js.map +1 -0
  16. package/dist/coordination/tree-events.d.ts +31 -0
  17. package/dist/coordination/tree-events.js +226 -0
  18. package/dist/coordination/tree-events.js.map +1 -0
  19. package/dist/coordination/wiring.d.ts +48 -0
  20. package/dist/coordination/wiring.js +143 -0
  21. package/dist/coordination/wiring.js.map +1 -0
  22. package/dist/coordination-cli.d.ts +34 -0
  23. package/dist/coordination-cli.js +460 -0
  24. package/dist/coordination-cli.js.map +1 -0
  25. package/dist/ftown-cli.js +12 -2
  26. package/dist/ftown-cli.js.map +1 -1
  27. package/dist/index.js +33 -7
  28. package/dist/index.js.map +1 -1
  29. package/dist/local-api-server.d.ts +6 -1
  30. package/dist/local-api-server.js +282 -5
  31. package/dist/local-api-server.js.map +1 -1
  32. package/dist/mail-delivery.d.ts +16 -2
  33. package/dist/mail-delivery.js +331 -77
  34. package/dist/mail-delivery.js.map +1 -1
  35. package/dist/mail-store.d.ts +7 -0
  36. package/dist/mail-store.js +71 -1
  37. package/dist/mail-store.js.map +1 -1
  38. package/dist/pull-request-events.d.ts +5 -0
  39. package/dist/pull-request-events.js +21 -1
  40. package/dist/pull-request-events.js.map +1 -1
  41. package/dist/quota/agy.d.ts +16 -0
  42. package/dist/quota/agy.js +287 -0
  43. package/dist/quota/agy.js.map +1 -0
  44. package/dist/quota/annotate.d.ts +5 -0
  45. package/dist/quota/annotate.js +56 -0
  46. package/dist/quota/annotate.js.map +1 -0
  47. package/dist/quota/claude.d.ts +27 -0
  48. package/dist/quota/claude.js +265 -0
  49. package/dist/quota/claude.js.map +1 -0
  50. package/dist/quota/codex.d.ts +25 -0
  51. package/dist/quota/codex.js +378 -0
  52. package/dist/quota/codex.js.map +1 -0
  53. package/dist/quota/format.d.ts +6 -0
  54. package/dist/quota/format.js +113 -0
  55. package/dist/quota/format.js.map +1 -0
  56. package/dist/quota/grok.d.ts +97 -0
  57. package/dist/quota/grok.js +563 -0
  58. package/dist/quota/grok.js.map +1 -0
  59. package/dist/quota/models-agy.d.ts +10 -0
  60. package/dist/quota/models-agy.js +144 -0
  61. package/dist/quota/models-agy.js.map +1 -0
  62. package/dist/quota/models-claude.d.ts +10 -0
  63. package/dist/quota/models-claude.js +227 -0
  64. package/dist/quota/models-claude.js.map +1 -0
  65. package/dist/quota/models-codex.d.ts +18 -0
  66. package/dist/quota/models-codex.js +305 -0
  67. package/dist/quota/models-codex.js.map +1 -0
  68. package/dist/quota/models-grok.d.ts +19 -0
  69. package/dist/quota/models-grok.js +272 -0
  70. package/dist/quota/models-grok.js.map +1 -0
  71. package/dist/quota/models-muse.d.ts +13 -0
  72. package/dist/quota/models-muse.js +200 -0
  73. package/dist/quota/models-muse.js.map +1 -0
  74. package/dist/quota/models-opencode.d.ts +51 -0
  75. package/dist/quota/models-opencode.js +400 -0
  76. package/dist/quota/models-opencode.js.map +1 -0
  77. package/dist/quota/muse.d.ts +38 -0
  78. package/dist/quota/muse.js +225 -0
  79. package/dist/quota/muse.js.map +1 -0
  80. package/dist/quota/opencode.d.ts +7 -0
  81. package/dist/quota/opencode.js +47 -0
  82. package/dist/quota/opencode.js.map +1 -0
  83. package/dist/quota/routing-config.d.ts +18 -0
  84. package/dist/quota/routing-config.js +438 -0
  85. package/dist/quota/routing-config.js.map +1 -0
  86. package/dist/quota/routing-service.d.ts +24 -0
  87. package/dist/quota/routing-service.js +118 -0
  88. package/dist/quota/routing-service.js.map +1 -0
  89. package/dist/quota/routing.d.ts +10 -0
  90. package/dist/quota/routing.js +180 -0
  91. package/dist/quota/routing.js.map +1 -0
  92. package/dist/quota/types.d.ts +304 -0
  93. package/dist/quota/types.js +45 -0
  94. package/dist/quota/types.js.map +1 -0
  95. package/dist/quota-cli.d.ts +80 -0
  96. package/dist/quota-cli.js +462 -0
  97. package/dist/quota-cli.js.map +1 -0
  98. package/dist/security/bridge/permissions.js +24 -2
  99. package/dist/security/bridge/permissions.js.map +1 -1
  100. package/dist/types.d.ts +7 -3
  101. package/dist/wire-types.d.ts +17 -1
  102. package/dist/wire-types.js +1 -1
  103. package/dist/wire-types.js.map +1 -1
  104. package/package.json +3 -2
  105. package/skills/ftown/SKILL.md +31 -5
  106. package/skills/ftown/references/orchestrator.md +17 -7
  107. package/skills/ftown/references/quota.md +177 -0
  108. 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
@@ -5,11 +5,13 @@ import { runEnv } from './env-commands.js';
5
5
  import { runSetup } from './setup.js';
6
6
  import { runStart } from './start-commands.js';
7
7
  import { runSecurity } from './security-cli.js';
8
+ import { runQuotaCli } from './quota-cli.js';
9
+ import { runBoard, runEvents, runStatus } from './coordination-cli.js';
8
10
  import { executeCli, isCliEntry } from './cli-entry.js';
9
11
  export { isCliEntry } from './cli-entry.js';
10
12
  export function usage() {
11
13
  return `Usage: ftown [bridge options]
12
- ftown <setup|start|sessions|harness|env|security> [args...]
14
+ ftown <setup|start|sessions|harness|env|security|quota|status|board|events> [args...]
13
15
 
14
16
  With no subcommand, start the bridge. Run setup explicitly before the first start.
15
17
 
@@ -19,7 +21,11 @@ Subcommands:
19
21
  sessions List, create, read and drive ftown agent sessions
20
22
  harness Inspect and drive the local ftown-bridge harness
21
23
  security Pair browsers and inspect/revoke encrypted endpoints
22
- env Manage per-provider machine tokens (~/.ftown/env.json)`;
24
+ env Manage per-provider machine tokens (~/.ftown/env.json)
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`;
23
29
  }
24
30
  export async function runFtown(argv, start = runStart) {
25
31
  const [group, ...args] = argv;
@@ -34,6 +40,10 @@ export async function runFtown(argv, start = runStart) {
34
40
  case 'harness': return runHarness(args);
35
41
  case 'env': return runEnv(args);
36
42
  case 'security': return runSecurity(args);
43
+ case 'quota': return runQuotaCli(args);
44
+ case 'status': return runStatus(args);
45
+ case 'board': return runBoard(args);
46
+ case 'events': return runEvents(args);
37
47
  case 'setup': return runSetup(args);
38
48
  case 'start': return start(args);
39
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,UAAU,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5C,MAAM,UAAU,KAAK;IACnB,OAAO;;;;;;;;;;;oEAW2D,CAAC;AACrE,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,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
@@ -29,9 +29,11 @@ import { loadOrCreateIdentity, readBoundBridgeIdentity } from './security/bridge
29
29
  import { bindLedgerIdentity } from './security/bridge/ledger-identity.js';
30
30
  import { BridgeSecurityService, applicationJson } from './security/bridge/security.js';
31
31
  import { createCommandHandler } from './command-rpc.js';
32
+ import { createRealModelRoutingService } from './quota/routing-service.js';
32
33
  import { PullRequestStatusService } from './pull-request-status.js';
33
34
  import { createPrReviewService } from './pull-request-review.js';
34
35
  import { PullRequestEventWatcher } from './pull-request-events.js';
36
+ import { createCoordination } from './coordination/wiring.js';
35
37
  import { removeFtownSession } from './remove-ftown-session.js';
36
38
  import { SessionResurrection, shouldResurrectStoredSession } from './session-resurrection.js';
37
39
  import { createTerminalOutput } from './terminal-output.js';
@@ -746,18 +748,40 @@ export async function runBridge(argv, commandName = 'ftown-bridge') {
746
748
  onSubagentIdle: (signal, isCurrent) => localApiServer.notifyIdleParent(signal, isCurrent),
747
749
  });
748
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);
749
763
  const stopPushSessionObserver = centrifugo.onLocalPublication((channel, data) => {
750
764
  if (channel !== `sessions:updates#${userId}` || !data || typeof data !== 'object')
751
765
  return;
752
766
  const update = data;
753
- if (update.type === 'session_update' && update.session?.id && update.session.status !== 'running') {
754
- 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
+ }
755
774
  }
756
775
  });
757
- const mailStore = new MailStore((sessionId) => store.sessionDir(sessionId));
758
- 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
+ };
759
782
  const notifyScriptPath = canonicalNotifyPath();
760
783
  const wireTerminalInput = (sessionId) => {
784
+ coordination.onSessionStart(sessionId);
761
785
  centrifugo.subscribeToTerminalInput(userId, sessionId, (sid, data) => { runner.write(sid, data); }, (sid, cols, rows) => { handleClientResize(sid, cols, rows); }, (sid) => { publishScreenDump(sid); });
762
786
  };
763
787
  const sessionFactoryDeps = {
@@ -785,7 +809,7 @@ export async function runBridge(argv, commandName = 'ftown-bridge') {
785
809
  lifecycle: {
786
810
  publishSessionUpdate: (session) => centrifugo.publishSessionUpdate(userId, session),
787
811
  publishHookEvent: (sid, event) => centrifugo.publishHookEvent(userId, sid, event),
788
- unregisterSession: (sid) => unregisterSession(sid),
812
+ unregisterSession: handleSessionExit,
789
813
  collectUsage: (session) => collectSessionUsage(session),
790
814
  },
791
815
  });
@@ -823,18 +847,18 @@ export async function runBridge(argv, commandName = 'ftown-bridge') {
823
847
  collectUsage: (session) => collectSessionUsage(session),
824
848
  publishSyntheticStop: (sid, reason) => pump.publishSyntheticStop(sid, reason),
825
849
  withSessionWrite: (sid, task) => pump.withSessionWrite(sid, task),
826
- unregisterSession: (sid) => unregisterSession(sid),
850
+ unregisterSession: handleSessionExit,
827
851
  flushTerminalBuffer: (sid) => pump.flush(sid),
828
852
  destroyTerminal: (sid) => terminalManager.destroy(sid),
829
853
  });
830
854
  localApiServer.setSessionController(sessionController);
831
- const pullRequestStatuses = new PullRequestStatusService();
832
855
  const pullRequestReview = createPrReviewService({ bridgeId, loadSession: id => sessionController.get(id), revalidate: principal => security.policy.revalidate(principal, 'read') });
833
856
  const pullRequestEvents = new PullRequestEventWatcher({ bridgeId, store,
834
857
  withSessionMutation: (id, task) => pump.withSessionWrite(id, task),
835
858
  statusService: pullRequestStatuses, mailStore,
836
859
  notifyCommitted: (session, sender) => localApiServer.notifyCommittedMail(session, sender, true),
837
860
  });
861
+ pullRequestEvents.setTreeEventEmitter((session, kind, summary, ref) => coordination.emit(session, kind, summary, ref));
838
862
  pullRequestEvents.start();
839
863
  const updateHome = realpathSync(homedir());
840
864
  const stagingRoot = join(updateHome, '.ftown', 'updates');
@@ -926,6 +950,7 @@ export async function runBridge(argv, commandName = 'ftown-bridge') {
926
950
  }).finally(release);
927
951
  });
928
952
  let ready = false;
953
+ const modelRouting = createRealModelRoutingService(homedir());
929
954
  const dispatchCommand = async (message) => {
930
955
  if (!ready)
931
956
  return { type: 'command_response', response: { requestId: message.envelope.messageId, success: false, error: 'bridge_offline' } };
@@ -940,6 +965,7 @@ export async function runBridge(argv, commandName = 'ftown-bridge') {
940
965
  }
941
966
  let result;
942
967
  await createCommandHandler({ bridgeId, security, sessionController, attentionStore, updates, updateEffects, pullRequestStatuses, pullRequestReview,
968
+ modelRouting: () => modelRouting,
943
969
  enqueueSessionMessage: (session, message) => localApiServer.enqueueSessionMessage(session, message),
944
970
  acceptSessionMail: (session, body) => localApiServer.acceptSessionMail(session, body),
945
971
  publishAttentionChanged: (sessionId) => { localApiServer.emit('event', { sessionId, eventName: 'AttentionSnapshot', data: {} }); },