paseo-room 0.8.0 → 0.9.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 (43) hide show
  1. package/README.md +51 -10
  2. package/dist/index.js +29 -5
  3. package/dist/index.js.map +1 -1
  4. package/dist/prompts/runtime/handoff-request.md +42 -0
  5. package/dist/prompts/runtime/successor-kickoff.md +13 -0
  6. package/dist/runtime-plugin/client/context-settings.tsx +93 -0
  7. package/dist/runtime-plugin/client/data.ts +6 -0
  8. package/dist/runtime-plugin/client/forms.tsx +167 -77
  9. package/dist/runtime-plugin/client/kit.tsx +1 -10
  10. package/dist/runtime-plugin/client/model.ts +116 -1
  11. package/dist/runtime-plugin/client/pills.ts +5 -1
  12. package/dist/runtime-plugin/client/record.tsx +2 -1
  13. package/dist/runtime-plugin/client/room.tsx +84 -11
  14. package/dist/runtime-plugin/client/succession.tsx +279 -0
  15. package/dist/runtime-plugin/client/time.ts +21 -0
  16. package/dist/runtime-plugin/client/views.tsx +18 -5
  17. package/dist/runtime-plugin/index.server.ts +40 -34
  18. package/dist/runtime-plugin/server/attention/engine.ts +78 -2
  19. package/dist/runtime-plugin/server/attention/log.ts +7 -1
  20. package/dist/runtime-plugin/server/attention/observer.ts +59 -13
  21. package/dist/runtime-plugin/server/attention/seat-starter.ts +16 -5
  22. package/dist/runtime-plugin/server/attention/signals.ts +28 -2
  23. package/dist/runtime-plugin/server/attention/succession-store.ts +109 -0
  24. package/dist/runtime-plugin/server/attention/succession.ts +592 -0
  25. package/dist/runtime-plugin/server/context.ts +31 -5
  26. package/dist/runtime-plugin/server/contracts/actions.ts +1 -1
  27. package/dist/runtime-plugin/server/controller.ts +28 -2
  28. package/dist/runtime-plugin/server/domain/acceptance.ts +12 -2
  29. package/dist/runtime-plugin/server/domain/state.ts +1 -1
  30. package/dist/runtime-plugin/server/domain/views.ts +40 -0
  31. package/dist/runtime-plugin/server/generated/succession.ts +11 -0
  32. package/dist/runtime-plugin/server/handlers/actions.ts +14 -5
  33. package/dist/runtime-plugin/server/handlers/turns.ts +62 -2
  34. package/dist/runtime-plugin/server/hooks.ts +81 -0
  35. package/dist/runtime-plugin/server/paseo-port.ts +84 -9
  36. package/dist/runtime-plugin/server/recovery.ts +11 -2
  37. package/dist/runtime-plugin/server/rpc.ts +52 -14
  38. package/dist/runtime-plugin/server/timeout.ts +24 -0
  39. package/dist/runtime-plugin/server/tools.ts +3 -2
  40. package/dist/runtime-plugin/shared/limits.ts +2 -0
  41. package/dist/runtime-plugin/shared/rpc-contracts.ts +39 -1
  42. package/dist/runtime-plugin/shared/seat-context.ts +77 -0
  43. package/package.json +1 -1
package/README.md CHANGED
@@ -278,9 +278,9 @@ recreate an existing Claude session after setup or an update.
278
278
  have none. Only the contract is dropped, never your own memory, and an earlier generation of it
279
279
  is removed rather than left behind. The choice is recorded in `room.json`, so `verify` compares
280
280
  against it and rejects the flag itself; `setup` without the flag restores the fallback. Keep the
281
- fallback unless you have a reason not to: the plugin hook is verified, and on Paseo 0.9.1 a
282
- *resumed* session was observed to keep the room prompt, but that is not proven for every
283
- supported version or for what the model actually reads, and `CLAUDE.md` is what covers that case.
281
+ fallback unless you have a reason not to: the plugin hook is verified, and a *resumed* session
282
+ keeps the room prompt it was created with (on Paseo 0.9.2 a daemon restart does not refresh it),
283
+ but what the model actually reads is not proven, and `CLAUDE.md` is what covers that case.
284
284
 
285
285
  Pi providers use a strict command tail:
286
286
 
@@ -406,8 +406,10 @@ npx paseo-room@<new-version> verify
406
406
  First inspect the dry run, then apply it. The apply regenerates managed prompt carriers,
407
407
  the Codex model catalogs and `AUTHENTICATION.md` from the newly resolved binaries, but
408
408
  preserves role credential paths and the operator agent homes. Stop and restart every affected
