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,12 @@
1
+ import { type Board, type BoardDeps, type BoardQuery, type BoardServiceApi, type SessionCard } from './contract.js';
2
+ export declare class BoardService implements BoardServiceApi {
3
+ private readonly deps;
4
+ constructor(deps: BoardDeps);
5
+ private buildCardForSession;
6
+ card(sessionId: string): Promise<SessionCard | null>;
7
+ board(query: BoardQuery): Promise<Board>;
8
+ digest(sessionId: string, sinceSeq: number): Promise<{
9
+ line: string | null;
10
+ cursor: number;
11
+ }>;
12
+ }
@@ -0,0 +1,240 @@
1
+ import { CARD_STATES, CARD_STALE_MS, DIGEST_MAX, } from './contract.js';
2
+ import { formatLocalHHMM } from './format.js';
3
+ function emptyRollup() {
4
+ const rollup = {
5
+ working: 0,
6
+ blocked: 0,
7
+ waiting_review: 0,
8
+ done: 0,
9
+ failed: 0,
10
+ unset: 0,
11
+ };
12
+ for (const state of CARD_STATES) {
13
+ rollup[state] = 0;
14
+ }
15
+ return rollup;
16
+ }
17
+ function sliceCodePoints(s, max) {
18
+ const cps = Array.from(s);
19
+ return cps.length > max ? cps.slice(0, max).join('') : s;
20
+ }
21
+ async function readAllEventsSince(deps, rootId, since) {
22
+ const all = [];
23
+ let cursor = since;
24
+ while (true) {
25
+ const page = await deps.events.read(rootId, { since: cursor, limit: 500 });
26
+ if (page.events.length === 0) {
27
+ break;
28
+ }
29
+ all.push(...page.events);
30
+ if (page.cursor <= cursor) {
31
+ break;
32
+ }
33
+ cursor = page.cursor;
34
+ if (page.events.length < 500) {
35
+ break;
36
+ }
37
+ }
38
+ return { events: all, cursor };
39
+ }
40
+ export class BoardService {
41
+ deps;
42
+ constructor(deps) {
43
+ this.deps = deps;
44
+ }
45
+ buildCardForSession(session) {
46
+ return (async () => {
47
+ const [attentionRes, unreadRes, prRes] = await Promise.all([
48
+ Promise.resolve()
49
+ .then(() => this.deps.attention(session.id))
50
+ .catch(() => ({
51
+ activity: { state: 'unknown' },
52
+ openCount: 0,
53
+ })),
54
+ Promise.resolve()
55
+ .then(() => this.deps.unreadMail(session.id))
56
+ .catch(() => 0),
57
+ session.pullRequestUrl
58
+ ? Promise.resolve()
59
+ .then(() => this.deps.prStatus(session.pullRequestUrl))
60
+ .catch(() => null)
61
+ : Promise.resolve(null),
62
+ ]);
63
+ const activity = attentionRes.activity;
64
+ const openAttention = attentionRes.openCount;
65
+ const unreadMail = unreadRes;
66
+ const previews = session.preview ? session.preview.files.map((f) => f.fileName) : [];
67
+ const derived = {
68
+ status: session.status,
69
+ activity: activity.state,
70
+ ...(activity.state === 'idle' && activity.lastActivityAt !== undefined
71
+ ? { idleSince: activity.lastActivityAt }
72
+ : {}),
73
+ openAttention,
74
+ unreadMail,
75
+ ...(session.pullRequestUrl && prRes
76
+ ? {
77
+ pr: {
78
+ url: session.pullRequestUrl,
79
+ state: prRes.state,
80
+ stale: prRes.stale,
81
+ checkedAt: prRes.checkedAt,
82
+ },
83
+ }
84
+ : {}),
85
+ previews,
86
+ ...(session.shellType !== undefined ? { shellType: session.shellType } : {}),
87
+ ...(session.model !== undefined ? { model: session.model } : {}),
88
+ };
89
+ const declared = session.card ?? null;
90
+ let stale = false;
91
+ if (declared && activity.lastActivityAt) {
92
+ const lastActMs = Date.parse(activity.lastActivityAt);
93
+ const updMs = Date.parse(declared.updatedAt);
94
+ if (!Number.isNaN(lastActMs) && !Number.isNaN(updMs) && lastActMs - updMs > CARD_STALE_MS) {
95
+ stale = true;
96
+ }
97
+ }
98
+ const card = {
99
+ sessionId: session.id,
100
+ name: session.name,
101
+ ...(session.parentSessionId !== undefined ? { parentSessionId: session.parentSessionId } : {}),
102
+ declared,
103
+ derived,
104
+ stale,
105
+ };
106
+ return card;
107
+ })();
108
+ }
109
+ async card(sessionId) {
110
+ const session = await this.deps.loadSession(sessionId);
111
+ if (!session)
112
+ return null;
113
+ return this.buildCardForSession(session);
114
+ }
115
+ async board(query) {
116
+ const session = await this.deps.loadSession(query.sessionId);
117
+ if (!session) {
118
+ throw new Error('Session not found');
119
+ }
120
+ const rootId = session.parentSessionId ?? session.id;
121
+ const [allSessions, cursor, eventsPage] = await Promise.all([
122
+ this.deps.listSessions(),
123
+ this.deps.events.head(rootId),
124
+ query.since !== undefined
125
+ ? readAllEventsSince(this.deps, rootId, query.since)
126
+ : Promise.resolve(null),
127
+ ]);
128
+ const sinceSessionIds = eventsPage
129
+ ? new Set(eventsPage.events.map((e) => e.sessionId))
130
+ : null;
131
+ let children = allSessions.filter((s) => s.parentSessionId === rootId && s.id !== rootId);
132
+ if (!query.all) {
133
+ children = children.filter((s) => s.status === 'running' ||
134
+ s.status === 'pending' ||
135
+ (sinceSessionIds !== null && sinceSessionIds.has(s.id)));
136
+ }
137
+ if (sinceSessionIds !== null) {
138
+ children = children.filter((s) => sinceSessionIds.has(s.id));
139
+ }
140
+ children.sort((a, b) => {
141
+ const ta = Date.parse(a.createdAt);
142
+ const tb = Date.parse(b.createdAt);
143
+ if (!Number.isNaN(ta) && !Number.isNaN(tb) && ta !== tb) {
144
+ return ta - tb;
145
+ }
146
+ return a.createdAt.localeCompare(b.createdAt);
147
+ });
148
+ let cards = await Promise.all(children.map((c) => this.buildCardForSession(c)));
149
+ if (query.ready) {
150
+ cards = cards.filter((c) => c.derived.pr?.state === 'passed' && c.declared?.state !== 'done');
151
+ }
152
+ const rollup = emptyRollup();
153
+ for (const c of cards) {
154
+ const key = c.declared?.state ?? 'unset';
155
+ rollup[key] += 1;
156
+ }
157
+ return {
158
+ rootId,
159
+ cursor,
160
+ cards,
161
+ rollup,
162
+ };
163
+ }
164
+ async digest(sessionId, sinceSeq) {
165
+ const session = await this.deps.loadSession(sessionId);
166
+ if (!session) {
167
+ throw new Error('Session not found');
168
+ }
169
+ const rootId = session.parentSessionId ?? session.id;
170
+ const { events } = await readAllEventsSince(this.deps, rootId, sinceSeq);
171
+ if (events.length === 0) {
172
+ return { line: null, cursor: sinceSeq };
173
+ }
174
+ const lastEvent = events[events.length - 1];
175
+ const cursor = lastEvent.seq;
176
+ const hhmm = formatLocalHHMM(events[0].ts);
177
+ // Latest event per child wins; order by latest event appearance
178
+ const latestByChild = new Map();
179
+ for (const ev of events) {
180
+ if (ev.sessionId === rootId)
181
+ continue;
182
+ if (latestByChild.has(ev.sessionId)) {
183
+ latestByChild.delete(ev.sessionId);
184
+ }
185
+ latestByChild.set(ev.sessionId, ev);
186
+ }
187
+ const childEvents = Array.from(latestByChild.values());
188
+ if (childEvents.length === 0) {
189
+ return { line: null, cursor };
190
+ }
191
+ const cardsById = new Map();
192
+ await Promise.all(childEvents.map(async (ev) => {
193
+ const c = await this.card(ev.sessionId);
194
+ cardsById.set(ev.sessionId, c);
195
+ }));
196
+ const visibleEvents = childEvents.slice(0, 6);
197
+ const extraCount = childEvents.length - visibleEvents.length;
198
+ const parts = [];
199
+ for (const ev of visibleEvents) {
200
+ const card = cardsById.get(ev.sessionId) ?? null;
201
+ const name = card?.name ?? ev.sessionName;
202
+ const state = card?.declared?.state ?? '-';
203
+ const rawHeadline = card?.declared?.headline ?? '';
204
+ const headline = sliceCodePoints(rawHeadline, 60);
205
+ const prState = card?.derived.pr?.state;
206
+ let part = `${name} ${state}`;
207
+ if (headline) {
208
+ part += ` "${headline}"`;
209
+ }
210
+ if (prState) {
211
+ part += ` (PR ${prState})`;
212
+ }
213
+ parts.push(part);
214
+ }
215
+ if (extraCount > 0) {
216
+ parts.push(`+${extraCount} more`);
217
+ }
218
+ let totalQuestions = 0;
219
+ for (const ev of childEvents) {
220
+ const card = cardsById.get(ev.sessionId);
221
+ if (card) {
222
+ totalQuestions += card.derived.openAttention;
223
+ }
224
+ }
225
+ if (totalQuestions > 0) {
226
+ parts.push(`${totalQuestions} question(s) waiting`);
227
+ }
228
+ let line = `[ftown] since ${hhmm}: ${parts.join(' | ')}`;
229
+ if (line.length > DIGEST_MAX) {
230
+ let cut = DIGEST_MAX;
231
+ const code = line.charCodeAt(cut - 1);
232
+ if (code >= 0xd800 && code <= 0xdbff) {
233
+ cut -= 1;
234
+ }
235
+ line = line.slice(0, cut);
236
+ }
237
+ return { line, cursor };
238
+ }
239
+ }
240
+ //# sourceMappingURL=board.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"board.js","sourceRoot":"","sources":["../../src/coordination/board.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { type CardPatch, type CardStoreApi, type CardStoreDeps, type SessionCardDeclared } from './contract.js';
2
+ export declare class CardStore implements CardStoreApi {
3
+ private readonly deps;
4
+ constructor(deps: CardStoreDeps);
5
+ get(sessionId: string): Promise<SessionCardDeclared | null>;
6
+ set(sessionId: string, patch: CardPatch): Promise<SessionCardDeclared>;
7
+ clear(sessionId: string): Promise<void>;
8
+ private notify;
9
+ }
@@ -0,0 +1,188 @@
1
+ import { BLOCKED_ON_KINDS, CARD_LIMITS, CARD_STATES, CardValidationError, } from './contract.js';
2
+ const ALLOWED_PATCH_KEYS = new Set(['state', 'headline', 'progress', 'blockedOn', 'next']);
3
+ const SESSION_REF_PATTERN = /^[A-Za-z0-9_-]{1,200}$/;
4
+ function hasOwn(record, key) {
5
+ return Object.prototype.hasOwnProperty.call(record, key);
6
+ }
7
+ function cleanText(value, field, minLength, maxLength) {
8
+ if (typeof value !== 'string')
9
+ throw new CardValidationError(`${field} must be a string`);
10
+ const withoutControls = [...value].map((char) => {
11
+ const code = char.codePointAt(0) ?? 0;
12
+ return code <= 31 || code === 127 ? ' ' : char;
13
+ }).join('');
14
+ const cleaned = withoutControls.replace(/\s+/g, ' ').trim();
15
+ const cleanedLength = [...cleaned].length;
16
+ if (cleanedLength < minLength)
17
+ throw new CardValidationError(`${field} must not be empty`);
18
+ if (cleanedLength > maxLength)
19
+ throw new CardValidationError(`${field} must be at most ${maxLength} characters`);
20
+ return cleaned;
21
+ }
22
+ function parseProgress(value) {
23
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
24
+ throw new CardValidationError('Progress must be an object');
25
+ }
26
+ const record = value;
27
+ const done = record.done;
28
+ const total = record.total;
29
+ if (typeof done !== 'number' || typeof total !== 'number' || !Number.isInteger(done) || !Number.isInteger(total)) {
30
+ throw new CardValidationError('Progress done and total must be integers');
31
+ }
32
+ if (total < 1 || total > CARD_LIMITS.progressTotal) {
33
+ throw new CardValidationError(`Progress total must be between 1 and ${CARD_LIMITS.progressTotal}`);
34
+ }
35
+ if (done < 0 || done > total) {
36
+ throw new CardValidationError('Progress done must be between 0 and total');
37
+ }
38
+ return { done, total };
39
+ }
40
+ function parseBlockedOn(value) {
41
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
42
+ throw new CardValidationError('Blocked-on must be an object');
43
+ }
44
+ const record = value;
45
+ const kind = BLOCKED_ON_KINDS.find((candidate) => candidate === record.kind);
46
+ if (!kind)
47
+ throw new CardValidationError('Blocked-on kind is invalid');
48
+ const text = cleanText(record.text, 'Blocked-on text', 1, CARD_LIMITS.blockedText);
49
+ if (kind === 'session') {
50
+ const ref = record.ref;
51
+ if (typeof ref !== 'string' || !SESSION_REF_PATTERN.test(ref)) {
52
+ throw new CardValidationError('Blocked-on session ref is invalid');
53
+ }
54
+ return { kind, ref, text };
55
+ }
56
+ if (hasOwn(record, 'ref') && record.ref !== undefined && record.ref !== null) {
57
+ throw new CardValidationError('Blocked-on ref is only allowed when kind is session');
58
+ }
59
+ return { kind, text };
60
+ }
61
+ function parsePatch(patch) {
62
+ if (typeof patch !== 'object' || patch === null || Array.isArray(patch)) {
63
+ throw new CardValidationError('Card update must be an object');
64
+ }
65
+ const record = patch;
66
+ const keys = Object.keys(record).filter((key) => record[key] !== undefined);
67
+ if (keys.length === 0)
68
+ throw new CardValidationError('Empty card update');
69
+ for (const key of keys) {
70
+ if (!ALLOWED_PATCH_KEYS.has(key))
71
+ throw new CardValidationError(`Unknown card field: ${key}`);
72
+ }
73
+ const parsed = {
74
+ hasState: keys.includes('state'),
75
+ hasHeadline: keys.includes('headline'),
76
+ hasProgress: keys.includes('progress'),
77
+ hasBlockedOn: keys.includes('blockedOn'),
78
+ hasNext: keys.includes('next'),
79
+ };
80
+ if (parsed.hasState) {
81
+ const state = CARD_STATES.find((candidate) => candidate === record.state);
82
+ if (!state)
83
+ throw new CardValidationError('Card state is invalid');
84
+ parsed.state = state;
85
+ }
86
+ if (parsed.hasHeadline) {
87
+ parsed.headline = cleanText(record.headline, 'Headline', 1, CARD_LIMITS.headline);
88
+ }
89
+ if (parsed.hasProgress) {
90
+ parsed.progress = record.progress === null ? null : parseProgress(record.progress);
91
+ }
92
+ if (parsed.hasBlockedOn) {
93
+ parsed.blockedOn = record.blockedOn === null ? null : parseBlockedOn(record.blockedOn);
94
+ }
95
+ if (parsed.hasNext) {
96
+ if (record.next === null) {
97
+ parsed.next = null;
98
+ }
99
+ else {
100
+ const cleanedNext = cleanText(record.next, 'Next', 0, CARD_LIMITS.next);
101
+ parsed.next = cleanedNext === '' ? null : cleanedNext;
102
+ }
103
+ }
104
+ return parsed;
105
+ }
106
+ function applyParsed(existing, parsed, updatedAt) {
107
+ if (!existing && (!parsed.hasState || !parsed.hasHeadline)) {
108
+ throw new CardValidationError('First card update must include state and headline');
109
+ }
110
+ let state = existing?.state;
111
+ let headline = existing?.headline;
112
+ let progress = existing?.progress;
113
+ let blockedOn = existing?.blockedOn;
114
+ let next = existing?.next;
115
+ if (parsed.hasState)
116
+ state = parsed.state;
117
+ if (parsed.hasHeadline)
118
+ headline = parsed.headline;
119
+ if (parsed.hasProgress)
120
+ progress = parsed.progress === null ? undefined : parsed.progress;
121
+ if (parsed.hasBlockedOn)
122
+ blockedOn = parsed.blockedOn === null ? undefined : parsed.blockedOn;
123
+ if (parsed.hasNext)
124
+ next = parsed.next === null ? undefined : parsed.next;
125
+ if (state !== 'blocked' && !parsed.hasBlockedOn)
126
+ blockedOn = undefined;
127
+ if (state === undefined || headline === undefined) {
128
+ throw new CardValidationError('First card update must include state and headline');
129
+ }
130
+ const card = { state, headline, updatedAt };
131
+ if (progress !== undefined)
132
+ card.progress = progress;
133
+ if (blockedOn !== undefined)
134
+ card.blockedOn = blockedOn;
135
+ if (next !== undefined)
136
+ card.next = next;
137
+ return card;
138
+ }
139
+ export class CardStore {
140
+ deps;
141
+ constructor(deps) {
142
+ this.deps = deps;
143
+ }
144
+ async get(sessionId) {
145
+ const session = await this.deps.loadSession(sessionId);
146
+ return session?.card ?? null;
147
+ }
148
+ async set(sessionId, patch) {
149
+ const session = await this.deps.loadSession(sessionId);
150
+ if (!session)
151
+ throw new Error('Session not found');
152
+ const parsed = parsePatch(patch);
153
+ const updatedAt = new Date(this.deps.now()).toISOString();
154
+ const fresh = await this.deps.loadSession(sessionId);
155
+ if (!fresh)
156
+ throw new Error('Session not found');
157
+ const previousCard = fresh.card ?? null;
158
+ const card = applyParsed(previousCard, parsed, updatedAt);
159
+ const savedSession = { ...fresh, card };
160
+ await this.deps.saveSession(savedSession);
161
+ await this.notify(savedSession, previousCard);
162
+ return card;
163
+ }
164
+ async clear(sessionId) {
165
+ const session = await this.deps.loadSession(sessionId);
166
+ if (!session || !session.card)
167
+ return;
168
+ const fresh = await this.deps.loadSession(sessionId);
169
+ if (!fresh || !fresh.card)
170
+ return;
171
+ const previousCard = fresh.card;
172
+ const savedSession = { ...fresh };
173
+ delete savedSession.card;
174
+ await this.deps.saveSession(savedSession);
175
+ await this.notify(savedSession, previousCard);
176
+ }
177
+ async notify(session, previous) {
178
+ if (!this.deps.onChange)
179
+ return;
180
+ try {
181
+ await this.deps.onChange(session, previous);
182
+ }
183
+ catch (error) {
184
+ console.warn('CardStore onChange failed', error);
185
+ }
186
+ }
187
+ }
188
+ //# sourceMappingURL=card-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"card-store.js","sourceRoot":"","sources":["../../src/coordination/card-store.ts"],"names":[],"mappings":"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"}