ftown 0.26.0 → 0.28.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 (83) hide show
  1. package/dist/attention-cli.d.ts +32 -0
  2. package/dist/attention-cli.js +310 -0
  3. package/dist/attention-cli.js.map +1 -0
  4. package/dist/attention-events.d.ts +2 -1
  5. package/dist/attention-events.js.map +1 -1
  6. package/dist/attention-store.d.ts +6 -3
  7. package/dist/attention-store.js +60 -2
  8. package/dist/attention-store.js.map +1 -1
  9. package/dist/brief-cli.d.ts +10 -0
  10. package/dist/brief-cli.js +163 -0
  11. package/dist/brief-cli.js.map +1 -0
  12. package/dist/command-rpc.d.ts +11 -0
  13. package/dist/command-rpc.js +83 -16
  14. package/dist/command-rpc.js.map +1 -1
  15. package/dist/coordination/attention-routing.d.ts +37 -0
  16. package/dist/coordination/attention-routing.js +154 -0
  17. package/dist/coordination/attention-routing.js.map +1 -0
  18. package/dist/coordination/board.js +82 -3
  19. package/dist/coordination/board.js.map +1 -1
  20. package/dist/coordination/contract-b.d.ts +206 -0
  21. package/dist/coordination/contract-b.js +58 -0
  22. package/dist/coordination/contract-b.js.map +1 -0
  23. package/dist/coordination/contract-c.d.ts +117 -0
  24. package/dist/coordination/contract-c.js +47 -0
  25. package/dist/coordination/contract-c.js.map +1 -0
  26. package/dist/coordination/contract.d.ts +8 -1
  27. package/dist/coordination/contract.js +1 -1
  28. package/dist/coordination/contract.js.map +1 -1
  29. package/dist/coordination/format.js +51 -12
  30. package/dist/coordination/format.js.map +1 -1
  31. package/dist/coordination/plan.d.ts +74 -0
  32. package/dist/coordination/plan.js +534 -0
  33. package/dist/coordination/plan.js.map +1 -0
  34. package/dist/coordination/routes-brief.d.ts +10 -0
  35. package/dist/coordination/routes-brief.js +149 -0
  36. package/dist/coordination/routes-brief.js.map +1 -0
  37. package/dist/coordination/routes-plan.d.ts +13 -0
  38. package/dist/coordination/routes-plan.js +182 -0
  39. package/dist/coordination/routes-plan.js.map +1 -0
  40. package/dist/coordination/routes-worktrees.d.ts +29 -0
  41. package/dist/coordination/routes-worktrees.js +138 -0
  42. package/dist/coordination/routes-worktrees.js.map +1 -0
  43. package/dist/coordination/wiring.d.ts +17 -2
  44. package/dist/coordination/wiring.js +81 -11
  45. package/dist/coordination/wiring.js.map +1 -1
  46. package/dist/coordination-cli.d.ts +6 -1
  47. package/dist/coordination-cli.js +23 -7
  48. package/dist/coordination-cli.js.map +1 -1
  49. package/dist/create-ftown-session.d.ts +26 -1
  50. package/dist/create-ftown-session.js +208 -104
  51. package/dist/create-ftown-session.js.map +1 -1
  52. package/dist/ftown-cli.js +14 -2
  53. package/dist/ftown-cli.js.map +1 -1
  54. package/dist/index.js +29 -0
  55. package/dist/index.js.map +1 -1
  56. package/dist/local-api-server.d.ts +24 -0
  57. package/dist/local-api-server.js +473 -32
  58. package/dist/local-api-server.js.map +1 -1
  59. package/dist/mail-delivery.d.ts +18 -4
  60. package/dist/mail-delivery.js +50 -8
  61. package/dist/mail-delivery.js.map +1 -1
  62. package/dist/plan-cli.d.ts +52 -0
  63. package/dist/plan-cli.js +357 -0
  64. package/dist/plan-cli.js.map +1 -0
  65. package/dist/security/bridge/permissions.js +55 -5
  66. package/dist/security/bridge/permissions.js.map +1 -1
  67. package/dist/session-controller.d.ts +17 -1
  68. package/dist/session-controller.js +93 -2
  69. package/dist/session-controller.js.map +1 -1
  70. package/dist/sessions-commands.js +75 -5
  71. package/dist/sessions-commands.js.map +1 -1
  72. package/dist/types.d.ts +9 -1
  73. package/dist/worktrees-cli.d.ts +39 -0
  74. package/dist/worktrees-cli.js +168 -0
  75. package/dist/worktrees-cli.js.map +1 -0
  76. package/dist/worktrees.d.ts +16 -0
  77. package/dist/worktrees.js +292 -0
  78. package/dist/worktrees.js.map +1 -0
  79. package/hooks/ftown-antigravity-hook.sh +12 -6
  80. package/package.json +2 -2
  81. package/skills/ftown/SKILL.md +88 -5
  82. package/skills/ftown/references/orchestrator.md +32 -29
  83. package/skills/ftown/references/sessions.md +155 -12