409
- seat after the apply; sending another turn to an already-running seat is not a restart.
410
- `setup` and `verify` prove the files and live Paseo configuration, not that an existing model
409
+ seat after the apply; sending another turn to an already-running seat is not a restart. A
410
+ Claude seat keeps the contract Paseo stored when it was created, and a daemon restart resumes it
411
+ with that same prompt, so for Claude open a new seat instead. `setup` and `verify` prove the
412
+ files and live Paseo configuration, not that an existing model
411
413
  context reloaded them. Only a newly launched seat context is expected to ingest the
412
414
  regenerated instructions.
413
415
 
@@ -624,6 +626,11 @@ npx paseo-room verify
624
626
  - **Lead** gains room tools such as `assignment_create`, `assignment_dispatch`, `assignment_answer`,
625
627
  `assignment_accept`, `gate_run`, and for isolated writers `workspace_close` and `lease_reclaim`.
626
628
  `assignment_create` refuses a base that is not a commit of the repository (`base_unknown`).
629
+ `gate_run` runs in the background, and a notice tells Lead when the gate ends, green, red or
630
+ without a trustworthy result.
631
+ `assignment_status` leaves out the brief Lead wrote (its outcome stays), keeps the last 10 history
632
+ entries, and gives a decided assignment with nothing left to close one line, unless Lead passes
633
+ `full: true`.
627
634
  **Supervisor** gains `room_status`, `runtime_findings`, `message_lead` (with a `project` for a
628
635
  Supervisor of several projects) and `attention_feedback`, and cannot change an assignment. Its
629
636
  status and findings cover only its portfolio and the project it stands in; `room_status` lists
@@ -636,6 +643,16 @@ npx paseo-room verify
636
643
  `ultracode`, which start agents on their own. It records the choice, shows it with the reason to
637
644
  Supervisor and in the panel, and keeps it for a reclaimed Peer while you still allow it. The model
638
645
  itself is never Lead's to change.
646
+ - **Seat context.** The panel and each seat's role pill show how full the seat's context is, as
647
+ Paseo reports it for the latest model call, and when the runtime last saw it compact. **Settings ›
648
+ Room seats › Seat context** sets marks per role, as a share of each seat's own model window:
649
+ - *Lead · report at* (30%): past it, the Lead's Supervisor gets one fact line and the panel shows
650
+ it with **Replace Lead…**, so you can hand over to a fresh Lead rather than let this one compact.
651
+ - *compact at* (Lead 50%, Supervisor and Peer off): a room Claude seat gets
652
+ `CLAUDE_CODE_AUTO_COMPACT_WINDOW` when its session opens, at creation or on a resume after a
653
+ daemon restart, so Claude compacts at that share instead of near the end of a 1M window. An open
654
+ session keeps what it opened with. Codex and Pi seats show their context and keep their own
655
+ compaction.
639
656
  - **A runtime-dispatched Peer** is titled `<Disposition> · <outcome gist> · <assignment id>` (for
640
657
  example `Reviewer · Review the Docker Compose dev env… · asg_…`), and the runtime's notices to Lead
641
658
  name the assignment the same way. It gets exactly two tools, `ask` and `handoff`, for its own
@@ -655,7 +672,8 @@ npx paseo-room verify
655
672
  - A project shows its Supervisor, its Lead and Peer seats (each opens its agent in Paseo, and
656
673
  shows the model and thinking option it runs with) and its runtime record: assignments, isolated
657
674
  writers, findings and recovery.
658
- - Starting a Supervisor, starting a project and assigning a Supervisor are guided forms.
675
+ - Starting a Supervisor, adding a repository, starting a Lead for a project that has none, and
676
+ assigning a Supervisor are guided forms.
659
677
  - The design notes are in [docs/design/runtime-panel-ux.md](docs/design/runtime-panel-ux.md).
660
678
  - **Settings › Room seats** shows which account each seat is signed in to (email, plan and
661
679
  organization for Claude; login method for Codex; for Pi, only whether a credential file exists).
@@ -679,6 +697,7 @@ learn only when you ask it to check.
679
697
  count.
680
698
  - They report a Lead archived while its seats still work, and a Lead's finished turn that the
681
699
  Supervisor did not prompt itself.
700
+ - They report, in a digest, a Lead whose context passes the rotation mark, once per crossing.
682
701
  - The Lead contract has Lead put a question for you on a line beginning `NEEDS-HUMAN:` and an
683
702
  incident on one beginning `INCIDENT:`. The first wakes the Supervisor and the second pages it,
684
703
  even for a turn it prompted, once per line, and the letter quotes those lines rather than the
@@ -689,10 +708,32 @@ learn only when you ask it to check.
689
708
  - Each item has an id for `attention_feedback`, and a letter's own id rates every item in it. A
