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.
- package/dist/coordination/board.d.ts +12 -0
- package/dist/coordination/board.js +240 -0
- package/dist/coordination/board.js.map +1 -0
- package/dist/coordination/card-store.d.ts +9 -0
- package/dist/coordination/card-store.js +188 -0
- package/dist/coordination/card-store.js.map +1 -0
- package/dist/coordination/contract.d.ts +236 -0
- package/dist/coordination/contract.js +63 -0
- package/dist/coordination/contract.js.map +1 -0
- package/dist/coordination/format.d.ts +5 -0
- package/dist/coordination/format.js +60 -0
- package/dist/coordination/format.js.map +1 -0
- package/dist/coordination/tree-events.d.ts +31 -0
- package/dist/coordination/tree-events.js +226 -0
- package/dist/coordination/tree-events.js.map +1 -0
- package/dist/coordination/wiring.d.ts +48 -0
- package/dist/coordination/wiring.js +143 -0
- package/dist/coordination/wiring.js.map +1 -0
- package/dist/coordination-cli.d.ts +34 -0
- package/dist/coordination-cli.js +460 -0
- package/dist/coordination-cli.js.map +1 -0
- package/dist/ftown-cli.js +9 -2
- package/dist/ftown-cli.js.map +1 -1
- package/dist/index.js +30 -7
- package/dist/index.js.map +1 -1
- package/dist/local-api-server.d.ts +6 -1
- package/dist/local-api-server.js +282 -5
- package/dist/local-api-server.js.map +1 -1
- package/dist/mail-delivery.d.ts +16 -2
- package/dist/mail-delivery.js +331 -77
- package/dist/mail-delivery.js.map +1 -1
- package/dist/mail-store.d.ts +7 -0
- package/dist/mail-store.js +71 -1
- package/dist/mail-store.js.map +1 -1
- package/dist/pull-request-events.d.ts +5 -0
- package/dist/pull-request-events.js +21 -1
- package/dist/pull-request-events.js.map +1 -1
- package/dist/security/bridge/permissions.js +20 -0
- package/dist/security/bridge/permissions.js.map +1 -1
- package/dist/types.d.ts +5 -1
- package/dist/wire-types.d.ts +17 -1
- package/dist/wire-types.js +1 -1
- package/dist/wire-types.js.map +1 -1
- package/package.json +2 -2
- package/skills/ftown/SKILL.md +29 -4
- package/skills/ftown/references/orchestrator.md +12 -7
- 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:
|
package/dist/ftown-cli.js.map
CHANGED
|
@@ -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
|
|
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
|
|
755
|
-
|
|
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
|
|
759
|
-
|
|
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:
|
|
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:
|
|
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');
|