@@ -76,18 +76,111 @@ ftown board [--json] [--since <n>] [--ready] [--all] [--session-id <id>]
76
76
  # Wait until a board condition holds
77
77
  ftown board [--wait --until any-change|any-done|any-blocked|all-done|any-ready [--timeout <s≤300>]] [--session-id <id>]
78
78
 
79
- # Tree events for my tree (status, attention, pr, preview, exit, idle, result, mail)
79
+ # Tree events for my tree (status, attention, pr, preview, exit, idle, result, mail, plan, removed)
80
80
  ftown events [--json] [--since <n>] [--limit <n>] [--wait [--timeout <s≤300>]] [--session-id <id>]
81
81
  ```
82
82
 
83
83
  `--ready` lists only children whose PR checks passed and who are not done;
84
- `--all` includes archived/completed children; `--since <n>` limits the board
85
- to children with events after that cursor (the board prints its cursor).
86
- Pass the cursor back as `--since` to see only what changed.
84
+ `--all` includes retired (archived) children after the live ones, newest
85
+ first, capped at 50 and suffixed `(retired)` in plain output; `--since <n>`
86
+ limits the board to children with events after that cursor (the board
87
+ prints its cursor). Pass the cursor back as `--since` to see only what
88
+ changed. Plain board output appends a `planned` section after the child
89
+ rows: up to 5 ready plan items as `→ <id> <title>`, then `+N more` when
90
+ more are ready.
91
+
92
+ Tree events also include `plan` (one per plan change, summary
93
+ `<id> <state>: <title>`, plus ` → ready: <id>, …` when items become ready)
94
+ and `removed` (summary `removed`, when a child is removed or archived
95
+ while not already exited).
87
96
 
88
97
  Exit codes for `status`, `board` and `events`: 0 ok, 1 error, 2 usage,
89
98
  3 wait timed out with the condition unmet.
90
99
 
100
+ ## Plan list
101
+
102
+ The plan is the manager's plan, not a ticket system: a todo list with
103
+ precedence stored on the manager (parent) session. It defaults to
104
+ `FTOWN_SESSION_ID`; `--session-id <id>` targets another session's plan.
105
+
106
+ ```bash
107
+ # List in plan order (--json passes the PlanView through)
108
+ ftown plan [--json] [--session-id <id>]
109
+
110
+ # Add (title is the remaining words; precedence via --after/--priority)
111
+ ftown plan add <title...> [--note <t>] [--after <id,id>] [--priority 1|2|3] [--session-id <id>]
112
+
113
+ # Link an existing child, or set state directly
114
+ ftown plan start <id> --session <child-id> [--session-id <id>]
115
+ ftown plan done <id> [--session-id <id>]
116
+ ftown plan drop <id> [--session-id <id>]
117
+ ftown plan todo <id> [--session-id <id>]
118
+
119
+ # Edit or remove (removing strips the id from other items' after lists)
120
+ ftown plan edit <id> [--title <t>] [--note <t>|--no-note] [--after <ids>|--no-after] [--priority n] [--session-id <id>]
121
+ ftown plan rm <id> [--session-id <id>]
122
+
123
+ # Create a child for a plan item (marks it started, linked to the child)
124
+ ftown sessions create --parent --plan-item <id> --prompt "<task>"
125
+ ```
126
+
127
+ List marks: `→` ready, `·` waiting, `▸` started, `✓` done, `✗` dropped,
128
+ printed as `<mark> <id> [P<priority>] <title>` plus `(after p1,p2)` or
129
+ `→ <child name>` when linked. Ordering is ready first, then waiting (both
130
+ by priority ascending, then creation time), then started, done and
131
+ dropped. An item is ready when it is `todo` and every item in its `after`
132
+ list is `done` or `dropped`; precedence is set only with `--after` and
133
+ `--priority` (1 is highest). Item ids are `p<n>` and are never reused.
134
+ Limits: 200 items, title 140 characters, note 500, at most 20 `after`
135
+ ids; `after` ids must exist, with no self-reference or cycles.
136
+
137
+ `--plan-item <id>` (on `ftown sessions create`, requires `--parent` or
138
+ `--parent-id`) fails with an error before any session is created when the
139
+ item is unknown or not `todo`; after creation the item becomes `started`
140
+ with the child linked, and a linking failure only warns (the session
141
+ stays). When a linked child's card becomes `done`, the item becomes
142
+ `done`; a `failed` card leaves it `started` for the manager to decide.
143
+ Setting an item back to `todo` clears its linked session. Exit codes for
144
+ `ftown plan`: 0 ok, 1 error, 2 usage.
145
+
146
+ ## Manager brief
147
+
148
+ A coordinating session keeps a markdown brief plus timestamped notes; the
149
+ dashboard overview renders the brief, the last 10 notes and the session's
150
+ children automatically. The target defaults to `FTOWN_SESSION_ID`.
151
+
152
+ ```bash
153
+ ftown brief show [--json] [--session-id <id>]
154
+ ftown brief set (--file <path.md> | --text <t> | --clear) [--session-id <id>]
155
+ ftown brief note <text...> [--session-id <id>]
156
+ ```
157
+
158
+ Text is markdown, at most 16384 characters; a note is a single line of
159
+ 1–280 characters; at most 50 notes are kept (oldest dropped). Control
160
+ characters except newline and tab are stripped; text over the limit is an
161
+ error (exit 1), never truncated.
162
+
163
+ ## Worktrees
164
+
165
+ Children that write code can get a bridge-created git worktree. The default
166
+ branch is `ftown/<slug(name)>` at `<repoRoot>/.claude/worktrees/<slug(name)>`;
167
+ the base defaults to the current branch of the working directory (a detached
168
+ HEAD needs `--base`). Only bridge-created worktrees are ever removed.
169
+
170
+ ```bash
171
+ ftown sessions create --parent --worktree [--branch <b>] [--base <ref>] [--workdir <dir>]
172
+ ftown sessions remove <id> [--keep-worktree | --force-worktree]
173
+ ftown worktrees list [--json]
174
+ ftown worktrees prune [--json]
175
+ ```
176
+
177
+ On remove, a clean worktree whose branch is merged or fully pushed is
178
+ retired (worktree removed; the branch is deleted only when merged);
179
+ otherwise it is retained and the command prints why (for example
180
+ `worktree retained: 2 unpushed commits`). `--keep-worktree` always retains,
181
+ `--force-worktree` forces removal. `prune` applies the same rule to archived
182
+ sessions only.
183
+
91
184
  ## Preview session files
92
185
 
93
186
  ```bash