690
709
  letter is evidence, not an instruction: the Supervisor contract has it ask or nudge the Lead, or
691
710
  relay a question to you, and never direct a Peer.
692
- - **Starting seats.** From the **Room** view, **Start Supervisor** opens one in an existing directory
693
- outside every repository. **Start project** checks a repository, opens its Lead under the
694
- Supervisor you pick, and sends a fixed kickoff with your first directive verbatim. **Assign
695
- Supervisor** moves an existing project under a Supervisor.
711
+ - **Starting seats.** From the **Room** view, **New Supervisor** opens one in an existing directory
712
+ outside every repository. **Add repository** checks a repository, opens its Lead under the
713
+ Supervisor you pick, and sends a fixed kickoff with your first directive verbatim; it also offers
714
+ the projects the room observes without a Lead. A project with no live Lead offers **Start Lead**
715
+ on its own screen, with its Supervisor preselected. **Assign Supervisor** moves an existing
716
+ project under a Supervisor.
717
+ - **Replacing a Lead.** **Replace Lead…** above a project's seats, or on a *context past rotation
718
+ mark* item, hands the project to a fresh Lead:
719
+ - It checks for a quiet point first: the Lead idle, every runtime assignment it leads settled, no
720
+ runtime notice waiting for it, no seat it opened still working. It also shows what Paseo's
721
+ archive does to each seat the Lead opened: those in its workspace are archived with it, and one
722
+ in another workspace or open in a tab is detached and kept.
723
+ - It asks the Lead for a handoff in fixed sections, and you review and edit it. Nothing is
724
+ archived until you confirm, and you may cancel until then.
725
+ - On **Replace Lead**, the runtime archives the Lead and starts `<repository> — Lead` with the same
726
+ agent under the same Supervisor. The new Lead's first message is the kickoff and your reviewed
727
+ handoff, verbatim, and it verifies the handoff and reports to you before it acts outside the
728
+ repository. The Supervisor gets one line naming the new Lead.
729
+ - The handoff stays on this machine, under `~/.paseo-room/runtime/v1/attention/successions/`,
730
+ owner-only and never sent to the sensor or in a letter. Finished replacements are pruned after 30
731
+ days.
732
+ - If the replacement stops after the archive, the project offers **Finish replacing Lead**, which
733
+ creates no second Lead, or cancel, which leaves the project as it is. A replacement that fails
734
+ before the archive stays on the project's screen for a day, with the reason.
735
+ - Paseo archives the seats in the Lead's workspace with it; the runtime archives them too when the
736
+ Lead is not running, when Paseo would take none.
696
737
  - **Settings › Room attention.** Here you turn letters on or off, change their thresholds, and
697
738
  configure the optional **attention sensor**.
