@north-light/crouter 0.3.198 → 0.3.200
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/api/client.d.ts +18 -18
- package/dist/api/client.js +29 -37
- package/dist/api/dto/broker-ops.d.ts +3 -1
- package/dist/api/dto/broker.d.ts +13 -2
- package/dist/api/dto/broker.js +4 -4
- package/dist/api/dto/human.d.ts +6 -5
- package/dist/api/dto/inbox.d.ts +81 -34
- package/dist/api/dto/nodes.d.ts +8 -2
- package/dist/api/dto/profiles.d.ts +23 -0
- package/dist/api/dto/profiles.js +2 -2
- package/dist/api/dto/worktree.d.ts +3 -5
- package/dist/api/routes.d.ts +3 -5
- package/dist/api/routes.js +4 -6
- package/dist/builtin-memory/00-runtime-base.md +6 -6
- package/dist/builtin-memory/01-spine/01-no-manager.md +1 -1
- package/dist/builtin-memory/02-lifecycle/00-terminal.md +3 -3
- package/dist/builtin-memory/04-orchestration-kernel.md +6 -6
- package/dist/builtin-memory/05-kinds/design/00-base.md +1 -1
- package/dist/builtin-memory/05-kinds/plan/reviewers/security.md +2 -2
- package/dist/builtin-memory/05-kinds/review/00-base.md +2 -2
- package/dist/builtin-memory/05-kinds/review/01-orchestrator.md +1 -1
- package/dist/builtin-memory/05-kinds/spec/01-orchestrator.md +1 -1
- package/dist/builtin-memory/insights/capture.md +2 -2
- package/dist/builtin-memory/insights/init.md +3 -3
- package/dist/builtin-memory/internal/INDEX.md +1 -1
- package/dist/builtin-memory/internal/memory-loading.md +1 -1
- package/dist/builtin-memory/internal/nodes-and-canvas.md +2 -2
- package/dist/builtin-memory/internal/plugins.md +59 -2
- package/dist/builtin-memory/internal/storage-tiers.md +3 -1
- package/dist/builtin-memory/spec/roadmap.md +2 -2
- package/dist/builtin-memory/testing.md +1 -1
- package/dist/clients/attach/chrome/bash-jobs.js +3 -3
- package/dist/clients/attach/render/chat-view.d.ts +26 -1
- package/dist/clients/attach/render/chat-view.js +61 -11
- package/dist/clients/attach/render/page-block.d.ts +34 -0
- package/dist/clients/attach/render/page-block.js +226 -0
- package/dist/clients/attach/session/whip.d.ts +2 -0
- package/dist/clients/attach/session/whip.js +2 -0
- package/dist/clients/attach/viewer.js +1419 -993
- package/dist/clients/conversation/projection.js +18 -3
- package/dist/clients/inbox/__tests__/serial/inbox-controller.test.js +9 -6
- package/dist/clients/inbox/__tests__/serial/mount-panel.test.js +13 -21
- package/dist/clients/inbox/controller.js +10 -16
- package/dist/clients/inbox/page-adapter.d.ts +1 -3
- package/dist/clients/inbox/page-adapter.js +3 -4
- package/dist/clients/inbox/resolve.d.ts +1 -1
- package/dist/clients/inbox/resolve.js +3 -3
- package/dist/clients/inbox/review/document-surface.js +3 -1
- package/dist/clients/inbox/review/state.d.ts +2 -1
- package/dist/clients/inbox/review/state.js +5 -16
- package/dist/clients/inbox/tui/input.js +37 -19
- package/dist/clients/inbox/tui/panel.js +5 -31
- package/dist/clients/inbox/tui/render.d.ts +11 -0
- package/dist/clients/inbox/tui/render.js +71 -27
- package/dist/clients/inbox/tui/slots.d.ts +3 -1
- package/dist/clients/inbox/tui/slots.js +16 -12
- package/dist/clients/inbox/tui/types.d.ts +2 -7
- package/dist/clients/inbox/tui.js +2 -2
- package/dist/commands/__tests__/human.test.js +71 -114
- package/dist/commands/__tests__/node-message.test.js +14 -0
- package/dist/commands/attention.js +4 -4
- package/dist/commands/canvas-snapshot.js +1 -1
- package/dist/commands/canvas.js +1 -1
- package/dist/commands/dashboard.js +1 -1
- package/dist/commands/human/{html.d.ts → components.d.ts} +1 -1
- package/dist/commands/human/components.js +77 -0
- package/dist/commands/human/feedback.d.ts +2 -0
- package/dist/commands/human/feedback.js +108 -0
- package/dist/commands/human/prompts.d.ts +13 -5
- package/dist/commands/human/prompts.js +160 -97
- package/dist/commands/human/queue.js +57 -88
- package/dist/commands/human/shared.d.ts +2 -12
- package/dist/commands/human/shared.js +17 -11
- package/dist/commands/human.js +29 -21
- package/dist/commands/memory/origin.js +2 -2
- package/dist/commands/node/bash.js +4 -4
- package/dist/commands/node/inspect.js +3 -3
- package/dist/commands/node/lifecycle.js +1 -1
- package/dist/commands/node/message.js +2 -2
- package/dist/commands/node-worktree.js +8 -8
- package/dist/commands/pkg/browse.js +1 -1
- package/dist/commands/pkg/plugin-manage.js +129 -10
- package/dist/commands/profile/delete.js +41 -15
- package/dist/commands/profile.js +1 -1
- package/dist/commands/push.js +1 -1
- package/dist/commands/surface/node/focus.js +29 -14
- package/dist/commands/surface-edit.js +3 -3
- package/dist/commands/surface-inbox.d.ts +2 -0
- package/dist/commands/{human/inbox.js → surface-inbox.js} +14 -18
- package/dist/commands/surface.js +2 -1
- package/dist/commands/sys/doctor.js +60 -3
- package/dist/commands/sys/feedback.js +79 -25
- package/dist/commands/sys/settings.js +1 -1
- package/dist/core/__tests__/cron-broker-capacity.test.js +1 -1
- package/dist/core/__tests__/extension-abort.test.js +5 -2
- package/dist/core/__tests__/fixtures/fake-engine.d.ts +13 -2
- package/dist/core/__tests__/fixtures/fake-engine.js +47 -3
- package/dist/core/__tests__/helpers/harness.js +17 -55
- package/dist/core/__tests__/human-cancel-guard.test.js +31 -10
- package/dist/core/__tests__/human-deliver.test.js +31 -26
- package/dist/core/__tests__/human-node-not-supervised.test.js +1 -1
- package/dist/core/__tests__/plugin-page-components.test.js +157 -0
- package/dist/core/__tests__/seam/broker-crash-teardown.test.js +4 -5
- package/dist/core/__tests__/seam/dormancy-release.test.js +40 -0
- package/dist/core/__tests__/serial/flagship-lifecycle.test.js +2 -2
- package/dist/core/__tests__/serial/human-deliver-e2e.test.js +12 -6
- package/dist/core/__tests__/serial/live-mutation.test.js +1 -1
- package/dist/core/__tests__/serial/tmux-surface.test.js +4 -2
- package/dist/core/__tests__/serial/worktree.test.js +24 -198
- package/dist/core/__tests__/session-cycles.test.js +22 -0
- package/dist/core/__tests__/stop-guard.test.js +4 -4
- package/dist/core/__tests__/watchdog-abort-arms-retry.test.js +19 -4
- package/dist/core/bash-jobs.d.ts +6 -0
- package/dist/core/bash-jobs.js +10 -0
- package/dist/core/canvas/__tests__/attention.test.js +8 -5
- package/dist/core/canvas/__tests__/render-remote.test.js +5 -5
- package/dist/core/canvas/attention.js +8 -6
- package/dist/core/canvas/browse/model.d.ts +8 -2
- package/dist/core/canvas/browse/model.js +11 -4
- package/dist/core/canvas/canvas.d.ts +7 -0
- package/dist/core/canvas/canvas.js +37 -0
- package/dist/core/canvas/crons.d.ts +9 -0
- package/dist/core/canvas/crons.js +51 -0
- package/dist/core/canvas/node-order.d.ts +22 -1
- package/dist/core/canvas/node-order.js +26 -1
- package/dist/core/canvas/render-source.d.ts +5 -0
- package/dist/core/canvas/render-source.js +1 -0
- package/dist/core/canvas/types.d.ts +9 -3
- package/dist/core/command-plugins/bundle.d.ts +6 -1
- package/dist/core/command-plugins/bundle.js +26 -13
- package/dist/core/command.js +2 -1
- package/dist/core/config.d.ts +47 -1
- package/dist/core/config.js +137 -4
- package/dist/core/help.js +1 -1
- package/dist/core/human/__tests__/page-catalog.test.js +4 -0
- package/dist/core/human/__tests__/page-tickets.test.js +65 -52
- package/dist/core/human/__tests__/page.test.js +56 -98
- package/dist/core/human/__tests__/serial/inbox-core.test.js +6 -6
- package/dist/core/human/answer-text.js +3 -3
- package/dist/core/human/answer.d.ts +6 -4
- package/dist/core/human/answer.js +4 -10
- package/dist/core/human/component-docs.d.ts +11 -7
- package/dist/core/human/component-docs.js +361 -88
- package/dist/core/human/convention.d.ts +17 -3
- package/dist/core/human/convention.js +36 -5
- package/dist/core/human/feedback-companion.d.ts +20 -0
- package/dist/core/human/feedback-companion.js +98 -0
- package/dist/core/human/feedback.d.ts +65 -0
- package/dist/core/human/feedback.js +116 -0
- package/dist/core/human/page-catalog.d.ts +40 -5
- package/dist/core/human/page-catalog.js +102 -30
- package/dist/core/human/page-errors.d.ts +4 -0
- package/dist/core/human/page-errors.js +7 -0
- package/dist/core/human/page-eval.d.ts +20 -0
- package/dist/core/human/page-eval.js +123 -0
- package/dist/core/human/page-schema.d.ts +23 -191
- package/dist/core/human/page-schema.js +60 -89
- package/dist/core/human/page-synth.d.ts +1 -1
- package/dist/core/human/page-synth.js +15 -18
- package/dist/core/human/page.d.ts +12 -27
- package/dist/core/human/page.js +142 -474
- package/dist/core/human/root.d.ts +6 -2
- package/dist/core/human/root.js +12 -4
- package/dist/core/human/scan.d.ts +3 -4
- package/dist/core/human/scan.js +16 -15
- package/dist/core/human/summary.d.ts +1 -2
- package/dist/core/human/summary.js +2 -2
- package/dist/core/human/tickets.d.ts +20 -14
- package/dist/core/human/tickets.js +91 -31
- package/dist/core/human/types.d.ts +10 -2
- package/dist/core/preview-registry.js +8 -10
- package/dist/core/profiles/default-binding.d.ts +4 -0
- package/dist/core/profiles/default-binding.js +24 -0
- package/dist/core/profiles/deletion-reservation.d.ts +8 -0
- package/dist/core/profiles/deletion-reservation.js +38 -0
- package/dist/core/profiles/manifest.d.ts +3 -0
- package/dist/core/profiles/manifest.js +12 -0
- package/dist/core/profiles/select.js +2 -2
- package/dist/core/review/realize.js +3 -3
- package/dist/core/review/store.d.ts +6 -0
- package/dist/core/review/store.js +31 -0
- package/dist/core/runtime/bearings.d.ts +0 -4
- package/dist/core/runtime/bearings.js +4 -62
- package/dist/core/runtime/bin-contributions.d.ts +44 -0
- package/dist/core/runtime/bin-contributions.js +186 -0
- package/dist/core/runtime/broker/client-registry.d.ts +4 -0
- package/dist/core/runtime/broker/client-registry.js +13 -1
- package/dist/core/runtime/broker/extension-abort.d.ts +1 -1
- package/dist/core/runtime/broker/extension-abort.js +4 -2
- package/dist/core/runtime/broker/fault-retry.js +4 -0
- package/dist/core/runtime/broker/frame-dispatch.d.ts +3 -1
- package/dist/core/runtime/broker/frame-dispatch.js +5 -6
- package/dist/core/runtime/broker/read-ops.d.ts +1 -1
- package/dist/core/runtime/broker/read-ops.js +2 -2
- package/dist/core/runtime/broker/rebind.d.ts +1 -0
- package/dist/core/runtime/broker/rebind.js +6 -1
- package/dist/core/runtime/broker-extension-render.js +19 -0
- package/dist/core/runtime/broker-protocol.d.ts +14 -0
- package/dist/core/runtime/broker.d.ts +1 -1
- package/dist/core/runtime/broker.js +17 -6
- package/dist/core/runtime/front-door-env.d.ts +5 -0
- package/dist/core/runtime/front-door-env.js +16 -0
- package/dist/core/runtime/front-door.d.ts +1 -5
- package/dist/core/runtime/front-door.js +2 -5
- package/dist/core/runtime/host.d.ts +1 -1
- package/dist/core/runtime/invocation.d.ts +6 -0
- package/dist/core/runtime/invocation.js +10 -0
- package/dist/core/runtime/kickoff.js +34 -0
- package/dist/core/runtime/launch.d.ts +2 -6
- package/dist/core/runtime/node-read.js +4 -1
- package/dist/core/runtime/nodes.js +2 -0
- package/dist/core/runtime/promote.d.ts +1 -0
- package/dist/core/runtime/promote.js +3 -1
- package/dist/core/runtime/session-cycles.d.ts +6 -0
- package/dist/core/runtime/session-cycles.js +15 -1
- package/dist/core/runtime/session-visibility.d.ts +17 -8
- package/dist/core/runtime/session-visibility.js +19 -10
- package/dist/core/runtime/spawn-env.d.ts +9 -1
- package/dist/core/runtime/spawn-env.js +62 -2
- package/dist/core/runtime/stop-guard.d.ts +2 -2
- package/dist/core/runtime/stop-guard.js +2 -2
- package/dist/core/runtime/stop-signals.d.ts +1 -1
- package/dist/core/runtime/stop-signals.js +2 -2
- package/dist/core/runtime/tmux-bindings.js +1 -1
- package/dist/core/session-model/session-state.d.ts +4 -3
- package/dist/core/session-model/session-state.js +14 -1
- package/dist/core/user-settings.d.ts +21 -2
- package/dist/core/user-settings.js +32 -11
- package/dist/core/worktree.d.ts +15 -45
- package/dist/core/worktree.js +59 -261
- package/dist/daemon/api/__tests__/seam/profile-delete.test.d.ts +1 -0
- package/dist/daemon/api/__tests__/seam/profile-delete.test.js +386 -0
- package/dist/daemon/api/handlers/bash-jobs.js +1 -1
- package/dist/daemon/api/handlers/broker-ops.js +9 -5
- package/dist/daemon/api/handlers/feedback-comments.d.ts +2 -0
- package/dist/daemon/api/handlers/feedback-comments.js +207 -0
- package/dist/daemon/api/handlers/human.js +24 -20
- package/dist/daemon/api/handlers/inbox.d.ts +10 -0
- package/dist/daemon/api/handlers/inbox.js +39 -115
- package/dist/daemon/api/handlers/profiles.js +11 -29
- package/dist/daemon/api/map.d.ts +6 -1
- package/dist/daemon/api/map.js +23 -0
- package/dist/daemon/api/server.js +3 -1
- package/dist/daemon/companion-retire.d.ts +2 -0
- package/dist/daemon/companion-retire.js +33 -0
- package/dist/daemon/cron-run.js +14 -16
- package/dist/daemon/human/finish.d.ts +12 -7
- package/dist/daemon/human/finish.js +101 -38
- package/dist/daemon/human/sweep.js +5 -1
- package/dist/daemon/profile-delete.d.ts +7 -0
- package/dist/daemon/profile-delete.js +306 -0
- package/dist/daemon/reconcilers/broker-supervision.js +3 -1
- package/dist/daemon/review/deliver.js +3 -3
- package/dist/daemon/review/finish.d.ts +0 -2
- package/dist/daemon/review/finish.js +1 -29
- package/dist/pi-extensions/__tests__/canvas-bash-valve.test.js +56 -1
- package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +4 -4
- package/dist/pi-extensions/canvas-bash-valve.js +19 -5
- package/dist/pi-extensions/canvas-inbox-watcher.js +1 -1
- package/dist/pi-extensions/canvas-review-boundary.d.ts +4 -0
- package/dist/pi-extensions/canvas-review-boundary.js +18 -9
- package/dist/pi-extensions/canvas-stophook.js +4 -4
- package/dist/shared/generated-context.js +2 -2
- package/dist/types.d.ts +44 -2
- package/dist/types.js +7 -2
- package/package.json +6 -5
- package/runtime.lock.json +5 -33
- package/dist/builtin-memory/init.md +0 -38
- package/dist/builtin-memory/plan.md +0 -19
- package/dist/builtin-memory/spec.md +0 -19
- package/dist/commands/human/doc.d.ts +0 -2
- package/dist/commands/human/doc.js +0 -91
- package/dist/commands/human/html.js +0 -81
- package/dist/commands/human/inbox.d.ts +0 -2
- package/dist/core/human/__tests__/html-markdown.test.js +0 -52
- package/dist/core/human/__tests__/page-render.test.js +0 -66
- package/dist/core/human/html-markdown.d.ts +0 -3
- package/dist/core/human/html-markdown.js +0 -288
- package/dist/core/human/page-render.d.ts +0 -4
- package/dist/core/human/page-render.js +0 -105
- package/dist/pages/bundle.css +0 -1
- package/dist/pages/bundle.js +0 -1778
- package/dist/pages/comments.d.ts +0 -72
- package/dist/pages/comments.js +0 -176
- package/dist/pages/controls.d.ts +0 -98
- package/dist/pages/controls.js +0 -261
- package/dist/pages/elements/cards.d.ts +0 -28
- package/dist/pages/elements/cards.js +0 -915
- package/dist/pages/elements/chart.d.ts +0 -23
- package/dist/pages/elements/chart.js +0 -664
- package/dist/pages/elements/options.d.ts +0 -30
- package/dist/pages/elements/options.js +0 -742
- package/dist/pages/elements/pages.d.ts +0 -30
- package/dist/pages/elements/pages.js +0 -377
- package/dist/pages/elements/slot.d.ts +0 -26
- package/dist/pages/elements/slot.js +0 -112
- package/dist/pages/elements/table.d.ts +0 -36
- package/dist/pages/elements/table.js +0 -1043
- package/dist/pages/elements/text.d.ts +0 -31
- package/dist/pages/elements/text.js +0 -1175
- package/dist/pages/entry.d.ts +0 -8
- package/dist/pages/entry.js +0 -8
- package/dist/pages/host.d.ts +0 -134
- package/dist/pages/host.js +0 -165
- package/dist/pages/readonly.d.ts +0 -24
- package/dist/pages/readonly.js +0 -31
- package/dist/pages/register.d.ts +0 -2
- package/dist/pages/register.js +0 -3
- package/dist/pages/responses.d.ts +0 -37
- package/dist/pages/responses.js +0 -56
- package/dist/pages/slot-config.d.ts +0 -36
- package/dist/pages/slot-config.js +0 -50
- package/dist/pages/types.d.ts +0 -98
- package/dist/pages/types.js +0 -23
- /package/dist/{core/human/__tests__/html-markdown.test.d.ts → commands/__tests__/node-message.test.d.ts} +0 -0
- /package/dist/core/{human/__tests__/page-render.test.d.ts → __tests__/plugin-page-components.test.d.ts} +0 -0
|
@@ -13,9 +13,9 @@ You are **terminal**: you owe a final result and you reap when done — this hol
|
|
|
13
13
|
<a tight summary of the result, with pointers to files/artifacts>
|
|
14
14
|
EOF
|
|
15
15
|
|
|
16
|
-
This writes your canonical result, marks you done, and closes your window. **Stopping without `push final` is not finishing** — if you stop with open work and nothing to wait for, you will be re-prompted to finish or escalate. But **something you are waiting on counts** — a child's report,
|
|
16
|
+
This writes your canonical result, marks you done, and closes your window. **Stopping without `push final` is not finishing** — if you stop with open work and nothing to wait for, you will be re-prompted to finish or escalate. But **something you are waiting on counts** — a child's report, the user, or a wake you scheduled for unpushable polling: that is waiting, not finishing, so end your turn dormant (see *Waiting*) and the runtime brings you back. Don't go quiet, and don't finish to stop waiting.
|
|
17
17
|
|
|
18
18
|
A terminal node expecting a one-off message from a parent, controller, or sibling without a live subscription must run `crtr node wait controller -h`, declare that wait, then stop.
|
|
19
19
|
|
|
20
|
-
## Reaching the
|
|
21
|
-
You run headlessly: your turn-by-turn output isn't surfaced to the user. `crtr human
|
|
20
|
+
## Reaching the user
|
|
21
|
+
You run headlessly: your turn-by-turn output isn't surfaced to the user. `crtr human send` is the channel that reaches them — it surfaces your question and returns their answer — so route anything you need from them through it: a decision, a review, an approval (see *When blocked, want feedback, or need the user*).
|
|
@@ -59,7 +59,7 @@ Larger artifacts — specs, plans, exploration findings, test recipes — live a
|
|
|
59
59
|
|
|
60
60
|
## Your long-term memory
|
|
61
61
|
|
|
62
|
-
Separate from the roadmap (your live plan and state) you have a persistent document substrate that outlasts any roadmap: **knowledge** you consult — how to do things, how things work, facts about the
|
|
62
|
+
Separate from the roadmap (your live plan and state) you have a persistent document substrate that outlasts any roadmap: **knowledge** you consult — how to do things, how things work, facts about the user and the project — and **preferences** about how you work, each scoped user-global, project, or node-local. Your boot context surfaces the relevant docs (`<knowledge>`, `<preferences>`) as a self-describing tree; `crtr memory list` / `find` / `read` reach the rest.
|
|
63
63
|
|
|
64
64
|
**Read the matching doc before you act, not after.** When a task matches a doc — by its name or its `# read when:` line — read it (`crtr memory read <name>`) before doing the work; each doc exists to prevent a specific mistake, so consulting it afterward forfeits the point. Treat a recalled doc as background that was true when written — if it names a file or flag, verify that still holds.
|
|
65
65
|
|
|
@@ -73,7 +73,7 @@ Then advance. Reshape the phases themselves only when reality invalidates the pl
|
|
|
73
73
|
|
|
74
74
|
## Promotion and freshness
|
|
75
75
|
|
|
76
|
-
Promotion changes the node's job from hands-on execution to coordination; yielding only refreshes its context. Promote when independent units can run in parallel and the assignment is large enough that their parallel execution materially improves intelligence, productivity, or elapsed throughput after coordination and synthesis costs. Size, phase count, context exhaustion, and one helper do not qualify on their own. Yield whenever this node needs a fresh window; a topic change, redesign, or long
|
|
76
|
+
Promotion changes the node's job from hands-on execution to coordination; yielding only refreshes its context. Promote when independent units can run in parallel and the assignment is large enough that their parallel execution materially improves intelligence, productivity, or elapsed throughput after coordination and synthesis costs. Size, phase count, context exhaustion, and one helper do not qualify on their own. Yield whenever this node needs a fresh window; a topic change, redesign, or long conversation with the user calls for yield, and combines with promotion only when the remaining work separately passes the parallelism threshold. Create a bounded child with `--mode orchestrator` only when its own assignment passes the same test.
|
|
77
77
|
|
|
78
78
|
Promotion and residency are orthogonal — promotion changes your role, residency changes your lifecycle.
|
|
79
79
|
|
|
@@ -95,13 +95,13 @@ Calibrate critique and validation to risk: types and config may need neither; su
|
|
|
95
95
|
|
|
96
96
|
Delegate another check only when it can produce evidence not already available and the risk justifies its coordination cost.
|
|
97
97
|
|
|
98
|
-
## Engaging the
|
|
98
|
+
## Engaging the user
|
|
99
99
|
|
|
100
|
-
You own the goal; the
|
|
100
|
+
You own the goal; the user is a stakeholder, not your manager. They answer questions, weigh tradeoffs, and approve direction — they don't drive the work. Resolve what you can resolve yourself: read the code, spawn a scout, run a tool. Engagement is expensive and blocks you, so a whole goal should cost a handful of asks, not a stream.
|
|
101
101
|
|
|
102
|
-
Engage (`crtr human
|
|
102
|
+
Engage (`crtr human send`) when the goal is genuinely ambiguous and the codebase doesn't settle it, when you're choosing between approaches with real tradeoffs, when you've found something that changes scope or direction, when an action is irreversible or high-risk, or when finished work needs sign-off. Resolve autonomously — or delegate to an agent — anything mechanical: code review, convention compliance, plan feasibility, test verification, details within an approved scope.
|
|
103
103
|
|
|
104
|
-
**Never yield holding an unasked question.** An in-flight `crtr human
|
|
104
|
+
**Never yield holding an unasked question.** An in-flight `crtr human send` survives a yield — the ask is its own node, and the answer is pushed to your inbox and wakes your fresh window like any child's report — so an outstanding decision is no reason to hold a bloated window open. What a yield *does* tear down is anything that lives only in your head: before you yield, put every open question through `crtr human send`, and record in your roadmap what each pending answer settles, so the fresh window knows what to do with it when it arrives.
|
|
105
105
|
|
|
106
106
|
## Completion bar
|
|
107
107
|
|
|
@@ -8,7 +8,7 @@ rationale: >-
|
|
|
8
8
|
senior-engineer architecture thinking — cross-service, high-level decisions (performance, db design, patterns) worked out interactively with the user, deliberately not taking the most obvious solution. Distinct from plan, which is a crutch for model intelligence (steps a dumber model can mindlessly execute); design decides how it SHOULD be put together. Schema/key-field definitions belong; verbatim controller code does not, unless naming a template pattern others will replicate.
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
You are a design agent. Given a bounded design task — a component, subsystem, or interaction surface — you produce one design document an implementer can build from without re-deciding anything you left open. That, not emitting a document, is the bar for done. When a decision turns on judgment the user should own — a performance tradeoff, a data-model shape, which pattern to adopt — work it out with them via `crtr human
|
|
11
|
+
You are a design agent. Given a bounded design task — a component, subsystem, or interaction surface — you produce one design document an implementer can build from without re-deciding anything you left open. That, not emitting a document, is the bar for done. When a decision turns on judgment the user should own — a performance tradeoff, a data-model shape, which pattern to adopt — work it out with them via `crtr human send` rather than picking the obvious option alone, because the obvious option is usually not the right one.
|
|
12
12
|
|
|
13
13
|
Read your task for the scope, the constraints, and the interface contracts you must honor. Write the design to `$CRTR_CONTEXT_DIR/design-<subject>.md` in the standard shape: Context & constraints, Architecture (lead with a diagram, then prose), Components & responsibilities, Interfaces & contracts, Data model, Key flows, Decisions, Open risks. Three things make it a design rather than a description: every decision that closes a real option is captured in Decisions with the alternatives you rejected and why — resolve the choice, never hand the implementer a branch to pick; every interface is concrete enough that both sides can build to it without negotiating; and it stays above implementation — no function bodies, library calls, algorithm walkthroughs, or implementation ordering. If something could be pasted into source, cut it.
|
|
14
14
|
|
|
@@ -5,11 +5,11 @@ system-prompt-visibility: content
|
|
|
5
5
|
file-read-visibility: none
|
|
6
6
|
gate: {kind: plan/reviewers/security}
|
|
7
7
|
rationale: >-
|
|
8
|
-
An over-flagging reviewer flooded plans with theoretical concerns and treated private, company-owned firewalled services like hostile public boundaries. Threat model follows deployment context: only a validated reachable exploit is a finding, while an unknown boundary becomes a context-rich
|
|
8
|
+
An over-flagging reviewer flooded plans with theoretical concerns and treated private, company-owned firewalled services like hostile public boundaries. Threat model follows deployment context: only a validated reachable exploit is a finding, while an unknown boundary becomes a context-rich question to the user that does not block confirmed work.
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
You are a **security reviewer**. Given a plan, assess the security risks that would ship if it were implemented as written.
|
|
12
12
|
|
|
13
13
|
Probe the surfaces where plans introduce risk: unvalidated input crossing a trust boundary, injection surfaces (SQL, shell, path, template, deserialization), authentication and authorization gaps, sensitive-data exposure in logs, responses, or storage, and race conditions on shared state or check-then-act sequences. For each candidate, trace whether an attacker can actually reach and exploit it given the plan's design. **Flag only risks with a validated concrete exploit path** — name the actor and entry point, the step that fails, the asset affected, and the impact. Scale the threat model to the actual deployment context: a local CLI is not a public service, and traffic between company-owned firewalled services is not hostile unless evidence says otherwise. A theoretical concern, unknown boundary, or defense-in-depth wish is not a finding.
|
|
14
14
|
|
|
15
|
-
Resolve threat-model context from the plan, source, and deployment evidence first. When a material fact is still genuinely ambiguous, ask through `crtr human
|
|
15
|
+
Resolve threat-model context from the plan, source, and deployment evidence first. When a material fact is still genuinely ambiguous, ask through `crtr human send`. Explain the known facts in plain language, the exact actor/access scenario and asset that would make hardening worthwhile, and ask whether that scenario applies and whether this should be fixed. Do not assign the question a severity or make other work wait on its answer; report any confirmed verdict and the non-blocking question to your parent first, using an urgent push when it is waiting on this review, then continue or go dormant while the runtime carries the answer back.
|
|
@@ -5,7 +5,7 @@ system-prompt-visibility: content
|
|
|
5
5
|
file-read-visibility: none
|
|
6
6
|
gate: {kind: review, mode: base}
|
|
7
7
|
rationale: >-
|
|
8
|
-
Agents don't want to fail — point one at working code with “find the issues” and it hallucinates issues rather than come back empty; they also project an internet-facing threat model onto private systems and block on hypothetical risks. Reviews need evidence-backed findings, a context-rich
|
|
8
|
+
Agents don't want to fail — point one at working code with “find the issues” and it hallucinates issues rather than come back empty; they also project an internet-facing threat model onto private systems and block on hypothetical risks. Reviews need evidence-backed findings, a context-rich question to the user for an unknown threat model, and a clean result when no defect is confirmed. Isolation prevents self-audit, but review nodes also recursively delegated and promoted until one artifact accumulated dozens of reviewers; only the root review assignment may decompose, once. Unproven “this might be a bug” findings kept becoming fix work for defects nobody demonstrated (Silas, 2026-07-17), so bug claims favor traced paths while only security keeps a hard exploit-path bar.
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
You **detect; you do not adjudicate.** Report each finding accurately and rate its severity — Critical, Major, Minor, Nit — by how bad it actually is; whether a finding blocks is the owner's call, not yours, so don't approve, gate, or soften. For each, state the location, the problem, and — where it isn't obvious — the fix. Cover the whole surface you were given. When you are the sole reviewer assigned an artifact that cleanly splits into independent review surfaces large enough for parallel coverage to repay synthesis cost, promote once into a review orchestrator; otherwise yield and continue the review hands-on. A slice delegated by another reviewer remains base: finish it hands-on across a yield if needed and return its verdict to the parent for synthesis.
|
|
@@ -14,4 +14,4 @@ A **clean review is a valid and expected outcome.** You assess what is in front
|
|
|
14
14
|
|
|
15
15
|
Favor substantiated bugs over speculation. When you suspect a defect, work to trace the failing path — the input, state, or sequence the code as written mishandles — before reporting it; a "this might break" you made no attempt to confirm mostly generates fix work for defects nobody demonstrated. Code-quality findings (structure, clarity, duplication) are observable facts and carry no such burden.
|
|
16
16
|
|
|
17
|
-
A security finding needs evidence that the scenario applies: trace the reachable exploit path against the actual trust boundary and deployment context. Resolve the context from source and deployment evidence first. When a material security posture is still unknown rather than defective, ask through `crtr human
|
|
17
|
+
A security finding needs evidence that the scenario applies: trace the reachable exploit path against the actual trust boundary and deployment context. Resolve the context from source and deployment evidence first. When a material security posture is still unknown rather than defective, ask through `crtr human send` instead of rating a hypothetical risk. Give the observed facts in plain language, the actor/access scenario and asset that would make the tightening worthwhile, and ask whether that scenario applies and whether to fix it. Keep the question separate from severity-rated findings; if you have a parent, report the confirmed verdict and non-blocking question upward before awaiting the answer, using an urgent push when it is waiting on this review so it can advance on what is proved.
|
|
@@ -12,4 +12,4 @@ Choose the one decomposition axis that best covers this surface: **units** (file
|
|
|
12
12
|
|
|
13
13
|
Synthesize the child reports yourself into the final review output: one deduplicated, severity-normalized verdict, most important first. You own synthesis and evidence reconciliation; do not delegate either or start a fresh review wave after seeing the reports. The owner disposes findings and validates changed behavior. Where findings conflict, inspect the evidence and reconcile them rather than pasting both.
|
|
14
14
|
|
|
15
|
-
Require security findings to establish a reachable exploit path in the actual deployment and trust model, and steer bug findings toward substance: in synthesis, weight a traced failing path over a speculative "could break", and prune speculation no child attempted to confirm rather than forwarding it. Code-quality findings are observable facts and carry no such burden. Resolve the context from source and deployment evidence first. When a child instead uncovers a material unknown threat-model assumption, remove it from the severity-rated verdict and ask the
|
|
15
|
+
Require security findings to establish a reachable exploit path in the actual deployment and trust model, and steer bug findings toward substance: in synthesis, weight a traced failing path over a speculative "could break", and prune speculation no child attempted to confirm rather than forwarding it. Code-quality findings are observable facts and carry no such burden. Resolve the context from source and deployment evidence first. When a child instead uncovers a material unknown threat-model assumption, remove it from the severity-rated verdict and ask the user through `crtr human send`: explain the observed facts in plain language, the actor/access scenario and asset that would justify hardening, and ask whether that scenario applies and whether to fix it. Report the confirmed verdict and non-blocking question upward before awaiting the answer, using an urgent push when the parent is waiting on this review so an ambiguous security posture does not stall otherwise approved work.
|
|
@@ -10,4 +10,4 @@ Own a specification effort that genuinely needs multiple phases or independent r
|
|
|
10
10
|
|
|
11
11
|
Before shaping the roadmap, read `crtr memory read spec/roadmap` because it defines the orchestration boundaries and handoffs. Delegate design only when the specification needs a separate architectural blueprint. Delegate the final behavioral contract to a `spec/requirements` child with the canonical specification and approved design artifacts, not the originating conversation, so undocumented assumptions surface under a cold read.
|
|
12
12
|
|
|
13
|
-
The effort is done when the normative artifacts are clearly named, no implementation-changing gap remains, and downstream planning can proceed without guessing.
|
|
13
|
+
The effort is done when the normative artifacts are clearly named, no implementation-changing gap remains, and downstream planning can proceed without guessing. Review by the user follows the stakes and their involvement: explicit document approval is load-bearing when the user is co-authoring or a consequential decision remains.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
kind: knowledge
|
|
3
|
-
when-and-why-to-read: When directly received user material supports a proposed reusable principle, this knowledge should be read because
|
|
3
|
+
when-and-why-to-read: When directly received user material supports a proposed reusable principle, this knowledge should be read because review by the user keeps durable guidance grounded in their actual judgment.
|
|
4
4
|
short-form: Extract the why behind one user-derived principle, review its truth and destination, then write only what the user approves.
|
|
5
5
|
system-prompt-visibility: none
|
|
6
6
|
file-read-visibility: none
|
|
@@ -9,7 +9,7 @@ rationale: Agents have missed deeper user insight hidden in ordinary feedback, s
|
|
|
9
9
|
|
|
10
10
|
# Confirm a user-derived insight before saving it
|
|
11
11
|
|
|
12
|
-
Insight capture collects
|
|
12
|
+
Insight capture collects alpha from the user: truth from their head that is stored in no code, no document, and no model weights. It is additive — new truth entering memory, not a correction of stored state. This workflow owns reviewed extraction and writing for a qualifying episode identified by [[insights/listen]] or an active domain listener. No semantic memory is written until the user approves both the durable truth and its destination.
|
|
13
13
|
|
|
14
14
|
## Extract the why, not the behavior
|
|
15
15
|
|
|
@@ -5,7 +5,7 @@ short-form: Initialize passive insight gathering for a domain at the narrowest d
|
|
|
5
5
|
system-prompt-visibility: none
|
|
6
6
|
file-read-visibility: none
|
|
7
7
|
slash: true
|
|
8
|
-
rationale: Ordinary conversations, corrections, answers to `crtr human
|
|
8
|
+
rationale: Ordinary conversations, corrections, answers to `crtr human send`, and review comments carry unique user knowledge that agents inconsistently recognize or save; when agents do infer a deeper principle, they have written it without first letting the user correct the extrapolation.
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
# /insights:init — begin domain listening
|
|
@@ -20,7 +20,7 @@ If `$ARGUMENTS` contains `--active`, follow the **active mode** steps below. Oth
|
|
|
20
20
|
|
|
21
21
|
## Establish the topic and scope
|
|
22
22
|
|
|
23
|
-
Turn the request into a short path-safe topic slug and a compact domain boundary that preserves the user's meaning rather than reducing it to a single keyword. If the request is empty or too vague to distinguish relevant from unrelated information, ask one focused question through `crtr human
|
|
23
|
+
Turn the request into a short path-safe topic slug and a compact domain boundary that preserves the user's meaning rather than reducing it to a single keyword. If the request is empty or too vague to distinguish relevant from unrelated information, ask one focused question through `crtr human send`.
|
|
24
24
|
|
|
25
25
|
Choose the narrowest durable scope that reaches every future conversation where this domain matters:
|
|
26
26
|
|
|
@@ -28,7 +28,7 @@ Choose the narrowest durable scope that reaches every future conversation where
|
|
|
28
28
|
- profile when it spans the selected profile's projects but should not follow the user elsewhere; or
|
|
29
29
|
- user when it concerns the person, a market, a craft, or a domain that crosses workspaces.
|
|
30
30
|
|
|
31
|
-
Infer the scope from the request and current workspace. Ask through `crtr human
|
|
31
|
+
Infer the scope from the request and current workspace. Ask through `crtr human send` only when more than one scope is genuinely plausible, and settle scope before writing anything. Never use node scope for an ongoing listener.
|
|
32
32
|
|
|
33
33
|
Search the chosen scope before creating. If `insights/<topic>` already represents the same domain, refine that listener rather than creating an overlapping directory.
|
|
34
34
|
|
|
@@ -16,7 +16,7 @@ Open this dir whenever a task turns on understanding the runtime itself or chang
|
|
|
16
16
|
- **storage-tiers** — where every kind of state lives: the two tiers (scope root and canvas home) and their durability/ownership contracts.
|
|
17
17
|
- **memory-loading** — the memory load model: the two hooks (boot catalog, file-read), the four-rung ladder, gates, applies-to/read-when routing, boot-render ordering, and store mounting/precedence — read when diagnosing why a doc did or didn't load.
|
|
18
18
|
- **agent-shaping** — the when-to-use-which layer over the four dials that shape a node: kinds (the builtin roster, sub-kinds, and custom personas), modes (base vs orchestrator), profiles, and the memory tiers (node/profile/project/user/builtin).
|
|
19
|
-
- **plugins** — authoring a crtr plugin: the plugin.json manifest, directory layout, scopes, install mechanics, versioning,
|
|
19
|
+
- **plugins** — authoring a crtr plugin: the plugin.json manifest, directory layout, scopes, install mechanics, versioning, command-capable plugins (contributing top-level CLI commands through commands.json plus an exec or HTTP transport), and bare binaries a plugin or scope puts on every node's PATH.
|
|
20
20
|
- **marketplaces** — authoring a crtr marketplace: the marketplace.json index, local-link and remote-Git plugin sources, auto-bump CI, dual-publishing.
|
|
21
21
|
- **examples/** — worked compositions of the primitives into complete systems (the analogue of pi's `examples/` dir), e.g. the iMessage assistant node.
|
|
22
22
|
|
|
@@ -26,7 +26,7 @@ Each doc sets both rungs explicitly; there is no kind-based default. Usually one
|
|
|
26
26
|
- `preview` — name + the `when-and-why-to-read` routing line, rendered verbatim. The heart of progressive disclosure: one sentence that lets an agent decide whether to spend the read.
|
|
27
27
|
- `content` — the full body inlined. Reserved for always-relevant docs that are either a bullet's worth of text or a wholly-important operating guide (the root INDEX shape below).
|
|
28
28
|
|
|
29
|
-
`short-form` is **not** a rung and never enters agent context — it exists for
|
|
29
|
+
`short-form` is **not** a rung and never enters agent context — it exists for the user browsing `crtr memory list`. Disclosure is name → routing line → whole thing; there is deliberately no "just the summary" level, because agents satisfice on abbreviations and never read the rest.
|
|
30
30
|
|
|
31
31
|
## Gates and read-when
|
|
32
32
|
|
|
@@ -18,10 +18,10 @@ The **daemon** (`crtrd`) is the sole owner of canvas persistent state: it is the
|
|
|
18
18
|
|
|
19
19
|
- Match `--kind` to the work (`explore spec design plan developer review general`, plus any custom persona). See `node new -h`.
|
|
20
20
|
- An orchestrator fans **independent** units out concurrently. Serialize only true dependencies; never let two live children edit the same files.
|
|
21
|
-
- `--root` spawns an independent node you neither manage nor are woken by (e.g. one
|
|
21
|
+
- `--root` spawns an independent node you neither manage nor are woken by (e.g. one the user will drive).
|
|
22
22
|
- Once you delegate a unit, don't also run it yourself — you'll be woken when it finishes.
|
|
23
23
|
|
|
24
|
-
Navigate/steer: `surface node focus` (put an attach viewer for a node in your pane), `surface attach` (connect to a node's existing broker), `surface node cycle` (DFS-walk neighbors), `surface node id` (copy the current node id), `node message send` (direct-message any node at a wake tier, reviving a dormant target), `node subscription add`/`node subscription remove` (wire edges spawn didn't create). Survey with `canvas dashboard` (ASCII tree), `canvas browse` (interactive navigator), `node inspect list/show`, `canvas attention` (who's blocked on
|
|
24
|
+
Navigate/steer: `surface node focus` (put an attach viewer for a node in your pane), `surface attach` (connect to a node's existing broker), `surface node cycle` (DFS-walk neighbors), `surface node id` (copy the current node id), `node message send` (direct-message any node at a wake tier, reviving a dormant target), `node subscription add`/`node subscription remove` (wire edges spawn didn't create). Survey with `canvas dashboard` (ASCII tree), `canvas browse` (interactive navigator), `node inspect list/show`, `canvas attention` (who's blocked on the user).
|
|
25
25
|
|
|
26
26
|
## The push/feed spine
|
|
27
27
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
kind: knowledge
|
|
3
3
|
when-and-why-to-read: When creating a crtr plugin, packaging memory docs for distribution, adding top-level CLI commands via a command manifest, or debugging install/resolution, this knowledge should be read so installs resolve predictably across scopes and command surfaces do not fail from manifest drift or protocol mistakes.
|
|
4
|
-
short-form: How to author a crtr plugin — plugin.json manifest, directory layout, scopes, install mechanics, versioning,
|
|
4
|
+
short-form: How to author a crtr plugin — plugin.json manifest, directory layout, scopes, install mechanics, versioning, command-capable plugins (commands.json plus an exec or HTTP transport), bare binaries (`bin`) a plugin or scope puts on every node's PATH, and advisory external executable requirements (`requires`). Use when creating a plugin, packaging memory docs, contributing commands or executables, or debugging install/resolution.
|
|
5
5
|
system-prompt-visibility: name
|
|
6
6
|
file-read-visibility: none
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Authoring crtr plugins
|
|
10
10
|
|
|
11
|
-
A **plugin** is a directory shipping substrate docs (knowledge and preferences) and other artifact types like `rules/` and `agents/`. Plugins are how you package that content for sharing across machines, projects, and people.
|
|
11
|
+
A **plugin** is a directory shipping substrate docs (knowledge and preferences) and other artifact types like `rules/` and `agents/`. Plugins are how you package that content for sharing across machines, projects, and people. The user can inspect marketplaces and their plugin capability surfaces in `crtr pkg browse`; agents use the scriptable `crtr pkg market browse` and `crtr pkg plugin list` leaves.
|
|
12
12
|
|
|
13
13
|
Audience: LLM agents creating or maintaining a crtr plugin.
|
|
14
14
|
|
|
@@ -64,6 +64,9 @@ The `<plugin-name>` directory IS the plugin. The manifest's `name` field must ma
|
|
|
64
64
|
| `owner` | optional | Author info. |
|
|
65
65
|
| `commands` | optional | Plugin-root-relative path to a `commands.json` command manifest. It must appear with `transport`; together they make the plugin contribute `crtr` commands — see [Plugin commands](#plugin-commands). |
|
|
66
66
|
| `transport` | optional | Required exactly when `commands` is present. `{ "kind": "exec", "executable": "bin/cmd.js" }` runs executable leaves; a passthrough-only exec manifest may omit `executable`. `{ "kind": "http", "endpoint": "https://…", "authEnv": "TOKEN_NAME" }` calls a remote HTTP command surface. Archive-installed plugins also carry crouter-synthesized `bundle` provenance; authors do not add it. |
|
|
67
|
+
| `page_components` | optional | Page-component contributions: an array of the same registrations a scope `config.json` `page_components` block carries. See [Plugin page components](#plugin-page-components). |
|
|
68
|
+
| `bin` | optional | Bare-callable executables the plugin ships, as `{"<bare-name>": "<plugin-relative path>"}`. Each becomes callable by bare name from any node's bash — no `crtr` command, no protocol. See [Bare binaries on the node PATH](#bare-binaries-on-the-node-path). |
|
|
69
|
+
| `requires` | optional | Advisory external executables the plugin needs, as `{"<bare-name>": "one-line install hint"}`. crouter never installs them or disables the plugin when absent: install warns and Doctor reports the hint. See [External executable requirements](#external-executable-requirements). |
|
|
67
70
|
| `kinds` | optional | Kind-registry contributions, keyed by full kind string — the same rule a scope `config.json` `kinds` block follows: each entry is any subset of `KindConfig` fields (`whenToUse`, `model`, `orchestratorModel`, `tools`, `extensions`, `availableTo`). It field-merges over a kind a lower layer already defines — `whenToUse` included, so overriding just the spawn guidance never strips the kind's model tier — and defines a new kind when none does (then `whenToUse` is required). See [Plugin kinds](#plugin-kinds). |
|
|
68
71
|
|
|
69
72
|
## Plugin kinds
|
|
@@ -74,6 +77,14 @@ A plugin can ship a complete persona kind: declare the registry entry in the man
|
|
|
74
77
|
|
|
75
78
|
For archive plugins the declaration lives in the archive's `bundle.json` — `{"bundleVersion": 1, "kinds": {…}}` — and the installer copies the block into the synthesized manifest. Install validates the block strictly (an invalid entry fails the install with per-entry reasons); the read side drops invalid entries silently, so the loud gate is install time.
|
|
76
79
|
|
|
80
|
+
## Plugin page components
|
|
81
|
+
|
|
82
|
+
A plugin can make product page components authorable: declare them in the manifest's `page_components` array, each entry a kind string or `{kind, description?, useWhen?, doc?, display?}` — the registration `crtr human components` renders and page validation checks authored components against. The product owning the renderer ships the catalog, so installing or updating the plugin adds or changes a component with no image roll, and removing it retires the component.
|
|
83
|
+
|
|
84
|
+
`resolvePageComponents` concatenates the user scope's own `config.json` entries with every enabled user-scope plugin's contributions, plugins name-sorted. Unlike `kinds` there is no precedence: two sources registering one kind — or two kinds deriving one JSX tag — is an error naming both sources, because a component bound to a renderer nobody chose is worse than a failed read. User scope only, so the daemon, CLI, and inbox TUI resolve one identical catalog regardless of cwd.
|
|
85
|
+
|
|
86
|
+
For archive plugins the declaration lives in the archive's `bundle.json` — `{"bundleVersion": 1, "page_components": […]}` — and the installer copies the block into the synthesized manifest. Install validates it strictly; a malformed block fails the install rather than breaking page authoring later.
|
|
87
|
+
|
|
77
88
|
## Scopes
|
|
78
89
|
|
|
79
90
|
A plugin can live in either scope:
|
|
@@ -255,12 +266,58 @@ crtr validates command manifests statically; it never executes an exec binary to
|
|
|
255
266
|
|
|
256
267
|
Core always wins a path collision. A cross-plugin collision drops every claimant with a `command_collision` issue. A fixed manifest goes live on the next invocation; there is nothing to restart.
|
|
257
268
|
|
|
269
|
+
## External executable requirements
|
|
270
|
+
|
|
271
|
+
A plugin can name a program it expects another install to provide, without making that program part of the plugin or asking crouter to install it. Use this for a wrapper that dispatches to a separately installed CLI:
|
|
272
|
+
|
|
273
|
+
```json
|
|
274
|
+
{
|
|
275
|
+
"name": "dev",
|
|
276
|
+
"requires": { "grove": "Install Grove, then register this repo with `grove register`." }
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
Each key is the same safe bare-name grammar as `bin`: `[A-Za-z0-9][A-Za-z0-9._-]{0,63}`. Each value is one non-empty line an agent can act on. crouter looks it up on the same PATH a node's bash receives, including bare binaries another enabled plugin contributes. A missing program is advisory: install succeeds and leaves the plugin enabled, then reports the executable and hint as a warning. `crtr sys doctor` emits one `requires:<name>` check per enabled plugin declaration; its pass names the plugin and resolved absolute path, and its failure carries the hint as remediation.
|
|
281
|
+
|
|
282
|
+
A malformed `requires` block is different: invalid names, non-strings, empty hints, and multi-line hints fail source-plugin install and update, because the manifest itself is defective. `requires` belongs only in a plugin manifest, never scope `config.json`.
|
|
283
|
+
|
|
284
|
+
## Bare binaries on the node PATH
|
|
285
|
+
|
|
286
|
+
A plugin can also ship plain executables that an agent calls by bare name — `mytool --flag`, exactly like `jq` or `rg`. These are not `crtr` commands: they take ordinary argv, write ordinary stdout, and speak none of the exec-command JSON protocol. Reach for this when the thing you are shipping is simply a program the agent should be able to run; reach for [Plugin commands](#plugin-commands) when it should appear in the `crtr` tree with native help, parsing, and rendered output.
|
|
287
|
+
|
|
288
|
+
Declare them in `plugin.json`:
|
|
289
|
+
|
|
290
|
+
```json
|
|
291
|
+
{
|
|
292
|
+
"name": "deploy-tools",
|
|
293
|
+
"version": "0.1.0",
|
|
294
|
+
"description": "...",
|
|
295
|
+
"bin": { "deployctl": "bin/deployctl", "envdiff": "bin/envdiff.py" }
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Each value is plugin-root-relative. When crouter resolves the effective set, it validates that the target is inside the plugin root, is a regular file, and carries the POSIX exec bit. Each key is the bare name a node's bash sees: `[A-Za-z0-9][A-Za-z0-9._-]{0,63}`, and never `crtr` or `crtrd`, which crouter owns.
|
|
300
|
+
|
|
301
|
+
A user or project scope declares the same block in its own `config.json`. A project scope's paths resolve against the **project directory** — where a repo's own tools actually live — and a user scope's against `~/.crouter/`:
|
|
302
|
+
|
|
303
|
+
```json
|
|
304
|
+
{ "bin": { "repoctl": "tools/repoctl" } }
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
crouter resolves the effective set for each node's cwd and profile, validates containment at that time, symlinks exactly those names into a shim directory it owns, and prepends that directory to every broker child's `PATH` — the host `PATH` stays intact behind it, so a contribution shadows a same-named host program and nothing else changes. Nothing is copied, wrapped, or evaluated: the shim is a symlink to the file you shipped, and the binary runs with the same authority the agent's bash tool already has. Treat a contributed binary as trusted local code, because that is exactly what it is.
|
|
308
|
+
|
|
309
|
+
Precedence ascends the same way the rest of the config layers: user-scope plugins, then user `config.json`, then each project root from farthest to nearest (that root's plugins, then that root's `config.json`). So a project contribution outranks a user one, and a scope's own config outranks its plugins. Disabling or removing a plugin removes its bare commands with it.
|
|
310
|
+
|
|
311
|
+
Two contributors at the same precedence claiming one name is a collision, not a precedence question: crouter installs neither, and `crtr sys doctor` reports the name and both claimants. Rename one of them, or claim the name explicitly at a higher layer.
|
|
312
|
+
|
|
258
313
|
## Validation
|
|
259
314
|
|
|
260
315
|
`crtr sys doctor` checks each plugin's manifest:
|
|
261
316
|
- Manifest exists and is valid JSON.
|
|
262
317
|
- Manifest `name` matches the directory name.
|
|
263
318
|
- When the plugin declares `commands`, its command manifest and transport declaration are validated statically; an exec executable is never executed during validation — see [Plugin commands](#plugin-commands).
|
|
319
|
+
- When the plugin (or a scope `config.json`) declares `bin`, each declaration is reported as a `bin:<name>` check: a pass names the contributor and the resolved target, while a fail names an unsafe/reserved name, malformed target declaration, missing/non-executable/root-escaping target, or same-precedence collision. Contributed binaries are never executed during validation. Plugin install and source-plugin updates fail loudly on an unsafe or reserved bare name.
|
|
320
|
+
- When an enabled plugin declares `requires`, each `requires:<name>` check names the plugin and resolved executable path on pass, or carries its install hint as remediation on fail. The executable is never run; a malformed declaration fails source-plugin install and update, while an absent executable remains advisory.
|
|
264
321
|
|
|
265
322
|
`crtr memory lint` checks the docs under `memory/`: frontmatter parses, valid `kind`, both visibility rungs set. Run `crtr memory write -h` for the authoring + routing guide. Other sibling artifact dirs (`rules/`, `agents/`, `hooks/`) are validated by their respective specs as those land.
|
|
266
323
|
|
|
@@ -22,7 +22,7 @@ User-wide content with no cwd dimension also belongs here: `~/.crouter/profile-d
|
|
|
22
22
|
|
|
23
23
|
## 2. Canvas home — node-graph runtime state, node artifacts, and bounded diagnostics
|
|
24
24
|
|
|
25
|
-
`~/.crouter/canvas/` (overridable with `CRTR_HOME`) is the cwd-agnostic node-graph home. `canvas.db` is the SQLite WAL topology store for nodes and edges, including durable tmux-pane focus. `nodes/<node_id>/` owns `meta.json`, `context/`, `reports/`, `messages/`, `inbox.jsonl`, `transcript.jsonl`, `session.ptr`, and `job/` state. Human ticket files (`page.json`, `page.
|
|
25
|
+
`~/.crouter/canvas/` (overridable with `CRTR_HOME`) is the cwd-agnostic node-graph home. `canvas.db` is the SQLite WAL topology store for nodes and edges, including durable tmux-pane focus. `nodes/<node_id>/` owns `meta.json`, `context/`, `reports/`, `messages/`, `inbox.jsonl`, `transcript.jsonl`, `session.ptr`, and `job/` state. Human ticket files (`page.json`, `page.tsx`, `page.js`, optional `reply-route.json`, `response.json`, `review.json`, and `branch-point.jsonl`) live under `nodes/`, the single derived ticket root. Reply-bearing tickets target the bridge recorded in `reply-route.json`; standalone pages have no bridge.
|
|
26
26
|
|
|
27
27
|
Specifications and plans are ordinary node-context artifacts. They share the node's lifetime and are removed when that node is reaped.
|
|
28
28
|
|
|
@@ -39,4 +39,6 @@ Canonical diagnostics are bounded NDJSON `EventEnvelope` streams. The synchronou
|
|
|
39
39
|
|
|
40
40
|
`<crtrHome>/crtrd.err` and `nodes/<node_id>/job/broker.log` are raw process/stdout-stderr residue for runtime warnings, third-party output, and last-resort evidence when canonical emission cannot complete. They are not canonical streams, are not parsed as event envelopes, and do not become JSON event output.
|
|
41
41
|
|
|
42
|
+
`<crtrHome>/bin-shims/<address>/` holds the symlink shims for bare-binary contributions (`bin` in a plugin manifest or a scope `config.json`), one content-addressed directory per effective set, prepended to every broker child's PATH. It is derived runtime state: the contributed executables themselves live with their contributor under the scope root, and a shim directory is re-derived on demand.
|
|
43
|
+
|
|
42
44
|
The contributor rule: durable user or repo content → scope root; node-graph state, node-authored deliverables, human tickets, current state, canonical streams, and raw residue → canvas home. Runtime install generations under `~/.crouter/runtime/generations/` are sealed install machinery, not a storage tier or an agent workspace.
|
|
@@ -5,7 +5,7 @@ short-form: Orchestrate a specification only for worthwhile parallel work, using
|
|
|
5
5
|
system-prompt-visibility: preview
|
|
6
6
|
file-read-visibility: none
|
|
7
7
|
gate: {kind: spec}
|
|
8
|
-
rationale: The prior roadmap required every large specification to follow exact stages, fresh-window yields, fixed delegation, and
|
|
8
|
+
rationale: The prior roadmap required every large specification to follow exact stages, fresh-window yields, fixed delegation, and user approval gates; the resulting process treated ceremony as the quality bar instead of the clarity of the finished contract.
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
# Orchestrating a specification
|
|
@@ -26,7 +26,7 @@ The dependency is shape → optional design → requirements. A phase exists bec
|
|
|
26
26
|
|
|
27
27
|
An independent reader exposes omissions; it does not decide product intent on the spec owner's behalf. When design or requirements finds an implementation-changing gap, bring the owning specification or design artifact current, then rerun only the affected handoff. The final requirements artifact contains the complete resolved contract rather than a review log or a list of inherited assumptions.
|
|
28
28
|
|
|
29
|
-
## Match
|
|
29
|
+
## Match the user's involvement to the decision
|
|
30
30
|
|
|
31
31
|
Use focused questions for consequential uncertainty and explicit document approval when the user is co-authoring or the artifact settles a high-impact product or architectural decision. Otherwise, present the concrete interpretation or largest remaining risks and keep moving. Reviewer silence and repeated approval loops are not completion criteria; settled intent and a usable contract are.
|
|
32
32
|
|
|
@@ -32,7 +32,7 @@ Raise that bar where the repo warrants one on its own evidence: a published libr
|
|
|
32
32
|
|
|
33
33
|
## 3. Confirm it with the owner
|
|
34
34
|
|
|
35
|
-
Put the draft to the owner through `crtr human
|
|
35
|
+
Put the draft to the owner through `crtr human send`, as one question answerable with "yes" or a short edit. Carry exactly three things: one line of evidence about what the suite looks like today, the specific decision you are blocked on, and the stance verbatim as you would store it. Ask about the general rule rather than only the change in front of you, so the answer keeps settling later work — once per repo, not once per change.
|
|
36
36
|
|
|
37
37
|
## 4. Store it as that repo's `testing-stance`
|
|
38
38
|
|
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
// the already-scanned job list, never touches disk itself (that's
|
|
4
4
|
// activeBackgroundBashJobs' job, in core/bash-jobs.ts). Enter on that row opens
|
|
5
5
|
// the Inspector's `jobs` section, which owns the drill-in rendering.
|
|
6
|
-
import { formatBashElapsed } from '../../../core/bash-jobs.js';
|
|
7
|
-
/**
|
|
6
|
+
import { bashJobCommandLine, formatBashElapsed } from '../../../core/bash-jobs.js';
|
|
7
|
+
/** The job's real command line (past its injected env preamble), capped to `cap` columns. A
|
|
8
8
|
* shell one-liner is cut on a word boundary when there is one near the cap, so
|
|
9
9
|
* the cell ends on a readable token instead of mid-`$((`. */
|
|
10
10
|
function cmdCell(command, cap) {
|
|
11
|
-
const oneLine = command
|
|
11
|
+
const oneLine = bashJobCommandLine(command);
|
|
12
12
|
if (oneLine.length <= cap)
|
|
13
13
|
return oneLine;
|
|
14
14
|
const cut = oneLine.slice(0, Math.max(1, cap - 1));
|
|
@@ -51,6 +51,13 @@ export interface ChatViewOptions {
|
|
|
51
51
|
* Absent → the user's `condensed_history` config setting, itself defaulting
|
|
52
52
|
* to `none` (cycle dividers only). */
|
|
53
53
|
condensedHistory?: CondensedHistoryMode;
|
|
54
|
+
/** Render an inline page sent by THIS node as a durable transcript block,
|
|
55
|
+
* anchored after the `human send` that raised it. Local attach only: a remote
|
|
56
|
+
* viewer cannot read the ticket directory the block renders from. */
|
|
57
|
+
inlinePageBlocks?: boolean;
|
|
58
|
+
/** How the person opens their inbox on this surface, resolved lazily because
|
|
59
|
+
* bindings are resolved after ChatView is constructed. */
|
|
60
|
+
pageOpenHint?: () => string;
|
|
54
61
|
/** Pre-colored banner lines pinned as the FIRST child of the chat container,
|
|
55
62
|
* above history (the crouton wordmark). Sits at the very top of the transcript
|
|
56
63
|
* and scrolls up into scrollback as the chat grows. Absent → no banner. */
|
|
@@ -73,6 +80,11 @@ export declare class ChatView {
|
|
|
73
80
|
* a nested container while condensed history is being built, so the same
|
|
74
81
|
* message-rendering path serves both regions. */
|
|
75
82
|
private appendTarget;
|
|
83
|
+
/** Inline page blocks placed in this transcript, by page id — one block per
|
|
84
|
+
* page, so a `--replace` revision refreshes the block already on screen. */
|
|
85
|
+
private readonly pageBlocks;
|
|
86
|
+
private readonly inlinePageBlocks;
|
|
87
|
+
private readonly pageOpenHint;
|
|
76
88
|
/** Trailing cycles kept at full fidelity (config `live_cycles`). */
|
|
77
89
|
private readonly liveCycles;
|
|
78
90
|
/** Messages kept from a condensed cycle (config `condensed_history`). */
|
|
@@ -223,7 +235,10 @@ export declare class ChatView {
|
|
|
223
235
|
fullOutputPath?: string;
|
|
224
236
|
}): void;
|
|
225
237
|
private addMessageToChat;
|
|
226
|
-
/** Render an assistant reply plus its initially-hidden boundary separator.
|
|
238
|
+
/** Render an assistant reply plus its initially-hidden boundary separator.
|
|
239
|
+
* A turn that ended on its own abort is rendered as the interrupt it is,
|
|
240
|
+
* matching the live seam above, so re-reading the transcript later never
|
|
241
|
+
* turns a healthy interrupt into a red `Error:` line. */
|
|
227
242
|
private appendAssistantMessage;
|
|
228
243
|
/** Add a separator in transcript order now; it renders only after a following
|
|
229
244
|
* tool settles in the folded view. */
|
|
@@ -271,6 +286,16 @@ export declare class ChatView {
|
|
|
271
286
|
private chatChildCount;
|
|
272
287
|
/** Clear all chat content. */
|
|
273
288
|
private resetChat;
|
|
289
|
+
/** Place the transcript block for an inline page a `human send` just raised.
|
|
290
|
+
* The block is a plain history child, NOT a tool-group member: collapsing the
|
|
291
|
+
* tool group folds the command away and leaves the page itself on screen, the
|
|
292
|
+
* way assistant prose stays. Condensed history is skipped deliberately — old
|
|
293
|
+
* cycles keep only prose and cycle seams. */
|
|
294
|
+
private maybeAppendPageBlock;
|
|
295
|
+
/** Re-read every placed page from disk. Driven by the viewer's ticket-activity
|
|
296
|
+
* watcher, so an answer, a cancellation, or a `--replace` revision lands on
|
|
297
|
+
* the block already anchored in the transcript. */
|
|
298
|
+
refreshPageBlocks(): void;
|
|
274
299
|
private makeLoader;
|
|
275
300
|
/** Let a self-updating history child invalidate only its own cached lines. */
|
|
276
301
|
private componentTui;
|
|
@@ -24,8 +24,9 @@ import { Container, Loader, Spacer, Text } from '@earendil-works/pi-tui';
|
|
|
24
24
|
import { AssistantMessageComponent, BashExecutionComponent, BranchSummaryMessageComponent, CompactionSummaryMessageComponent, CustomMessageComponent, parseSkillBlock, SkillInvocationMessageComponent, ToolExecutionComponent, UserMessageComponent, } from '@earendil-works/pi-coding-agent';
|
|
25
25
|
import { attachMarkdownTheme } from '../config.js';
|
|
26
26
|
import { ContextMessageComponent } from './context-message.js';
|
|
27
|
+
import { detectInlinePageResult, PageBlockComponent } from './page-block.js';
|
|
27
28
|
import { CRTR_OUTPUT_CUSTOM_TYPE, CrtrOutputMessageComponent, createCrtrBashToolDefinition, } from './crtr-output.js';
|
|
28
|
-
import { CRTR_CYCLE_DIVIDER_CUSTOM_TYPE } from '../../../core/runtime/session-cycles.js';
|
|
29
|
+
import { CRTR_CYCLE_DIVIDER_CUSTOM_TYPE, endedByAbort } from '../../../core/runtime/session-cycles.js';
|
|
29
30
|
import { generatedContextExpandedBody, generatedContextPresentation, isRuntimeRestartContinuation, } from '../../../shared/generated-context.js';
|
|
30
31
|
import { assistantVisibleText, isTrueUserMessage, } from '../../../shared/tool-groups.js';
|
|
31
32
|
import { transformDiagramFences } from './diagram.js';
|
|
@@ -266,6 +267,11 @@ export class ChatView {
|
|
|
266
267
|
* a nested container while condensed history is being built, so the same
|
|
267
268
|
* message-rendering path serves both regions. */
|
|
268
269
|
appendTarget = this.historyContainer;
|
|
270
|
+
/** Inline page blocks placed in this transcript, by page id — one block per
|
|
271
|
+
* page, so a `--replace` revision refreshes the block already on screen. */
|
|
272
|
+
pageBlocks = new Map();
|
|
273
|
+
inlinePageBlocks;
|
|
274
|
+
pageOpenHint;
|
|
269
275
|
/** Trailing cycles kept at full fidelity (config `live_cycles`). */
|
|
270
276
|
liveCycles;
|
|
271
277
|
/** Messages kept from a condensed cycle (config `condensed_history`). */
|
|
@@ -379,6 +385,8 @@ export class ChatView {
|
|
|
379
385
|
this.condensedHistory = opts.condensedHistory ?? readCondensedHistory();
|
|
380
386
|
this.onFooterEvent = opts.onFooterEvent;
|
|
381
387
|
this.onActivityChange = opts.onActivityChange;
|
|
388
|
+
this.inlinePageBlocks = opts.inlinePageBlocks ?? false;
|
|
389
|
+
this.pageOpenHint = opts.pageOpenHint ?? (() => 'crtr human list');
|
|
382
390
|
this.recapPalette = opts.palette ?? defaultAttachPalette;
|
|
383
391
|
this.spinnerStyle = this.recapPalette.active;
|
|
384
392
|
this.dimStyle = this.recapPalette.muted;
|
|
@@ -482,9 +490,7 @@ export class ChatView {
|
|
|
482
490
|
const hasProse = assistantVisibleText(message).trim() !== '';
|
|
483
491
|
const toolCalls = this.assistantToolCalls(message);
|
|
484
492
|
const endedWithFailure = message.stopReason === 'aborted' || message.stopReason === 'error';
|
|
485
|
-
const terminalErrorMessage = message.
|
|
486
|
-
? 'Interrupted'
|
|
487
|
-
: (message.errorMessage ?? 'Error');
|
|
493
|
+
const terminalErrorMessage = endedByAbort(message) ? 'Interrupted' : (message.errorMessage ?? 'Error');
|
|
488
494
|
// A terminal assistant failure remains visible as its own boundary. Settle
|
|
489
495
|
// any interrupted calls so the completed span before it can still recap.
|
|
490
496
|
if (endedWithFailure) {
|
|
@@ -539,6 +545,7 @@ export class ChatView {
|
|
|
539
545
|
this.historyContainer.markDirty(component);
|
|
540
546
|
this.settleGroupTool(component, message, message.isError === true);
|
|
541
547
|
renderedPendingTools.delete(message.toolCallId);
|
|
548
|
+
this.maybeAppendPageBlock(message);
|
|
542
549
|
}
|
|
543
550
|
}
|
|
544
551
|
else {
|
|
@@ -829,15 +836,21 @@ export class ChatView {
|
|
|
829
836
|
if (this.streamingComponent) {
|
|
830
837
|
const stopReason = event.message.stopReason;
|
|
831
838
|
let errorMessage = event.message.errorMessage;
|
|
832
|
-
// An aborted turn may be a user interrupt or a lifecycle interruption
|
|
833
|
-
//
|
|
834
|
-
//
|
|
835
|
-
|
|
839
|
+
// An aborted turn may be a user interrupt or a lifecycle interruption
|
|
840
|
+
// (a refresh-yield aborts its own turn). Providers spell it several
|
|
841
|
+
// ways — including `stopReason: 'error'` carrying a bare AbortError,
|
|
842
|
+
// which would otherwise render as a red `Error: This operation was
|
|
843
|
+
// aborted` for a perfectly healthy yield — so override it outright
|
|
844
|
+
// with one plain, human label.
|
|
845
|
+
if (endedByAbort(event.message)) {
|
|
836
846
|
errorMessage = 'Interrupted';
|
|
837
847
|
// Surface the abort on the assistant bubble itself, mirroring pi
|
|
838
848
|
// (interactive-mode.js:2280 sets streamingMessage.errorMessage before
|
|
839
|
-
// updateContent) so the rendered message shows the annotation.
|
|
849
|
+
// updateContent) so the rendered message shows the annotation. The
|
|
850
|
+
// stopReason moves with it: pi's component reserves its red
|
|
851
|
+
// `Error: …` line for stopReason 'error', and an abort is not one.
|
|
840
852
|
event.message.errorMessage = errorMessage;
|
|
853
|
+
event.message.stopReason = 'aborted';
|
|
841
854
|
}
|
|
842
855
|
this.streamingComponent.updateContent(event.message);
|
|
843
856
|
if (stopReason === 'aborted' || stopReason === 'error') {
|
|
@@ -905,6 +918,7 @@ export class ChatView {
|
|
|
905
918
|
this.settleGroupTool(component, result, event.isError);
|
|
906
919
|
this.applyToolDisplay();
|
|
907
920
|
this.historyContainer.markDirty(component);
|
|
921
|
+
this.maybeAppendPageBlock(result);
|
|
908
922
|
}
|
|
909
923
|
break;
|
|
910
924
|
}
|
|
@@ -1141,10 +1155,16 @@ export class ChatView {
|
|
|
1141
1155
|
// -------------------------------------------------------------------------
|
|
1142
1156
|
// Helpers
|
|
1143
1157
|
// -------------------------------------------------------------------------
|
|
1144
|
-
/** Render an assistant reply plus its initially-hidden boundary separator.
|
|
1158
|
+
/** Render an assistant reply plus its initially-hidden boundary separator.
|
|
1159
|
+
* A turn that ended on its own abort is rendered as the interrupt it is,
|
|
1160
|
+
* matching the live seam above, so re-reading the transcript later never
|
|
1161
|
+
* turns a healthy interrupt into a red `Error:` line. */
|
|
1145
1162
|
appendAssistantMessage(message, groupMember = false) {
|
|
1146
1163
|
const component = new ViewerAssistantMessageComponent(undefined, this.hideThinking, attachMarkdownTheme(), this.hiddenThinkingLabel, this.markdownTransformers);
|
|
1147
|
-
|
|
1164
|
+
const rendered = endedByAbort(message)
|
|
1165
|
+
? { ...message, stopReason: 'aborted', errorMessage: 'Interrupted' }
|
|
1166
|
+
: message;
|
|
1167
|
+
component.updateContent(rendered);
|
|
1148
1168
|
this.appendAssistantPart(component, groupMember);
|
|
1149
1169
|
this.registerCopyBlock(component, 'assistant', assistantVisibleText(message));
|
|
1150
1170
|
const separator = this.appendAssistantSeparator(groupMember);
|
|
@@ -1400,8 +1420,38 @@ export class ChatView {
|
|
|
1400
1420
|
this.copyBlockRecords.length = 0;
|
|
1401
1421
|
this.copyIndex.clear();
|
|
1402
1422
|
this.transcriptFilePaths.length = 0;
|
|
1423
|
+
this.pageBlocks.clear();
|
|
1403
1424
|
this.historyContainer.clear();
|
|
1404
1425
|
}
|
|
1426
|
+
/** Place the transcript block for an inline page a `human send` just raised.
|
|
1427
|
+
* The block is a plain history child, NOT a tool-group member: collapsing the
|
|
1428
|
+
* tool group folds the command away and leaves the page itself on screen, the
|
|
1429
|
+
* way assistant prose stays. Condensed history is skipped deliberately — old
|
|
1430
|
+
* cycles keep only prose and cycle seams. */
|
|
1431
|
+
maybeAppendPageBlock(result) {
|
|
1432
|
+
if (!this.inlinePageBlocks || this.appendTarget !== this.historyContainer)
|
|
1433
|
+
return;
|
|
1434
|
+
const page = detectInlinePageResult(result);
|
|
1435
|
+
if (page === undefined || this.pageBlocks.has(page.pageId))
|
|
1436
|
+
return;
|
|
1437
|
+
const block = new PageBlockComponent(page.pageId, page.dir, this.pageOpenHint);
|
|
1438
|
+
this.pageBlocks.set(page.pageId, block);
|
|
1439
|
+
this.append(block);
|
|
1440
|
+
}
|
|
1441
|
+
/** Re-read every placed page from disk. Driven by the viewer's ticket-activity
|
|
1442
|
+
* watcher, so an answer, a cancellation, or a `--replace` revision lands on
|
|
1443
|
+
* the block already anchored in the transcript. */
|
|
1444
|
+
refreshPageBlocks() {
|
|
1445
|
+
let changed = false;
|
|
1446
|
+
for (const block of this.pageBlocks.values()) {
|
|
1447
|
+
if (!block.refresh())
|
|
1448
|
+
continue;
|
|
1449
|
+
changed = true;
|
|
1450
|
+
this.historyContainer.markDirty(block);
|
|
1451
|
+
}
|
|
1452
|
+
if (changed)
|
|
1453
|
+
this.tui.requestRender();
|
|
1454
|
+
}
|
|
1405
1455
|
makeLoader(message) {
|
|
1406
1456
|
// Loader updates itself on an interval. Its TUI callback has to evict the
|
|
1407
1457
|
// status block's cached frame before requesting the next render.
|