@@ -183,7 +276,9 @@ Attention persists an `agent_needs_input` event, returns its exact ID and update
183
276
  the existing dashboard attention flow. Logical duplicate unresolved requests
184
277
  coalesce while recording occurrences; resolving it permits a new incident.
185
278
  Only creation triggers notification, and hosted push remains opt-in with existing
186
- session/harness eligibility. Do not automatically retry an uncertain mutation.
279
+ session/harness eligibility. For a parent-routed item, creation notifies only
280
+ the parent; the dashboard notice and push fire if it is escalated to the human.
281
+ Do not automatically retry an uncertain mutation.
187
282
  Acknowledging/resolving an event never answers or approves a CLI prompt.
188
283
 
189
284
  ### Questions and answers
@@ -223,6 +318,37 @@ FTown session follow the same path and are answered from the dashboard inbox.
223
318
  The terminal picker appears only if the human chooses "Answer in terminal" or
224
319
  after an hour.
225
320
 
321
+ ### Parent-first routing
322
+
323
+ When the asking session has a running parent, the request goes to the parent
324
+ first: the parent receives one waking escalation mail (`[ftown question ...]`)
325
+ naming the commands below, and the human's inbox shows the item greyed as
326
+ "with parent" (the human may still answer it). There is no timer; only the
327
+ parent, or the parent stopping while the item is open, moves it to the human.
328
+
329
+ ```bash
330
+ # Open parent-routed questions from my children (plain: `<child> <eventId> <title>` plus options)
331
+ ftown attention list [--json]
332
+
333
+ # Answer a child's question (as the parent)
334
+ ftown attention answer <child-id> <event-id> (--option <n|label>... | --text <t> | --answers-json <json>) [--json]
335
+
336
+ # Raise it to the human instead (note at most 500 characters)
337
+ ftown attention escalate <child-id> <event-id> [--note <t>] [--json]
338
+
339
+ # Bypass the parent: only the human can provide this
340
+ ftown sessions attention --to human --message "Please paste the API token" --title "Credential needed"
341
+ ```
342
+
343
+ Answer only from facts you hold — the plan, the agreed contract, earlier
344
+ human answers. Preferences and irreversible choices are escalated, not
345
+ answered. A parent answer is delivered exactly like a human answer (live
346
+ waiter, or mail whose sender is the parent session).
347
+
348
+ Exit codes for `ftown attention`: 0 ok, 1 error, 2 usage, 4 forbidden (the
349
+ caller is not the child's parent), 5 conflict (already resolved or already
350
+ escalated to the human).
351
+
226
352
  PR links accept only HTTPS GitHub `/owner/repo/pull/<positive-number>` URLs.