698
739
  - The sensor speaks the System One HTTP shape, with [TypeSafe Jev](https://docs.typesafe.ai/)
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ var init_package = __esm({
15
15
  "package.json"() {
16
16
  package_default = {
17
17
  name: "paseo-room",
18
- version: "0.8.0",
18
+ version: "0.9.0",
19
19
  description: "One CLI that configures Codex, Claude Code, and Pi role homes in $HOME and registers them with your local Paseo daemon.",
20
20
  keywords: [
21
21
  "paseo",
@@ -870,6 +870,11 @@ var init_prompts = __esm({
870
870
  pi: {
871
871
  communicationStyle: { path: "pi/communication-style.md", kind: "capsule" },
872
872
  runtime: { path: "pi/runtime.md", kind: "capsule" }
873
+ },
874
+ /** Messages the runtime plugin sends a Lead on Human's instruction; setup renders them into the plugin. */
875
+ runtime: {
876
+ handoffRequest: { path: "runtime/handoff-request.md", kind: "section" },
877
+ successorKickoff: { path: "runtime/successor-kickoff.md", kind: "section" }
873
878
  }
874
879
  };
875
880
  PromptAssetError = class extends Error {
@@ -2417,6 +2422,21 @@ function renderRuntimeManifestFile(agents, roles) {
2417
2422
  return `${JSON.stringify(renderRuntimeManifest(agents, roles), null, 2)}
2418
2423
  `;
2419
2424
  }
2425
+ function renderSuccessionText() {
2426
+ return [
2427
+ "/** Generated by paseo-room setup. The Markdown prompt assets remain authoritative. */",
2428
+ "export interface SuccessionText {",
2429
+ " readonly request: string;",
2430
+ " readonly kickoff: string;",
2431
+ "}",
2432
+ "",
2433
+ "export const SUCCESSION_TEXT: SuccessionText | undefined = {",
2434
+ ` request: ${typescriptTemplateLiteral(loadPromptAsset("runtime", "handoffRequest"))},`,
2435
+ ` kickoff: ${typescriptTemplateLiteral(loadPromptAsset("runtime", "successorKickoff"))},`,
2436
+ "};",
2437
+ ""
2438
+ ].join("\n");
2439
+ }
2420
2440
  function renderRuntimeLocation(layout) {
2421
2441
  const location = { pluginDirectory: runtimePluginDir(layout), runtimeRoot: join12(layout.roomHome, "runtime", "v1") };
2422
2442
  return [
@@ -2448,22 +2468,25 @@ function runtimePluginEntries(layout, agents, roles) {
2448
2468
  ...files.map((path) => ({
2449
2469
  kind: "file",
2450
2470
  path: join12(root, path),
2451
- content: path === LOCATION_MODULE ? renderRuntimeLocation(layout) : readFileSync4(join12(BUNDLE, path), "utf8")
2471
+ content: path === LOCATION_MODULE ? renderRuntimeLocation(layout) : path === SUCCESSION_MODULE ? renderSuccessionText() : readFileSync4(join12(BUNDLE, path), "utf8")
2452
2472
  })),
2453
2473
  { kind: "file", path: join12(root, MANIFEST_FILE), content: renderRuntimeManifestFile(agents, roles) }
2454
2474
  ];
2455
2475
  }
2456
- var BUNDLE, LOCATION_MODULE;
2476
+ var BUNDLE, LOCATION_MODULE, SUCCESSION_MODULE;
2457
2477
  var init_runtime = __esm({
2458
2478
  "src/runtime.ts"() {
2459
2479
  "use strict";
2480
+ init_plugin();
2460
2481
  init_roles();
2461
2482
  init_instructions();
2483
+ init_prompts();
2462
2484
  init_manifest();
2463
2485
  init_identity();
2464
2486
  init_policy();
2465
2487
  BUNDLE = fileURLToPath(new URL("./runtime-plugin/", import.meta.url));
2466
2488
  LOCATION_MODULE = "server/generated/location.ts";
2489
+ SUCCESSION_MODULE = "server/generated/succession.ts";
2467
2490
  }
2468
2491
  });
2469
2492
 
@@ -2481,7 +2504,7 @@ function boundedString(max = MAX_STRING_BYTES) {
2481
2504
  function boundedArray(item) {
2482
2505
  return z4.array(item).max(MAX_ARRAY_ITEMS);
2483
2506
  }
2484
- var MAX_AGGREGATE_BYTES, MAX_ARRAY_ITEMS, MAX_STRING_BYTES, MAX_COMMAND_BYTES, MAX_GATE_TIMEOUT_SECONDS, encoder, MAX_WORKTREE_LEASES;
2507
+ var MAX_AGGREGATE_BYTES, MAX_ARRAY_ITEMS, MAX_STRING_BYTES, MAX_COMMAND_BYTES, MAX_GATE_TIMEOUT_SECONDS, MAX_HANDOFF_BYTES, encoder, MAX_WORKTREE_LEASES;
2485
2508
  var init_limits = __esm({
2486
2509
  "src/runtime-plugin/shared/limits.ts"() {
2487
2510
  "use strict";
@@ -2490,6 +2513,7 @@ var init_limits = __esm({
2490
2513
  MAX_STRING_BYTES = 8 * 1024;
2491
2514
  MAX_COMMAND_BYTES = 16 * 1024;
2492
2515
  MAX_GATE_TIMEOUT_SECONDS = 3600;
2516
+ MAX_HANDOFF_BYTES = 64 * 1024;
2493
2517
  encoder = new TextEncoder();
2494
2518
  MAX_WORKTREE_LEASES = 3;
2495
2519
  }
@@ -3311,7 +3335,7 @@ var init_actions = __esm({
3311
3335
  assignment_reject: z6.strictObject({ ...assignment, reason }),
3312
3336
  assignment_abandon: z6.strictObject({ ...assignment, reason }),
3313
3337
  assignment_close: z6.strictObject(assignment),
3314
- assignment_status: z6.strictObject({ assignmentId: assignmentIdSchema.optional() }),
3338
+ assignment_status: z6.strictObject({ assignmentId: assignmentIdSchema.optional(), full: z6.boolean().optional() }),
3315
3339
  gate_run: z6.strictObject(assignment),
3316
3340
  // Discarding a retained worktree's uncommitted work is Lead's explicit decision, with a reason.
3317
3341
  workspace_close: z6.strictObject({ ...assignment, discardUncommitted: z6.literal(true).optional(), reason: reason.optional() }).refine((input) => input.discardUncommitted !== true || input.reason !== void 0, { message: "discardUncommitted needs a reason", path: ["reason"] }),