@north-light/crouter 0.3.170 → 0.3.171
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/build-root.d.ts +1 -16
- package/dist/build-root.js +1 -25
- package/dist/builtin-memory/insights/capture.md +66 -0
- package/dist/builtin-memory/insights/init.md +45 -0
- package/dist/builtin-memory/internal/plugins.md +12 -11
- package/dist/cli.js +2 -6
- package/dist/clients/attach/__tests__/attach-keybindings.test.js +7 -1
- package/dist/clients/attach/__tests__/context-message.test.js +50 -3
- package/dist/clients/attach/__tests__/diagram.test.js +1 -1
- package/dist/clients/attach/chrome/header.d.ts +10 -0
- package/dist/clients/attach/chrome/header.js +35 -0
- package/dist/clients/attach/chrome/status-line.d.ts +3 -0
- package/dist/clients/attach/chrome/status-line.js +5 -0
- package/dist/clients/attach/chrome/widgets.js +7 -18
- package/dist/clients/attach/input/controller.d.ts +10 -0
- package/dist/clients/attach/input/controller.js +3 -0
- package/dist/clients/attach/overlays/help.d.ts +33 -0
- package/dist/clients/attach/overlays/help.js +204 -0
- package/dist/clients/attach/render/chat-view.d.ts +81 -9
- package/dist/clients/attach/render/chat-view.js +434 -90
- package/dist/clients/attach/render/context-message.js +3 -3
- package/dist/clients/attach/render/diagram.js +2 -2
- package/dist/clients/attach/render/measured-container.d.ts +94 -0
- package/dist/clients/attach/render/measured-container.js +307 -0
- package/dist/clients/attach/render/transcript-copy.d.ts +9 -0
- package/dist/clients/attach/render/transcript-copy.js +81 -0
- package/dist/clients/attach/render/viewport.d.ts +29 -0
- package/dist/clients/attach/render/viewport.js +160 -0
- package/dist/clients/attach/session/bindings.d.ts +5 -1
- package/dist/clients/attach/session/bindings.js +16 -0
- package/dist/clients/attach/session/context.d.ts +5 -3
- package/dist/clients/attach/session/frame.d.ts +34 -0
- package/dist/clients/attach/session/frame.js +173 -0
- package/dist/clients/attach/session/frames.d.ts +2 -0
- package/dist/clients/attach/session/frames.js +3 -0
- package/dist/clients/attach/session/input-wiring.d.ts +10 -4
- package/dist/clients/attach/session/input-wiring.js +13 -13
- package/dist/clients/attach/session/keys.d.ts +4 -1
- package/dist/clients/attach/session/keys.js +9 -4
- package/dist/clients/attach/session/layout.d.ts +10 -8
- package/dist/clients/attach/session/layout.js +32 -31
- package/dist/clients/attach/session/mouse.d.ts +15 -0
- package/dist/clients/attach/session/mouse.js +61 -0
- package/dist/clients/attach/slash/dispatch.d.ts +10 -0
- package/dist/clients/attach/slash/dispatch.js +35 -2
- package/dist/clients/attach/viewer.js +605 -581
- package/dist/clients/web/dev-server.d.ts +4 -1
- package/dist/clients/web/dev-server.js +8 -19
- package/dist/clients/web/web-cmd.js +1 -1
- package/dist/commands/human/prompts.js +2 -1
- package/dist/commands/pkg/plugin-manage.js +143 -68
- package/dist/commands/sys/__tests__/setup-core.test.js +4 -2
- package/dist/commands/sys/setup-core.js +21 -16
- package/dist/core/clipboard-text.d.ts +8 -0
- package/dist/core/clipboard-text.js +18 -0
- package/dist/core/command-manifests/registry.d.ts +1 -3
- package/dist/core/command-plugins/bundle.d.ts +29 -0
- package/dist/core/command-plugins/bundle.js +198 -0
- package/dist/core/command-plugins/discovery.d.ts +0 -8
- package/dist/core/command-plugins/discovery.js +2 -39
- package/dist/core/command-plugins/transport/http-fetch.d.ts +4 -30
- package/dist/core/command-plugins/transport/http-fetch.js +17 -95
- package/dist/core/command.d.ts +1 -13
- package/dist/core/command.js +1 -16
- package/dist/core/config.js +2 -1
- package/dist/core/keybindings/__tests__/resolve.test.js +4 -0
- package/dist/core/keybindings/attach-control.d.ts +3 -0
- package/dist/core/keybindings/attach-control.js +1 -0
- package/dist/core/keybindings/catalog.d.ts +2 -2
- package/dist/core/keybindings/catalog.js +8 -0
- package/dist/core/runtime/broker-protocol.d.ts +13 -1
- package/dist/core/runtime/broker.js +213 -5
- package/dist/core/runtime/canvas-extensions.d.ts +3 -0
- package/dist/core/runtime/canvas-extensions.js +3 -0
- package/dist/core/runtime/front-door.js +4 -4
- package/dist/core/runtime/kickoff.d.ts +1 -5
- package/dist/core/runtime/kickoff.js +1 -5
- package/dist/core/runtime/naming.d.ts +7 -0
- package/dist/core/runtime/naming.js +5 -2
- package/dist/core/runtime/node-read.js +15 -0
- package/dist/core/runtime/package-health.d.ts +6 -21
- package/dist/core/runtime/package-health.js +12 -123
- package/dist/core/runtime/stop-guard.d.ts +1 -1
- package/dist/core/runtime/stop-guard.js +3 -3
- package/dist/core/runtime/tool-group-summary.d.ts +19 -0
- package/dist/core/runtime/tool-group-summary.js +117 -0
- package/dist/core/termrender/code-doc.d.ts +12 -0
- package/dist/core/termrender/code-doc.js +91 -0
- package/dist/core/termrender/display.d.ts +12 -0
- package/dist/core/termrender/display.js +19 -0
- package/dist/core/termrender/termrender.d.ts +73 -0
- package/dist/core/termrender/termrender.js +795 -0
- package/dist/core/termrender/version.d.ts +1 -0
- package/dist/core/termrender/version.js +1 -0
- package/dist/core/user-settings.d.ts +14 -0
- package/dist/core/user-settings.js +20 -0
- package/dist/daemon/crtrd.js +5 -6
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/pi-extensions/__tests__/canvas-structured-output.test.d.ts +1 -0
- package/dist/pi-extensions/__tests__/canvas-structured-output.test.js +63 -0
- package/dist/pi-extensions/canvas-stophook.js +2 -2
- package/dist/pi-extensions/canvas-structured-output.js +52 -8
- package/dist/pi-extensions/summary-tool.d.ts +33 -0
- package/dist/pi-extensions/summary-tool.js +62 -0
- package/dist/shared/generated-context.d.ts +19 -4
- package/dist/shared/generated-context.js +98 -7
- package/dist/shared/tool-groups.d.ts +23 -0
- package/dist/shared/tool-groups.js +60 -0
- package/dist/types.d.ts +11 -0
- package/dist/types.js +1 -0
- package/dist/web-client/assets/{index-U_NZ66VE.js → index-D7I3gHCL.js} +26 -19
- package/dist/web-client/index.html +1 -1
- package/dist/web-client/sw.js +1 -1
- package/package.json +3 -1
- package/runtime.lock.json +62 -3
- package/scripts/postinstall.mjs +14 -1
- package/dist/core/command-plugins/store.d.ts +0 -16
- package/dist/core/command-plugins/store.js +0 -64
- package/dist/core/runtime/fault-recovery-nudge.d.ts +0 -3
- package/dist/core/runtime/fault-recovery-nudge.js +0 -3
|
@@ -10,8 +10,8 @@ type ProfileMenuAction = 'up' | 'down' | 'select' | 'accept-default' | 'abort' |
|
|
|
10
10
|
type SetupAction = 'cancel' | 'tab-next' | 'tab-previous' | 'open' | 'list-down' | 'list-up' | 'toggle' | 'details' | 'advance' | 'cell-previous' | 'cell-next';
|
|
11
11
|
type SetupKeybindingAction = 'edit' | 'commit-edit' | 'cancel-edit' | 'unbind' | 'reset-row' | 'reset-all' | 'save' | 'discard' | 'page-up' | 'page-down' | 'filter' | 'filter-delete' | 'filter-clear';
|
|
12
12
|
type SetupModelsAction = 'open' | 'commit' | 'cancel' | 'scope-next';
|
|
13
|
-
export type BindingId = `crtr.tmux.menu.${TmuxMenuAction}` | `crtr.tmux.menu.issue.${'idea' | 'bug'}` | AttachMenuBindingId | `crtr.tmux.menu-global.${TmuxMenuEntryAction}` | `crtr.tmux.node.${'next' | 'previous'}` | `crtr.tmux.view.${'next' | 'previous'}` | 'crtr.tmux.inbox.toggle' | AttachBindingId | `crtr.graph.${GraphAction}` | `crtr.graph.confirm.${'accept' | 'cancel'}` | `crtr.view.host.${'force-quit' | 'editor.backspace'}` | `crtr.view.canvas.${'down' | 'up' | 'refresh' | 'quit'}` | `crtr.view.chat.${'submit' | 'contextual-cancel' | 'reconnect' | 'quit'}` | `crtr.view.git-pr.${'down' | 'up' | 'refresh' | 'quit'}` | `crtr.view.inbox.${InboxAction}` | `crtr.view.linkedin.${LinkedinAction}` | `crtr.view.prompt-review.${'down' | 'up' | 'compare-previous' | 'compare-next' | 'toggle-mode' | 'expand' | 'export' | 'refresh' | 'quit'}` | `crtr.view.workspace-sidebar.${'down' | 'up' | 'open' | 'refresh' | 'quit'}` | `crtr.view.inspector.${'down' | 'up' | 'section-next' | 'section-prev' | 'page-down' | 'page-up' | 'toggle-detail' | 'cancel-item' | 'open-log' | 'confirm' | 'dismiss' | 'retarget' | 'refresh' | 'quit'}` | `crtr.view-picker.${'down' | 'up' | 'run' | 'quit'}` | `crtr.browse.${BrowseAction}` | `crtr.browse.search.${'cancel' | 'commit' | 'delete' | 'quit'}` | `crtr.profile.menu.${ProfileMenuAction}` | `crtr.profile.search.${'up' | 'down' | 'pick' | 'back' | 'delete' | 'abort'}` | `crtr.setup.${SetupAction}` | `crtr.setup.confirm.${'accept' | 'back'}` | `crtr.setup.keybindings.${SetupKeybindingAction}` | `crtr.setup.models.${SetupModelsAction}`;
|
|
14
|
-
export declare const BINDING_CATALOG: readonly [BindingDefinition<"crtr.tmux.menu.open">, BindingDefinition<"crtr.tmux.menu.attach">, ...(BindingDefinition<BindingId> | BindingDefinition<"crtr.tmux.node.next"> | BindingDefinition<"crtr.tmux.node.previous"> | BindingDefinition<"crtr.tmux.inbox.toggle"> | BindingDefinition<"crtr.tmux.view.next"> | BindingDefinition<"crtr.tmux.view.previous"> | BindingDefinition<"crtr.graph.down"> | BindingDefinition<"crtr.graph.up"> | BindingDefinition<"crtr.graph.first"> | BindingDefinition<"crtr.graph.last"> | BindingDefinition<"crtr.graph.collapse-or-manager"> | BindingDefinition<"crtr.graph.expand-or-child"> | BindingDefinition<"crtr.graph.focus"> | BindingDefinition<"crtr.graph.revive"> | BindingDefinition<"crtr.graph.focus-manager"> | BindingDefinition<"crtr.graph.close-subtree"> | BindingDefinition<"crtr.graph.dismiss"> | BindingDefinition<"crtr.graph.confirm.accept"> | BindingDefinition<"crtr.graph.confirm.cancel"> | BindingDefinition<"crtr.view.host.force-quit"> | BindingDefinition<"crtr.view.host.editor.backspace"> | BindingDefinition<"crtr.view.chat.submit"> | BindingDefinition<"crtr.view.chat.contextual-cancel"> | BindingDefinition<"crtr.view.chat.reconnect"> | BindingDefinition<"crtr.view.chat.quit"> | BindingDefinition<"crtr.view.prompt-review.down"> | BindingDefinition<"crtr.view.prompt-review.up"> | BindingDefinition<"crtr.view.prompt-review.compare-previous"> | BindingDefinition<"crtr.view.prompt-review.compare-next"> | BindingDefinition<"crtr.view.prompt-review.toggle-mode"> | BindingDefinition<"crtr.view.prompt-review.expand"> | BindingDefinition<"crtr.view.prompt-review.export"> | BindingDefinition<"crtr.view.prompt-review.refresh"> | BindingDefinition<"crtr.view.prompt-review.quit"> | BindingDefinition<"crtr.view.workspace-sidebar.down"> | BindingDefinition<"crtr.view.workspace-sidebar.up"> | BindingDefinition<"crtr.view.workspace-sidebar.open"> | BindingDefinition<"crtr.view.workspace-sidebar.refresh"> | BindingDefinition<"crtr.view.workspace-sidebar.quit"> | BindingDefinition<"crtr.view.inspector.down"> | BindingDefinition<"crtr.view.inspector.up"> | BindingDefinition<"crtr.view.inspector.section-next"> | BindingDefinition<"crtr.view.inspector.section-prev"> | BindingDefinition<"crtr.view.inspector.page-down"> | BindingDefinition<"crtr.view.inspector.page-up"> | BindingDefinition<"crtr.view.inspector.toggle-detail"> | BindingDefinition<"crtr.view.inspector.cancel-item"> | BindingDefinition<"crtr.view.inspector.open-log"> | BindingDefinition<"crtr.view.inspector.confirm"> | BindingDefinition<"crtr.view.inspector.dismiss"> | BindingDefinition<"crtr.view.inspector.retarget"> | BindingDefinition<"crtr.view.inspector.refresh"> | BindingDefinition<"crtr.view.inspector.quit"> | BindingDefinition<"crtr.view-picker.down"> | BindingDefinition<"crtr.view-picker.up"> | BindingDefinition<"crtr.view-picker.run"> | BindingDefinition<"crtr.view-picker.quit"> | BindingDefinition<"crtr.browse.quit"> | BindingDefinition<"crtr.browse.down"> | BindingDefinition<"crtr.browse.up"> | BindingDefinition<"crtr.browse.first"> | BindingDefinition<"crtr.browse.last"> | BindingDefinition<"crtr.browse.expand-or-child"> | BindingDefinition<"crtr.browse.collapse-or-parent"> | BindingDefinition<"crtr.browse.toggle-fold"> | BindingDefinition<"crtr.browse.tab-next"> | BindingDefinition<"crtr.browse.tab-previous"> | BindingDefinition<"crtr.browse.tab.2" | "crtr.browse.tab.1" | "crtr.browse.tab.3" | "crtr.browse.tab.4" | "crtr.browse.tab.5"> | BindingDefinition<"crtr.browse.close-subtree"> | BindingDefinition<"crtr.browse.confirm-close"> | BindingDefinition<"crtr.browse.sort"> | BindingDefinition<"crtr.browse.scope"> | BindingDefinition<"crtr.browse.profile"> | BindingDefinition<"crtr.browse.residents"> | BindingDefinition<"crtr.browse.preview"> | BindingDefinition<"crtr.browse.search"> | BindingDefinition<"crtr.browse.revive-now"> | BindingDefinition<"crtr.browse.focus"> | BindingDefinition<"crtr.browse.focus-background"> | BindingDefinition<"crtr.browse.search.cancel"> | BindingDefinition<"crtr.browse.search.commit"> | BindingDefinition<"crtr.browse.search.delete"> | BindingDefinition<"crtr.browse.search.quit"> | BindingDefinition<"crtr.profile.menu.up"> | BindingDefinition<"crtr.profile.menu.down"> | BindingDefinition<"crtr.profile.menu.select"> | BindingDefinition<"crtr.profile.menu.accept-default"> | BindingDefinition<"crtr.profile.menu.abort"> | BindingDefinition<"crtr.profile.menu.slot.2" | "crtr.profile.menu.slot.1" | "crtr.profile.menu.slot.3" | "crtr.profile.menu.slot.4" | "crtr.profile.menu.slot.5" | "crtr.profile.menu.slot.9" | "crtr.profile.menu.slot.8" | "crtr.profile.menu.slot.6" | "crtr.profile.menu.slot.7">)[], BindingDefinition<"crtr.profile.menu.create">, BindingDefinition<"crtr.profile.menu.search-existing">, BindingDefinition<"crtr.profile.menu.use-root">, BindingDefinition<"crtr.profile.menu.set-default">, BindingDefinition<"crtr.profile.menu.add-directory">, BindingDefinition<"crtr.profile.menu.unpin">, BindingDefinition<"crtr.profile.search.up">, BindingDefinition<"crtr.profile.search.down">, BindingDefinition<"crtr.profile.search.pick">, BindingDefinition<"crtr.profile.search.back">, BindingDefinition<"crtr.profile.search.delete">, BindingDefinition<"crtr.profile.search.abort">, BindingDefinition<"crtr.setup.cancel">, BindingDefinition<"crtr.setup.tab-next">, BindingDefinition<"crtr.setup.tab-previous">, BindingDefinition<"crtr.setup.open">, BindingDefinition<"crtr.setup.list-down">, BindingDefinition<"crtr.setup.list-up">, BindingDefinition<"crtr.setup.toggle">, BindingDefinition<"crtr.setup.details">, BindingDefinition<"crtr.setup.advance">, BindingDefinition<"crtr.setup.confirm.accept">, BindingDefinition<"crtr.setup.confirm.back">, BindingDefinition<"crtr.setup.keybindings.edit">, BindingDefinition<"crtr.setup.keybindings.commit-edit">, BindingDefinition<"crtr.setup.keybindings.cancel-edit">, BindingDefinition<"crtr.setup.keybindings.unbind">, BindingDefinition<"crtr.setup.keybindings.reset-row">, BindingDefinition<"crtr.setup.keybindings.reset-all">, BindingDefinition<"crtr.setup.keybindings.save">, BindingDefinition<"crtr.setup.keybindings.discard">, BindingDefinition<"crtr.setup.keybindings.page-up">, BindingDefinition<"crtr.setup.keybindings.page-down">, BindingDefinition<"crtr.setup.keybindings.filter">, BindingDefinition<"crtr.setup.keybindings.filter-delete">, BindingDefinition<"crtr.setup.keybindings.filter-clear">, BindingDefinition<"crtr.setup.cell-previous">, BindingDefinition<"crtr.setup.cell-next">, BindingDefinition<"crtr.setup.models.open">, BindingDefinition<"crtr.setup.models.scope-next">, BindingDefinition<"crtr.setup.models.commit">, BindingDefinition<"crtr.setup.models.cancel">];
|
|
13
|
+
export type BindingId = `crtr.tmux.menu.${TmuxMenuAction}` | `crtr.tmux.menu.issue.${'idea' | 'bug'}` | AttachMenuBindingId | `crtr.tmux.menu-global.${TmuxMenuEntryAction}` | `crtr.tmux.node.${'next' | 'previous'}` | `crtr.tmux.view.${'next' | 'previous'}` | 'crtr.tmux.inbox.toggle' | `crtr.attach.scroll.${'up' | 'down' | 'page-up' | 'page-down' | 'live'}` | 'crtr.attach.mouse.toggle' | 'crtr.attach.copy.message' | 'crtr.attach.help.toggle' | AttachBindingId | `crtr.graph.${GraphAction}` | `crtr.graph.confirm.${'accept' | 'cancel'}` | `crtr.view.host.${'force-quit' | 'editor.backspace'}` | `crtr.view.canvas.${'down' | 'up' | 'refresh' | 'quit'}` | `crtr.view.chat.${'submit' | 'contextual-cancel' | 'reconnect' | 'quit'}` | `crtr.view.git-pr.${'down' | 'up' | 'refresh' | 'quit'}` | `crtr.view.inbox.${InboxAction}` | `crtr.view.linkedin.${LinkedinAction}` | `crtr.view.prompt-review.${'down' | 'up' | 'compare-previous' | 'compare-next' | 'toggle-mode' | 'expand' | 'export' | 'refresh' | 'quit'}` | `crtr.view.workspace-sidebar.${'down' | 'up' | 'open' | 'refresh' | 'quit'}` | `crtr.view.inspector.${'down' | 'up' | 'section-next' | 'section-prev' | 'page-down' | 'page-up' | 'toggle-detail' | 'cancel-item' | 'open-log' | 'confirm' | 'dismiss' | 'retarget' | 'refresh' | 'quit'}` | `crtr.view-picker.${'down' | 'up' | 'run' | 'quit'}` | `crtr.browse.${BrowseAction}` | `crtr.browse.search.${'cancel' | 'commit' | 'delete' | 'quit'}` | `crtr.profile.menu.${ProfileMenuAction}` | `crtr.profile.search.${'up' | 'down' | 'pick' | 'back' | 'delete' | 'abort'}` | `crtr.setup.${SetupAction}` | `crtr.setup.confirm.${'accept' | 'back'}` | `crtr.setup.keybindings.${SetupKeybindingAction}` | `crtr.setup.models.${SetupModelsAction}`;
|
|
14
|
+
export declare const BINDING_CATALOG: readonly [BindingDefinition<"crtr.tmux.menu.open">, BindingDefinition<"crtr.tmux.menu.attach">, ...(BindingDefinition<BindingId> | BindingDefinition<"crtr.tmux.node.next"> | BindingDefinition<"crtr.tmux.node.previous"> | BindingDefinition<"crtr.tmux.inbox.toggle"> | BindingDefinition<"crtr.tmux.view.next"> | BindingDefinition<"crtr.tmux.view.previous"> | BindingDefinition<"crtr.attach.scroll.up"> | BindingDefinition<"crtr.attach.scroll.down"> | BindingDefinition<"crtr.attach.scroll.page-up"> | BindingDefinition<"crtr.attach.scroll.page-down"> | BindingDefinition<"crtr.attach.scroll.live"> | BindingDefinition<"crtr.attach.mouse.toggle"> | BindingDefinition<"crtr.attach.copy.message"> | BindingDefinition<"crtr.graph.down"> | BindingDefinition<"crtr.graph.up"> | BindingDefinition<"crtr.graph.first"> | BindingDefinition<"crtr.graph.last"> | BindingDefinition<"crtr.graph.collapse-or-manager"> | BindingDefinition<"crtr.graph.expand-or-child"> | BindingDefinition<"crtr.graph.focus"> | BindingDefinition<"crtr.graph.revive"> | BindingDefinition<"crtr.graph.focus-manager"> | BindingDefinition<"crtr.graph.close-subtree"> | BindingDefinition<"crtr.graph.dismiss"> | BindingDefinition<"crtr.graph.confirm.accept"> | BindingDefinition<"crtr.graph.confirm.cancel"> | BindingDefinition<"crtr.view.host.force-quit"> | BindingDefinition<"crtr.view.host.editor.backspace"> | BindingDefinition<"crtr.view.chat.submit"> | BindingDefinition<"crtr.view.chat.contextual-cancel"> | BindingDefinition<"crtr.view.chat.reconnect"> | BindingDefinition<"crtr.view.chat.quit"> | BindingDefinition<"crtr.view.prompt-review.down"> | BindingDefinition<"crtr.view.prompt-review.up"> | BindingDefinition<"crtr.view.prompt-review.compare-previous"> | BindingDefinition<"crtr.view.prompt-review.compare-next"> | BindingDefinition<"crtr.view.prompt-review.toggle-mode"> | BindingDefinition<"crtr.view.prompt-review.expand"> | BindingDefinition<"crtr.view.prompt-review.export"> | BindingDefinition<"crtr.view.prompt-review.refresh"> | BindingDefinition<"crtr.view.prompt-review.quit"> | BindingDefinition<"crtr.view.workspace-sidebar.down"> | BindingDefinition<"crtr.view.workspace-sidebar.up"> | BindingDefinition<"crtr.view.workspace-sidebar.open"> | BindingDefinition<"crtr.view.workspace-sidebar.refresh"> | BindingDefinition<"crtr.view.workspace-sidebar.quit"> | BindingDefinition<"crtr.view.inspector.down"> | BindingDefinition<"crtr.view.inspector.up"> | BindingDefinition<"crtr.view.inspector.section-next"> | BindingDefinition<"crtr.view.inspector.section-prev"> | BindingDefinition<"crtr.view.inspector.page-down"> | BindingDefinition<"crtr.view.inspector.page-up"> | BindingDefinition<"crtr.view.inspector.toggle-detail"> | BindingDefinition<"crtr.view.inspector.cancel-item"> | BindingDefinition<"crtr.view.inspector.open-log"> | BindingDefinition<"crtr.view.inspector.confirm"> | BindingDefinition<"crtr.view.inspector.dismiss"> | BindingDefinition<"crtr.view.inspector.retarget"> | BindingDefinition<"crtr.view.inspector.refresh"> | BindingDefinition<"crtr.view.inspector.quit"> | BindingDefinition<"crtr.view-picker.down"> | BindingDefinition<"crtr.view-picker.up"> | BindingDefinition<"crtr.view-picker.run"> | BindingDefinition<"crtr.view-picker.quit"> | BindingDefinition<"crtr.browse.quit"> | BindingDefinition<"crtr.browse.down"> | BindingDefinition<"crtr.browse.up"> | BindingDefinition<"crtr.browse.first"> | BindingDefinition<"crtr.browse.last"> | BindingDefinition<"crtr.browse.expand-or-child"> | BindingDefinition<"crtr.browse.collapse-or-parent"> | BindingDefinition<"crtr.browse.toggle-fold"> | BindingDefinition<"crtr.browse.tab-next"> | BindingDefinition<"crtr.browse.tab-previous"> | BindingDefinition<"crtr.browse.tab.2" | "crtr.browse.tab.1" | "crtr.browse.tab.3" | "crtr.browse.tab.4" | "crtr.browse.tab.5"> | BindingDefinition<"crtr.browse.close-subtree"> | BindingDefinition<"crtr.browse.confirm-close"> | BindingDefinition<"crtr.browse.sort"> | BindingDefinition<"crtr.browse.scope"> | BindingDefinition<"crtr.browse.profile"> | BindingDefinition<"crtr.browse.residents"> | BindingDefinition<"crtr.browse.preview"> | BindingDefinition<"crtr.browse.search"> | BindingDefinition<"crtr.browse.revive-now"> | BindingDefinition<"crtr.browse.focus"> | BindingDefinition<"crtr.browse.focus-background"> | BindingDefinition<"crtr.browse.search.cancel"> | BindingDefinition<"crtr.browse.search.commit"> | BindingDefinition<"crtr.browse.search.delete"> | BindingDefinition<"crtr.browse.search.quit"> | BindingDefinition<"crtr.profile.menu.up"> | BindingDefinition<"crtr.profile.menu.down"> | BindingDefinition<"crtr.profile.menu.select"> | BindingDefinition<"crtr.profile.menu.accept-default"> | BindingDefinition<"crtr.profile.menu.abort"> | BindingDefinition<"crtr.profile.menu.slot.2" | "crtr.profile.menu.slot.1" | "crtr.profile.menu.slot.3" | "crtr.profile.menu.slot.4" | "crtr.profile.menu.slot.5" | "crtr.profile.menu.slot.9" | "crtr.profile.menu.slot.8" | "crtr.profile.menu.slot.6" | "crtr.profile.menu.slot.7">)[], BindingDefinition<"crtr.profile.menu.create">, BindingDefinition<"crtr.profile.menu.search-existing">, BindingDefinition<"crtr.profile.menu.use-root">, BindingDefinition<"crtr.profile.menu.set-default">, BindingDefinition<"crtr.profile.menu.add-directory">, BindingDefinition<"crtr.profile.menu.unpin">, BindingDefinition<"crtr.profile.search.up">, BindingDefinition<"crtr.profile.search.down">, BindingDefinition<"crtr.profile.search.pick">, BindingDefinition<"crtr.profile.search.back">, BindingDefinition<"crtr.profile.search.delete">, BindingDefinition<"crtr.profile.search.abort">, BindingDefinition<"crtr.setup.cancel">, BindingDefinition<"crtr.setup.tab-next">, BindingDefinition<"crtr.setup.tab-previous">, BindingDefinition<"crtr.setup.open">, BindingDefinition<"crtr.setup.list-down">, BindingDefinition<"crtr.setup.list-up">, BindingDefinition<"crtr.setup.toggle">, BindingDefinition<"crtr.setup.details">, BindingDefinition<"crtr.setup.advance">, BindingDefinition<"crtr.setup.confirm.accept">, BindingDefinition<"crtr.setup.confirm.back">, BindingDefinition<"crtr.setup.keybindings.edit">, BindingDefinition<"crtr.setup.keybindings.commit-edit">, BindingDefinition<"crtr.setup.keybindings.cancel-edit">, BindingDefinition<"crtr.setup.keybindings.unbind">, BindingDefinition<"crtr.setup.keybindings.reset-row">, BindingDefinition<"crtr.setup.keybindings.reset-all">, BindingDefinition<"crtr.setup.keybindings.save">, BindingDefinition<"crtr.setup.keybindings.discard">, BindingDefinition<"crtr.setup.keybindings.page-up">, BindingDefinition<"crtr.setup.keybindings.page-down">, BindingDefinition<"crtr.setup.keybindings.filter">, BindingDefinition<"crtr.setup.keybindings.filter-delete">, BindingDefinition<"crtr.setup.keybindings.filter-clear">, BindingDefinition<"crtr.setup.cell-previous">, BindingDefinition<"crtr.setup.cell-next">, BindingDefinition<"crtr.setup.models.open">, BindingDefinition<"crtr.setup.models.scope-next">, BindingDefinition<"crtr.setup.models.commit">, BindingDefinition<"crtr.setup.models.cancel">];
|
|
15
15
|
export declare const BINDING_IDS: ReadonlySet<string>;
|
|
16
16
|
export declare const SAFETY_REQUIREMENTS: readonly SafetyRequirement[];
|
|
17
17
|
export {};
|
|
@@ -74,11 +74,19 @@ export const BINDING_CATALOG = Object.freeze([
|
|
|
74
74
|
...attachEntry('crtr.tmux.menu.attach.clear-or-detach', 'crtr.attach.clear-or-detach', 'Clear or detach', 'Clear input or detach when input is empty.', 'c', ['ctrl+c']),
|
|
75
75
|
...attachEntry('crtr.tmux.menu.attach.mode-cycle', 'crtr.mode.cycle', 'Cycle mode', 'Cycle the active agent mode.', 'p', ['alt+shift+p']),
|
|
76
76
|
...attachEntry('crtr.tmux.menu.attach.graph.toggle', 'crtr.attach.graph.toggle', 'Toggle graph', 'Open or close the graph overlay.', 'g', ['alt+g']),
|
|
77
|
+
...attachEntry('crtr.tmux.menu.attach.help.toggle', 'crtr.attach.help.toggle', 'Help', 'Open the attach help overlay.', 'k', ['alt+shift+k']),
|
|
77
78
|
...attachEntry('crtr.tmux.menu.attach.model-ladder.next', 'crtr.attach.model-ladder.next', 'Next model ladder', 'Move to the next model ladder rung.', ']', ['alt+m']),
|
|
78
79
|
...attachEntry('crtr.tmux.menu.attach.model-ladder.previous', 'crtr.attach.model-ladder.previous', 'Previous model ladder', 'Move to the previous model ladder rung.', '[', ['alt+shift+m']),
|
|
79
80
|
...attachEntry('crtr.tmux.menu.attach.command.inspect', 'crtr.attach.command.inspect', 'Inspect loaded command', 'Open the loaded slash command’s expanded prompt.', 'h', ['alt+shift+h']),
|
|
80
81
|
...attachEntry('crtr.tmux.menu.attach.file-review', 'crtr.attach.file-review', 'Review a file', 'Open a line-anchored review of a file named in the transcript.', 'r', ['alt+shift+r']),
|
|
81
82
|
...attachEntry('crtr.tmux.menu.attach.profile-files', 'crtr.attach.profile-files', 'Search profile files', 'Search files across the node’s profile projects, cwd, and ancestor crouter memory stores.', 'f', []),
|
|
83
|
+
b('crtr.attach.scroll.up', 'Attach', 'Scroll up', 'Scroll the transcript one line up.', ['shift+up'], 'terminal', ATTACH_CONTEXTS),
|
|
84
|
+
b('crtr.attach.scroll.down', 'Attach', 'Scroll down', 'Scroll the transcript one line down.', ['shift+down'], 'terminal', ATTACH_CONTEXTS),
|
|
85
|
+
b('crtr.attach.scroll.page-up', 'Attach', 'Scroll page up', 'Scroll the transcript one page up.', ['pageup'], 'terminal', ATTACH_CONTEXTS),
|
|
86
|
+
b('crtr.attach.scroll.page-down', 'Attach', 'Scroll page down', 'Scroll the transcript one page down.', ['pagedown'], 'terminal', ATTACH_CONTEXTS),
|
|
87
|
+
b('crtr.attach.scroll.live', 'Attach', 'Return to live', 'Return the transcript to the live bottom.', ['shift+end'], 'terminal', ATTACH_CONTEXTS),
|
|
88
|
+
b('crtr.attach.mouse.toggle', 'Attach', 'Toggle mouse wheel scrolling', 'Toggle mouse wheel scrolling on or off.', ['alt+shift+o'], 'terminal', ATTACH_CONTEXTS),
|
|
89
|
+
b('crtr.attach.copy.message', 'Attach', 'Copy visible message', 'Copy the newest message visible in the transcript viewport.', ['alt+shift+y'], 'terminal', ATTACH_CONTEXTS),
|
|
82
90
|
b('crtr.graph.down', 'GRAPH', 'Move down', 'Move to the next graph row.', ['j'], 'terminal', ['graph']),
|
|
83
91
|
b('crtr.graph.up', 'GRAPH', 'Move up', 'Move to the previous graph row.', ['k'], 'terminal', ['graph']),
|
|
84
92
|
b('crtr.graph.first', 'GRAPH', 'First row', 'Move to the first graph row.', ['g'], 'terminal', ['graph']),
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { AgentSession, AgentSessionEvent, RpcExtensionUIRequest, RpcExtensionUIResponse, RpcSessionState, SessionEntry, SessionInfo, SettingsConfig, SessionStats } from '@earendil-works/pi-coding-agent';
|
|
2
2
|
import type { Api, ImageContent, Model } from '@earendil-works/pi-ai';
|
|
3
3
|
import type { BrokerErrorFrame } from '../../api/dto/broker.js';
|
|
4
|
+
import type { ToolGroupSummary } from '../../shared/tool-groups.js';
|
|
4
5
|
/** pi's own RPC types, re-exported unchanged. `broker-protocol` stays the one
|
|
5
6
|
* import site for the wire union; the shapes themselves are pi's, versioned by
|
|
6
7
|
* pi, so a pi change is a compile error here instead of silent drift. */
|
|
@@ -45,6 +46,10 @@ export interface BrokerSnapshot {
|
|
|
45
46
|
}>;
|
|
46
47
|
title: string | undefined;
|
|
47
48
|
};
|
|
49
|
+
/** Broker-owned summaries keyed by the first tool-call id in each group.
|
|
50
|
+
* Structured objects with bullets, nodesSpawned, and filesEdited.
|
|
51
|
+
* Optional so snapshots from an older live runtime remain readable. */
|
|
52
|
+
toolGroupSummaries?: Record<string, ToolGroupSummary>;
|
|
48
53
|
}
|
|
49
54
|
/** Opens the connection and FIXES this client's role for its lifetime. A repeated
|
|
50
55
|
* `hello` on an already-helloed socket never changes the established role. */
|
|
@@ -563,10 +568,17 @@ export interface ExtensionUIDismissFrame {
|
|
|
563
568
|
type: 'extension_ui_dismiss';
|
|
564
569
|
id: string;
|
|
565
570
|
}
|
|
571
|
+
/** A completed broker-side tool-group summary. The viewer owns presentation;
|
|
572
|
+
* this frame carries the durable group key and structured summary object. */
|
|
573
|
+
export interface ToolGroupSummaryFrame {
|
|
574
|
+
type: 'tool_group_summary';
|
|
575
|
+
key: string;
|
|
576
|
+
summary: ToolGroupSummary;
|
|
577
|
+
}
|
|
566
578
|
/** Everything the broker can send. Live `AgentSessionEvent`s are relayed
|
|
567
579
|
* verbatim (the broker adds nothing); the broker's own control frames carry
|
|
568
580
|
* non-colliding `type` discriminants. */
|
|
569
|
-
export type BrokerToClient = WelcomeFrame | ModelChangedFrame | ErrorFrame | AckFrame | BrokerDataFrame | BashStartFrame | BashOutputFrame | BashEndFrame | ExtensionUIRequestFrame | ExtensionUIDismissFrame | AgentSessionEvent;
|
|
581
|
+
export type BrokerToClient = WelcomeFrame | ModelChangedFrame | ErrorFrame | AckFrame | BrokerDataFrame | BashStartFrame | BashOutputFrame | BashEndFrame | ExtensionUIRequestFrame | ExtensionUIDismissFrame | ToolGroupSummaryFrame | AgentSessionEvent;
|
|
570
582
|
/** Encode one frame as a single newline-terminated JSON line. */
|
|
571
583
|
export declare function encodeFrame(frame: ClientToBroker | BrokerToClient): string;
|
|
572
584
|
/** Byte bounds for a {@link FrameDecoder} (C5). */
|
|
@@ -32,6 +32,8 @@ import { operationIdContext } from '../events/operation-id.js';
|
|
|
32
32
|
import { findMissingPackagePaths } from './package-health.js';
|
|
33
33
|
import { SessionListCache } from './session-list-cache.js';
|
|
34
34
|
import { getNode, updateNode } from '../canvas/index.js';
|
|
35
|
+
import { readConfig } from '../config.js';
|
|
36
|
+
import { atomicWriteJson, readJsonIfExists } from '../fs-utils.js';
|
|
35
37
|
import { buildRefInventory } from '../memory/inline-ref-inventory.js';
|
|
36
38
|
import { buildGuidance } from '../memory/inline-ref-guidance.js';
|
|
37
39
|
import { clearSessionCache } from '../substrate/session-cache.js';
|
|
@@ -44,7 +46,9 @@ import { PoolCredentialStore } from '../pool-credential-store.js';
|
|
|
44
46
|
import { clearFault, isModelNotFoundError, isProviderUnconfiguredError, readFault, recordFault, recordFaultForCurrentNode } from './fault.js';
|
|
45
47
|
import { clearCleanAbort, markBusy, markCleanAbort } from './busy.js';
|
|
46
48
|
import { extractCoolingDeadline } from './managed-provider-cooling.js';
|
|
47
|
-
import { AUTH_FAULT_RECOVERY_BODY, CONNECTION_FAULT_RECOVERY_BODY, PROVIDER_FAULT_RECOVERY_BODY } from '
|
|
49
|
+
import { AUTH_FAULT_RECOVERY_BODY, CONNECTION_FAULT_RECOVERY_BODY, PROVIDER_FAULT_RECOVERY_BODY, formatModelFallbackRecovery, generatedContextText, } from '../../shared/generated-context.js';
|
|
50
|
+
import { assistantVisibleText, isTrueUserMessage, normalizeToolGroupSummaryRecord, } from '../../shared/tool-groups.js';
|
|
51
|
+
import { headlessToolGroupSummary, serializeToolGroup } from './tool-group-summary.js';
|
|
48
52
|
import { markFatalOnExhaust, nextFaultRetry, policyFor } from './fault-recovery.js';
|
|
49
53
|
import { probeOnline as probeOnlineReal } from './connectivity.js';
|
|
50
54
|
import { CRTR_CYCLE_CUSTOM_TYPE, cycleAwareMessages } from './session-cycles.js';
|
|
@@ -588,7 +592,26 @@ export async function runBroker(nodeId, startupAt = process.hrtime.bigint(), sta
|
|
|
588
592
|
const displayStatuses = new Map();
|
|
589
593
|
const displayWidgets = new Map();
|
|
590
594
|
let displayTitle;
|
|
595
|
+
const toolSummariesPath = join(jobDir(nodeId), 'tool-summaries.json');
|
|
596
|
+
const toolGroupSummaries = new Map();
|
|
597
|
+
try {
|
|
598
|
+
const persisted = readJsonIfExists(toolSummariesPath);
|
|
599
|
+
for (const [key, summary] of Object.entries(normalizeToolGroupSummaryRecord(persisted))) {
|
|
600
|
+
toolGroupSummaries.set(key, summary);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
catch {
|
|
604
|
+
// A malformed sidecar merely withholds summaries; transcript tools remain visible.
|
|
605
|
+
}
|
|
606
|
+
const summaryAttempted = new Set(toolGroupSummaries.keys());
|
|
607
|
+
const generatingToolGroups = new Set();
|
|
608
|
+
const toolGroupsByCallId = new Map();
|
|
609
|
+
const summaryTasks = new Set();
|
|
610
|
+
let openToolGroup;
|
|
611
|
+
let lastToolGroupBoundaryProse = '';
|
|
612
|
+
let sawAssistantProse = false;
|
|
591
613
|
let disposed = false;
|
|
614
|
+
let disposePending = false;
|
|
592
615
|
let agentRunActive = false;
|
|
593
616
|
let shutdownRequested = false;
|
|
594
617
|
let server;
|
|
@@ -729,6 +752,168 @@ export async function runBroker(nodeId, startupAt = process.hrtime.bigint(), sta
|
|
|
729
752
|
}
|
|
730
753
|
broadcast(frame);
|
|
731
754
|
};
|
|
755
|
+
/** Record and asynchronously summarize the maximal non-boundary region between
|
|
756
|
+
* visible prose messages. A boundary can land while a tool is still running,
|
|
757
|
+
* so closed groups retain their call ids until every result has joined the
|
|
758
|
+
* same serialized segment; only then may they become collapsible. */
|
|
759
|
+
const ensureOpenToolGroup = () => {
|
|
760
|
+
if (openToolGroup === undefined) {
|
|
761
|
+
openToolGroup = {
|
|
762
|
+
toolCount: 0,
|
|
763
|
+
pieces: [],
|
|
764
|
+
boundaryProse: lastToolGroupBoundaryProse,
|
|
765
|
+
pendingToolIds: new Set(),
|
|
766
|
+
closed: false,
|
|
767
|
+
summarizeWhenSettled: false,
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
return openToolGroup;
|
|
771
|
+
};
|
|
772
|
+
const generateSettledToolGroup = (group) => {
|
|
773
|
+
if (!group.closed || group.pendingToolIds.size > 0 || group.key === undefined || !group.summarizeWhenSettled)
|
|
774
|
+
return;
|
|
775
|
+
const key = group.key;
|
|
776
|
+
if (summaryAttempted.has(key) || generatingToolGroups.has(key))
|
|
777
|
+
return;
|
|
778
|
+
summaryAttempted.add(key);
|
|
779
|
+
generatingToolGroups.add(key);
|
|
780
|
+
let task;
|
|
781
|
+
task = headlessToolGroupSummary(serializeToolGroup(group.boundaryProse, group.pieces))
|
|
782
|
+
.then((summary) => {
|
|
783
|
+
if (summary === null)
|
|
784
|
+
return;
|
|
785
|
+
toolGroupSummaries.set(key, summary);
|
|
786
|
+
try {
|
|
787
|
+
atomicWriteJson(toolSummariesPath, Object.fromEntries(toolGroupSummaries));
|
|
788
|
+
}
|
|
789
|
+
catch {
|
|
790
|
+
// A delivery without durable state would disappear on reattach, so do
|
|
791
|
+
// not advertise it. The calls remain folded normally instead.
|
|
792
|
+
toolGroupSummaries.delete(key);
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
795
|
+
broadcast({ type: 'tool_group_summary', key, summary });
|
|
796
|
+
})
|
|
797
|
+
.catch(() => undefined)
|
|
798
|
+
.finally(() => {
|
|
799
|
+
generatingToolGroups.delete(key);
|
|
800
|
+
summaryTasks.delete(task);
|
|
801
|
+
});
|
|
802
|
+
summaryTasks.add(task);
|
|
803
|
+
};
|
|
804
|
+
const finishOpenToolGroup = () => {
|
|
805
|
+
const group = openToolGroup;
|
|
806
|
+
openToolGroup = undefined;
|
|
807
|
+
if (group === undefined)
|
|
808
|
+
return;
|
|
809
|
+
group.closed = true;
|
|
810
|
+
// Configuration is read at the boundary, not when a slow tool later settles.
|
|
811
|
+
group.summarizeWhenSettled = readConfig('user').summarize_tool_calls;
|
|
812
|
+
generateSettledToolGroup(group);
|
|
813
|
+
};
|
|
814
|
+
const visibleBoundary = (prose) => {
|
|
815
|
+
finishOpenToolGroup();
|
|
816
|
+
lastToolGroupBoundaryProse = prose;
|
|
817
|
+
};
|
|
818
|
+
const observeToolGroupEvent = (event) => {
|
|
819
|
+
// The viewer turns every compaction_end into a summary, cancellation, or
|
|
820
|
+
// error line, each of which is a hard transcript seam.
|
|
821
|
+
if (event.type === 'compaction_end') {
|
|
822
|
+
finishOpenToolGroup();
|
|
823
|
+
return;
|
|
824
|
+
}
|
|
825
|
+
// A failed automatic retry is rendered as ChatView's visible error line.
|
|
826
|
+
// Successful retries only clear activity and remain within the same group.
|
|
827
|
+
if (event.type === 'auto_retry_end' && event.success !== true) {
|
|
828
|
+
finishOpenToolGroup();
|
|
829
|
+
return;
|
|
830
|
+
}
|
|
831
|
+
// The attach viewer renders aborted and errored assistant endings as visible
|
|
832
|
+
// transcript seams. Close their completed tool run here too; any tool that
|
|
833
|
+
// never emitted its execution_end keeps the group unsettled and visible.
|
|
834
|
+
if (event.type === 'message_end') {
|
|
835
|
+
const message = event.message;
|
|
836
|
+
if (message !== null && typeof message === 'object') {
|
|
837
|
+
const item = message;
|
|
838
|
+
if (item.role === 'assistant' && (item.stopReason === 'aborted' || item.stopReason === 'error')) {
|
|
839
|
+
finishOpenToolGroup();
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
844
|
+
if (event.type === 'tool_execution_start') {
|
|
845
|
+
const group = ensureOpenToolGroup();
|
|
846
|
+
const id = typeof event.toolCallId === 'string' ? event.toolCallId : '';
|
|
847
|
+
if (group.key === undefined && id !== '')
|
|
848
|
+
group.key = id;
|
|
849
|
+
if (id !== '') {
|
|
850
|
+
group.pendingToolIds.add(id);
|
|
851
|
+
toolGroupsByCallId.set(id, group);
|
|
852
|
+
}
|
|
853
|
+
group.toolCount += 1;
|
|
854
|
+
group.pieces.push({ type: 'tool', name: typeof event.toolName === 'string' ? event.toolName : 'tool', args: event.args });
|
|
855
|
+
return;
|
|
856
|
+
}
|
|
857
|
+
if (event.type === 'tool_execution_end') {
|
|
858
|
+
const id = typeof event.toolCallId === 'string' ? event.toolCallId : '';
|
|
859
|
+
const group = id === '' ? openToolGroup : toolGroupsByCallId.get(id);
|
|
860
|
+
if (group !== undefined) {
|
|
861
|
+
group.pieces.push({
|
|
862
|
+
type: 'result',
|
|
863
|
+
name: typeof event.toolName === 'string' ? event.toolName : 'tool',
|
|
864
|
+
result: event.result,
|
|
865
|
+
isError: event.isError === true,
|
|
866
|
+
});
|
|
867
|
+
if (id !== '') {
|
|
868
|
+
group.pendingToolIds.delete(id);
|
|
869
|
+
toolGroupsByCallId.delete(id);
|
|
870
|
+
}
|
|
871
|
+
generateSettledToolGroup(group);
|
|
872
|
+
}
|
|
873
|
+
return;
|
|
874
|
+
}
|
|
875
|
+
if (event.type !== 'message_start' && event.type !== 'message_update')
|
|
876
|
+
return;
|
|
877
|
+
const message = event.message;
|
|
878
|
+
if (message === null || typeof message !== 'object')
|
|
879
|
+
return;
|
|
880
|
+
const item = message;
|
|
881
|
+
const role = item.role;
|
|
882
|
+
if (role === 'assistant') {
|
|
883
|
+
if (event.type === 'message_start')
|
|
884
|
+
sawAssistantProse = false;
|
|
885
|
+
const prose = assistantVisibleText(item);
|
|
886
|
+
if (!sawAssistantProse && prose.trim() !== '') {
|
|
887
|
+
sawAssistantProse = true;
|
|
888
|
+
visibleBoundary(prose);
|
|
889
|
+
}
|
|
890
|
+
return;
|
|
891
|
+
}
|
|
892
|
+
if (event.type !== 'message_start')
|
|
893
|
+
return;
|
|
894
|
+
if (role === 'compactionSummary' || role === 'branchSummary' || role === 'bashExecution' || role === 'status' || role === 'error' || item.customType === 'crtr-cycle-divider') {
|
|
895
|
+
finishOpenToolGroup();
|
|
896
|
+
return;
|
|
897
|
+
}
|
|
898
|
+
if (isTrueUserMessage(item)) {
|
|
899
|
+
visibleBoundary(generatedContextText(item));
|
|
900
|
+
return;
|
|
901
|
+
}
|
|
902
|
+
if (item.display === false)
|
|
903
|
+
return;
|
|
904
|
+
const text = generatedContextText(item);
|
|
905
|
+
const isBearingsOrRevive = item.customType === 'crtr-context' || (role === 'user' && text.startsWith('You have been revived fresh after a context refresh'));
|
|
906
|
+
if (isBearingsOrRevive) {
|
|
907
|
+
if (openToolGroup !== undefined && text !== '')
|
|
908
|
+
openToolGroup.pieces.push({ type: 'text', text });
|
|
909
|
+
return;
|
|
910
|
+
}
|
|
911
|
+
// Generated inbox/situational/nudge and visible custom output are part of
|
|
912
|
+
// the between-message activity and may begin a group before its first tool.
|
|
913
|
+
const group = ensureOpenToolGroup();
|
|
914
|
+
if (text !== '')
|
|
915
|
+
group.pieces.push({ type: 'text', text });
|
|
916
|
+
};
|
|
732
917
|
// ---------------------------------------------------------------------------
|
|
733
918
|
// F2: message_update coalescing. `relayEvent` is the single entry point for
|
|
734
919
|
// engine events headed to viewers: a message_update is held (latest wins) and
|
|
@@ -951,9 +1136,7 @@ export async function runBroker(nodeId, startupAt = process.hrtime.bigint(), sta
|
|
|
951
1136
|
// node from reviving straight back into fault-recovery chrome.
|
|
952
1137
|
if (unconfigured)
|
|
953
1138
|
clearFault(nodeId, { link: 'pi→provider' });
|
|
954
|
-
await operationIdContext.fresh(() => session.prompt(unconfigured
|
|
955
|
-
? `The previous model (${currentSpec}) had no usable provider credential, so you were automatically switched to ${resolved}. Continue the task from where the failed turn left off.`
|
|
956
|
-
: `The previous model (${currentSpec}) was unavailable (provider 404 not_found), so you were automatically switched to ${resolved}. Continue the task from where the failed turn left off.`));
|
|
1139
|
+
await operationIdContext.fresh(() => session.prompt(formatModelFallbackRecovery(currentSpec, resolved, unconfigured ? 'credential' : 'not-found')));
|
|
957
1140
|
})()
|
|
958
1141
|
.catch((err) => {
|
|
959
1142
|
emitEvent({
|
|
@@ -1295,6 +1478,7 @@ export async function runBroker(nodeId, startupAt = process.hrtime.bigint(), sta
|
|
|
1295
1478
|
widgets: Object.fromEntries([...displayWidgets].map(([k, w]) => [k, { lines: [...w.lines], placement: w.placement }])),
|
|
1296
1479
|
title: displayTitle,
|
|
1297
1480
|
},
|
|
1481
|
+
toolGroupSummaries: Object.fromEntries(toolGroupSummaries),
|
|
1298
1482
|
});
|
|
1299
1483
|
// Send a client its catch-up snapshot. welcome.pending_dialog carries a single
|
|
1300
1484
|
// still-in-flight dialog to a WRITABLE client attaching mid-dialog; an observer
|
|
@@ -1337,7 +1521,7 @@ export async function runBroker(nodeId, startupAt = process.hrtime.bigint(), sta
|
|
|
1337
1521
|
// The single exit helper (plan §0): dispose the engine, close + unlink the
|
|
1338
1522
|
// socket, exit 0. Idempotent — every trigger converges here.
|
|
1339
1523
|
// -------------------------------------------------------------------------
|
|
1340
|
-
const
|
|
1524
|
+
const completeExit = (status) => {
|
|
1341
1525
|
if (disposed)
|
|
1342
1526
|
return;
|
|
1343
1527
|
disposed = true;
|
|
@@ -1381,6 +1565,23 @@ export async function runBroker(nodeId, startupAt = process.hrtime.bigint(), sta
|
|
|
1381
1565
|
}
|
|
1382
1566
|
process.exit(status);
|
|
1383
1567
|
};
|
|
1568
|
+
const disposeAndExit = (reason, status = 0) => {
|
|
1569
|
+
if (disposed)
|
|
1570
|
+
return;
|
|
1571
|
+
// A normal terminal shutdown follows a visible boundary that may have just
|
|
1572
|
+
// launched a capped (45s) headless summary. Keep the broker and its child
|
|
1573
|
+
// alive until those already-started tasks persist/broadcast, rather than
|
|
1574
|
+
// process.exit() orphaning pi and losing the sidecar. Abrupt failures and
|
|
1575
|
+
// signals retain their existing immediate teardown behavior.
|
|
1576
|
+
if ((reason === 'shutdown-hook' || reason === 'shutdown-after-settle') && summaryTasks.size > 0) {
|
|
1577
|
+
if (disposePending)
|
|
1578
|
+
return;
|
|
1579
|
+
disposePending = true;
|
|
1580
|
+
void Promise.allSettled([...summaryTasks]).finally(() => completeExit(status));
|
|
1581
|
+
return;
|
|
1582
|
+
}
|
|
1583
|
+
completeExit(status);
|
|
1584
|
+
};
|
|
1384
1585
|
// A stophook can request shutdown while pi is still unwinding a completed
|
|
1385
1586
|
// turn. Let that turn reach agent_settled first: inbox delivery commits its
|
|
1386
1587
|
// durable cursor there, and only there. Explicit operator shutdown and OS
|
|
@@ -1491,6 +1692,7 @@ export async function runBroker(nodeId, startupAt = process.hrtime.bigint(), sta
|
|
|
1491
1692
|
return;
|
|
1492
1693
|
}
|
|
1493
1694
|
}
|
|
1695
|
+
observeToolGroupEvent(event);
|
|
1494
1696
|
relayEvent(event, generation);
|
|
1495
1697
|
if (event.type === 'agent_settled')
|
|
1496
1698
|
scheduleFaultRetry();
|
|
@@ -1526,6 +1728,9 @@ export async function runBroker(nodeId, startupAt = process.hrtime.bigint(), sta
|
|
|
1526
1728
|
providerFallbackInFlight = null;
|
|
1527
1729
|
notFoundFallbackInFlight = null;
|
|
1528
1730
|
reloadAuthInFlight = null;
|
|
1731
|
+
openToolGroup = undefined;
|
|
1732
|
+
toolGroupsByCallId.clear();
|
|
1733
|
+
sawAssistantProse = false;
|
|
1529
1734
|
await candidateSession.bindExtensions({
|
|
1530
1735
|
uiContext,
|
|
1531
1736
|
// 'rpc' — NOT 'print'. Per pi docs/rpc.md:1078 this is exactly our shape:
|
|
@@ -1810,6 +2015,9 @@ export async function runBroker(nodeId, startupAt = process.hrtime.bigint(), sta
|
|
|
1810
2015
|
// Order before any held assistant message_update, so a `!` run mid-stream
|
|
1811
2016
|
// never renders ahead of the update it follows.
|
|
1812
2017
|
flushPendingUpdate();
|
|
2018
|
+
// The live bash component is a visible transcript boundary, even though
|
|
2019
|
+
// its persisted bashExecution message arrives later via the session.
|
|
2020
|
+
finishOpenToolGroup();
|
|
1813
2021
|
broadcast({ type: 'bash_start', command, excludeFromContext: exclude });
|
|
1814
2022
|
void session
|
|
1815
2023
|
.executeBash(command, (chunk) => broadcast({ type: 'bash_output', chunk }), {
|
|
@@ -12,6 +12,9 @@ export declare const CANVAS_BASH_VALVE_PATH: string;
|
|
|
12
12
|
* (`runtime/naming.ts`) to give it a constrained-schema `name_session` tool.
|
|
13
13
|
* Deliberately absent from CANVAS_EXTENSIONS: a node must never carry it. */
|
|
14
14
|
export declare const NAMING_TOOL_PATH: string;
|
|
15
|
+
/** NOT a canvas extension — loaded only by the broker's headless tool-group
|
|
16
|
+
* summarizer, which is the sole owner of summary generation and persistence. */
|
|
17
|
+
export declare const SUMMARY_TOOL_PATH: string;
|
|
15
18
|
/** The canvas extensions every node loads, in order. The inbox watcher commits
|
|
16
19
|
* its cursor at agent_settled before the stophook checks it for idle release. */
|
|
17
20
|
export declare const CANVAS_EXTENSIONS: string[];
|
|
@@ -24,6 +24,9 @@ export const CANVAS_BASH_VALVE_PATH = resolveExtension('canvas-bash-valve');
|
|
|
24
24
|
* (`runtime/naming.ts`) to give it a constrained-schema `name_session` tool.
|
|
25
25
|
* Deliberately absent from CANVAS_EXTENSIONS: a node must never carry it. */
|
|
26
26
|
export const NAMING_TOOL_PATH = resolveExtension('naming-tool');
|
|
27
|
+
/** NOT a canvas extension — loaded only by the broker's headless tool-group
|
|
28
|
+
* summarizer, which is the sole owner of summary generation and persistence. */
|
|
29
|
+
export const SUMMARY_TOOL_PATH = resolveExtension('summary-tool');
|
|
27
30
|
/** The canvas extensions every node loads, in order. The inbox watcher commits
|
|
28
31
|
* its cursor at agent_settled before the stophook checks it for idle release. */
|
|
29
32
|
export const CANVAS_EXTENSIONS = [
|
|
@@ -151,7 +151,7 @@ export async function maybeBootRoot(argv) {
|
|
|
151
151
|
// Unambiguous front-door launch → boot a resident root inline (exec pi in
|
|
152
152
|
// this terminal). Does not return. Load the heavy boot-path deps lazily now
|
|
153
153
|
// that we've committed to booting (see the import note at the top of file).
|
|
154
|
-
const [{ bootRoot }, { resumeRoot }, {
|
|
154
|
+
const [{ bootRoot }, { resumeRoot }, { rendererWarning, missingPackageWarning, piAgentDir }] = await Promise.all([
|
|
155
155
|
import('./boot-root.js'),
|
|
156
156
|
import('./resume-root.js'),
|
|
157
157
|
import('./package-health.js'),
|
|
@@ -164,9 +164,9 @@ export async function maybeBootRoot(argv) {
|
|
|
164
164
|
const warn = missingPackageWarning(piAgentDir());
|
|
165
165
|
if (warn !== null)
|
|
166
166
|
process.stderr.write(`\n${warn}\n\n`);
|
|
167
|
-
const
|
|
168
|
-
if (
|
|
169
|
-
process.stderr.write(`\n${
|
|
167
|
+
const rendererWarn = rendererWarning();
|
|
168
|
+
if (rendererWarn !== null)
|
|
169
|
+
process.stderr.write(`\n${rendererWarn}\n\n`);
|
|
170
170
|
}
|
|
171
171
|
catch {
|
|
172
172
|
/* best-effort diagnostic — never block a boot */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type NodeMeta } from '../canvas/index.js';
|
|
2
2
|
import { type WakeOrigin } from './bearings.js';
|
|
3
|
-
export { REVIVE_KICKOFF_SENTINEL } from '../../shared/generated-context.js';
|
|
3
|
+
export { REVIVE_KICKOFF_SENTINEL, RUNTIME_RESTART_CONTINUATION, } from '../../shared/generated-context.js';
|
|
4
4
|
/** The goal file — the prompt/task a node was spawned with, persisted at birth
|
|
5
5
|
* so a fresh revive can re-read its mandate. */
|
|
6
6
|
export declare function goalPath(nodeId: string): string;
|
|
@@ -16,10 +16,6 @@ export declare function captureGoalIfAbsent(nodeId: string, text: string): boole
|
|
|
16
16
|
/** Sentinel opening the fresh-revive kickoff message (see buildReviveKickoff).
|
|
17
17
|
* The goal-capture extension and attached renderers share its pure definition,
|
|
18
18
|
* so the same exact contract controls both prompt exclusion and display. */
|
|
19
|
-
/** Injected only when a broker cleanly persisted an aborted in-flight turn
|
|
20
|
-
* before a daemon restart. The transcript already carries the full picture, so
|
|
21
|
-
* this is a bare nudge — a longer explanation only destabilizes the resume. */
|
|
22
|
-
export declare const RUNTIME_RESTART_CONTINUATION = "continue";
|
|
23
19
|
/** The yield-message file — a short note `crtr node yield` records for the next
|
|
24
20
|
* fresh/cycling revive ("on wake, do X"). It remains durable through failed
|
|
25
21
|
* launch attempts and is cleared only when session_start confirms a boot. */
|
|
@@ -25,7 +25,7 @@ import { buildWakeBearings } from './bearings.js';
|
|
|
25
25
|
import { personaDrift, commitPersonaAck } from './persona.js';
|
|
26
26
|
import { readInboxSince, readCursor, writeCursor, coalesce, } from '../feed/inbox.js';
|
|
27
27
|
import { REVIVE_KICKOFF_SENTINEL } from '../../shared/generated-context.js';
|
|
28
|
-
export { REVIVE_KICKOFF_SENTINEL } from '../../shared/generated-context.js';
|
|
28
|
+
export { REVIVE_KICKOFF_SENTINEL, RUNTIME_RESTART_CONTINUATION, } from '../../shared/generated-context.js';
|
|
29
29
|
// ---------------------------------------------------------------------------
|
|
30
30
|
// Companion context files: the goal (the spawning mandate) and the one-shot
|
|
31
31
|
// yield message (a note from the prior self to the revived self).
|
|
@@ -65,10 +65,6 @@ export function captureGoalIfAbsent(nodeId, text) {
|
|
|
65
65
|
/** Sentinel opening the fresh-revive kickoff message (see buildReviveKickoff).
|
|
66
66
|
* The goal-capture extension and attached renderers share its pure definition,
|
|
67
67
|
* so the same exact contract controls both prompt exclusion and display. */
|
|
68
|
-
/** Injected only when a broker cleanly persisted an aborted in-flight turn
|
|
69
|
-
* before a daemon restart. The transcript already carries the full picture, so
|
|
70
|
-
* this is a bare nudge — a longer explanation only destabilizes the resume. */
|
|
71
|
-
export const RUNTIME_RESTART_CONTINUATION = 'continue';
|
|
72
68
|
/** The yield-message file — a short note `crtr node yield` records for the next
|
|
73
69
|
* fresh/cycling revive ("on wake, do X"). It remains durable through failed
|
|
74
70
|
* launch attempts and is cleared only when session_start confirms a boot. */
|
|
@@ -5,6 +5,13 @@ export declare function sanitizeSessionName(raw: string): string;
|
|
|
5
5
|
/** Local fallback: derive a name straight from the prompt (no pi call). Drops
|
|
6
6
|
* stop-words, takes the first few content words. */
|
|
7
7
|
export declare function slugFromPrompt(prompt: string): string;
|
|
8
|
+
/** The namer's model: the `light` rung of the DEFAULT provider's ladder, with
|
|
9
|
+
* any thinking suffix stripped (we pass `--thinking off` explicitly — naming is
|
|
10
|
+
* a trivial classification that never needs a reasoning budget). Reading the
|
|
11
|
+
* ladder rather than pinning a concrete model id keeps naming working for a
|
|
12
|
+
* user who never configured Anthropic: an OpenAI default provider resolves to
|
|
13
|
+
* its own light rung. `CRTR_NAME_MODEL` still overrides. */
|
|
14
|
+
export declare function lightModel(overrideEnv?: string): string;
|
|
8
15
|
/** A generated session name: the kebab-case handle plus the Nerd Font glyph the
|
|
9
16
|
* namer chose for it. `icon` is '' when the model returned nothing usable —
|
|
10
17
|
* every surface renders the name alone in that case. */
|
|
@@ -119,13 +119,16 @@ export function slugFromPrompt(prompt) {
|
|
|
119
119
|
* ladder rather than pinning a concrete model id keeps naming working for a
|
|
120
120
|
* user who never configured Anthropic: an OpenAI default provider resolves to
|
|
121
121
|
* its own light rung. `CRTR_NAME_MODEL` still overrides. */
|
|
122
|
-
function
|
|
123
|
-
const override = process.env[
|
|
122
|
+
export function lightModel(overrideEnv) {
|
|
123
|
+
const override = overrideEnv === undefined ? undefined : process.env[overrideEnv];
|
|
124
124
|
if (override !== undefined && override.trim() !== '')
|
|
125
125
|
return override.trim();
|
|
126
126
|
const ladders = modelLadders();
|
|
127
127
|
return stripThinkingSuffix(ladders[defaultProvider(ladders)].light);
|
|
128
128
|
}
|
|
129
|
+
function nameModel() {
|
|
130
|
+
return lightModel('CRTR_NAME_MODEL');
|
|
131
|
+
}
|
|
129
132
|
/** The pi argv for a headless TEXT request (issue titles). Stripped down (no
|
|
130
133
|
* tools, session, context files, extensions, skills, templates, themes) so
|
|
131
134
|
* it's fast and side-effect free. */
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
// and were imported into the handlers from there; Stage B-3 relocated them here
|
|
9
9
|
// so the CLI leaves' import graph reaches no canvas state store (spec §1/§10).
|
|
10
10
|
import { copyFileSync, existsSync, mkdtempSync, readFileSync, rmSync } from 'node:fs';
|
|
11
|
+
import { readJsonIfExists } from '../fs-utils.js';
|
|
11
12
|
import { tmpdir } from 'node:os';
|
|
12
13
|
import { basename, join } from 'node:path';
|
|
13
14
|
import { InputError } from '../io.js';
|
|
@@ -17,6 +18,7 @@ import { SessionManager } from './broker-sdk.js';
|
|
|
17
18
|
import { piAgentDir } from './package-health.js';
|
|
18
19
|
import { BUILTIN_SLASH_COMMANDS } from './pi-vendored.js';
|
|
19
20
|
import { cycleAwareMessages } from './session-cycles.js';
|
|
21
|
+
import { normalizeToolGroupSummaryRecord } from '../../shared/tool-groups.js';
|
|
20
22
|
import { ModelRegistry, ModelRuntime } from '@earendil-works/pi-coding-agent';
|
|
21
23
|
import { PoolCredentialStore } from '../pool-credential-store.js';
|
|
22
24
|
/** A session `.jsonl` records only `{ provider, modelId }` — pi never persists a
|
|
@@ -131,6 +133,15 @@ function readIfPresent(path) {
|
|
|
131
133
|
return null;
|
|
132
134
|
}
|
|
133
135
|
}
|
|
136
|
+
function readToolGroupSummaries(nodeId) {
|
|
137
|
+
try {
|
|
138
|
+
const raw = readJsonIfExists(join(jobDir(nodeId), 'tool-summaries.json'));
|
|
139
|
+
return normalizeToolGroupSummaryRecord(raw);
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
return {};
|
|
143
|
+
}
|
|
144
|
+
}
|
|
134
145
|
/** Reconstruct a persisted session without launching its broker. Backs the
|
|
135
146
|
* machine-readable snapshot endpoint and the human transcript render. */
|
|
136
147
|
export async function readNodeSnapshot(nodeId) {
|
|
@@ -175,6 +186,10 @@ export async function readNodeSnapshot(nodeId) {
|
|
|
175
186
|
// process state (last setStatus/setWidget/setTitle) and is not persisted,
|
|
176
187
|
// so an offline read has none.
|
|
177
188
|
display: { statuses: {}, widgets: {}, title: undefined },
|
|
189
|
+
// Sidecar summaries survive broker exit so a dormant transcript receives
|
|
190
|
+
// the same completed-group data as a live welcome snapshot. Malformed or
|
|
191
|
+
// absent sidecars are deliberately ignored: tool calls remain visible.
|
|
192
|
+
toolGroupSummaries: readToolGroupSummaries(nodeId),
|
|
178
193
|
};
|
|
179
194
|
return {
|
|
180
195
|
nodeId,
|
|
@@ -4,27 +4,12 @@ export interface MissingPackage {
|
|
|
4
4
|
/** Absolute path it resolved to (which does not exist). */
|
|
5
5
|
resolved: string;
|
|
6
6
|
}
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
* dependency range in crouter's package.json. The bundled copy is the floor
|
|
14
|
-
* required by crouter's generated `hl inbox toggle` binding. */
|
|
15
|
-
export declare function bundledHumanloopVersion(): string | null;
|
|
16
|
-
/** Read the PATH-visible `hl` package directly. Spawning `npm ls -g` here
|
|
17
|
-
* makes every front-door boot pay for npm's global dependency-tree scan; a
|
|
18
|
-
* linked development install can make that scan take many seconds. The real
|
|
19
|
-
* executable points into the package for both ordinary and npm-linked installs,
|
|
20
|
-
* so walking upward to its package.json is authoritative for the CLI crtr will
|
|
21
|
-
* actually invoke. */
|
|
22
|
-
export declare function globalHumanloopVersion(): string | null;
|
|
23
|
-
export declare function globalHumanloopHealth(): GlobalHumanloopHealth;
|
|
24
|
-
/** A non-fatal action-oriented diagnostic for a missing, unreadable, or stale
|
|
25
|
-
* global `hl` executable. */
|
|
26
|
-
export declare function globalHumanloopWarning(): string | null;
|
|
27
|
-
export declare function globalHumanloopInstallCommand(): string;
|
|
7
|
+
/** A non-fatal, action-oriented diagnostic for an unprovisioned managed
|
|
8
|
+
* renderer — the one remaining out-of-tree dependency. Deliberately calls
|
|
9
|
+
* `isRendererReady()`, NOT `ensureRenderer()`: this runs on the front-door boot
|
|
10
|
+
* path and at crtrd startup, where a `uv pip install` (up to 180s) must never
|
|
11
|
+
* happen. Readiness is a handful of fs stats, no subprocess. */
|
|
12
|
+
export declare function rendererWarning(): string | null;
|
|
28
13
|
/**
|
|
29
14
|
* The pi agent config dir (`~/.pi/agent`, or `$PI_CODING_AGENT_DIR`) — a local
|
|
30
15
|
* reimplementation of pi's `getAgentDir()`. Reimplemented (not imported) ON
|