227
353
  Outer whitespace, query/fragment and a trailing slash are normalized; credentials,
228
354
  nondefault ports and other paths/hosts are rejected. No GitHub request is made.
@@ -291,6 +417,10 @@ Fan-out targets are messaged sequentially, one JSON result line per target.
291
417
  | `--command` | Full command override (skips `--shell` builder) |
292
418
  | `--parent` | Set parent to `$FTOWN_SESSION_ID` |
293
419
  | `--parent-id` | Explicit parent session UUID |
420
+ | `--plan-item <id>` | Do plan item `p<n>` of the parent (requires `--parent` or `--parent-id`; see Plan list) |
421
+ | `--worktree` | Create a bridge-owned git worktree for the session (see Worktrees) |
422
+ | `--branch <b>` | Worktree branch (requires `--worktree`; default `ftown/<slug(name)>`) |
423
+ | `--base <ref>` | Ref the worktree branch starts from (requires `--worktree`) |
294
424
  | `--model` | Harness model name or provider/model pattern (when supported) |
295
425
 
296
426
  Provider-flavored shells (`zai`, `kimi`, `deepseek`, `fireworks`) run Claude
@@ -313,9 +443,9 @@ ftown sessions grep <child-id> --pattern 'FAIL|Error'
313
443
 
314
444
  ### Completion handoff
315
445
 
316
- When the task creates or updates a GitHub PR, associate its actual URL with the
317
- FTown session before the completion notice. Then request user attention once the
318
- task is complete, before the final handoff. Replace the sample URL and summary
446
+ A top-level session (no parent): when the task creates or updates a GitHub PR,
447
+ associate its actual URL with the FTown session before the completion notice.
448
+ Then request user attention once the task is complete, before the final handoff. Replace the sample URL and summary
319
449
  below with truthful outcomes and checks (including checks not run):
320
450
 
321
451
  ```bash
@@ -329,8 +459,10 @@ For tasks without a PR, omit the PR command and PR summary. Use the verified
329
459
 
330
460
  Send one completion request per completed task, not repeated per-turn notices.
331
461
  Logical duplicate coalescing does not justify retries after an uncertain outcome;
332
- inspect the existing request first, as described above. Child agents still send
333
- their assigned result to the parent; the user attention request is additional.
462
+ inspect the existing request first, as described above. Child agents do not
463
+ raise "Work complete": they set their card to `done` and send their assigned
464
+ result to the parent, and the parent raises one completion notice for the
465
+ whole job.
334
466
 
335
467
  ## Environment
336
468
 
@@ -361,7 +493,18 @@ The CLI wraps the loopback API. Raw access if needed:
361
493
  | GET | `/api/sessions` | List |
362
494
  | POST | `/api/sessions` | Create |
363
495
  | PATCH | `/api/sessions/:id` | Rename, move or associate a PR (`{ name?, parentSessionId?, pullRequestUrl? }`; `null` detaches/clears) |
364
- | POST | `/api/sessions/:id/attention` | Request human input (`{ message, title?, questions? }`) → `{ event }`; invalid `questions` → 400 `invalid_prompt` |
496
+ | POST | `/api/sessions/:id/attention` | Request input (`{ message, title?, questions?, to?: 'human' }`) → `{ event }`; invalid `questions` → 400 `invalid_prompt` |
497
+ | POST | `/api/sessions/:id/attention/:eventId/answer` | Parent answers a child (`{ answers }`); 403 not the parent, 409 resolved |
498
+ | POST | `/api/sessions/:id/attention/:eventId/escalate` | Parent raises it to the human (`{ note? }`); 403 not the parent, 409 already human/resolved |
499
+ | GET | `/api/sessions/:id/attention/routed` | Open parent-routed items of my children → `{ items }` |
500
+ | GET/PUT/DELETE | `/api/sessions/:id/brief` | Read, set/clear (`{ text: string \| null }`) or delete the manager brief |
501
+ | POST | `/api/sessions/:id/brief/notes` | Append a brief note (`{ text }`) |
502
+ | GET | `/api/sessions/:id/plan` | Read the plan (`PlanView`: ordered items plus ready ids) |
503
+ | POST | `/api/sessions/:id/plan` | Add a plan item (`{ title, note?, after?, priority? }`) → `{ item }` |
504
+ | PATCH | `/api/sessions/:id/plan/:itemId` | Edit a plan item (`{ title?, note?: string\|null, after?, priority?, state?, sessionId?: string\|null }`) → `{ item }`; item id is `p<n>` |
505
+ | DELETE | `/api/sessions/:id/plan/:itemId` | Remove a plan item (strips it from other items' `after`) → `{ ok: true }` |
506
+ | GET | `/api/worktrees` | List bridge-owned worktrees with git status |
507
+ | POST | `/api/worktrees/prune` | Retire eligible archived worktrees → `{ removed, retained }` |
365
508
  | GET | `/api/sessions/:id/attention/:eventId` | Read one item (`?waitSeconds=0..25` long-polls until resolved) → `{ event }`; 404 `attention_not_found` |
366
509
  | POST | `/api/sessions/:id/attention/ask` | Harness hook: record an AskUserQuestion (`{ toolName, toolUseId, toolInput }`) → `{ event }` or `null` if not promptable |
367
510
  | GET | `/api/sessions/:id/screen` | Terminal lines |
@@ -373,7 +516,7 @@ The CLI wraps the loopback API. Raw access if needed:
373
516
  | POST | `/api/sessions/:id/message` | Inject a message line as keystrokes (`{ text, from? }`) |
374
517
  | PUT | `/api/sessions/:id/preview` | Replace or add preview files, local CLI only (`{ paths: string[], mode: 'replace' \| 'add' }`) |
375
518
  | DELETE | `/api/sessions/:id/preview` | Remove preview files by name or clear the preview, local CLI only (`{ names?: string[] }`; absent names clears all) |
376
- | DELETE | `/api/sessions/:id` | Remove (tombstone-archived) |
519
+ | DELETE | `/api/sessions/:id` | Remove (tombstone-archived; `?worktree=keep\|force` overrides worktree retirement) |
377
520
  | GET | `/api/archive` | List removed-session tombstones |
378
521
  | POST | `/api/sessions/:id/revive` | Recreate a removed session (new id) |
379
522