@north-light/crouter 0.3.164 → 0.3.166

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/dist/build-root.d.ts +6 -6
  2. package/dist/build-root.js +12 -13
  3. package/dist/builtin-memory/00-runtime-base.md +3 -4
  4. package/dist/builtin-memory/01-spine/01-no-manager.md +1 -1
  5. package/dist/builtin-memory/02-lifecycle/00-terminal.md +2 -0
  6. package/dist/builtin-memory/04-orchestration-kernel.md +16 -18
  7. package/dist/builtin-memory/05-kinds/advisor/00-base.md +0 -2
  8. package/dist/builtin-memory/05-kinds/advisor/01-orchestrator.md +3 -9
  9. package/dist/builtin-memory/05-kinds/developer/00-base.md +1 -3
  10. package/dist/builtin-memory/05-kinds/developer/01-orchestrator.md +2 -10
  11. package/dist/builtin-memory/05-kinds/explore/00-base.md +2 -2
  12. package/dist/builtin-memory/05-kinds/explore/01-orchestrator.md +0 -2
  13. package/dist/builtin-memory/05-kinds/general/00-base.md +3 -5
  14. package/dist/builtin-memory/05-kinds/general/01-orchestrator.md +0 -4
  15. package/dist/builtin-memory/05-kinds/plan/01-orchestrator.md +1 -3
  16. package/dist/builtin-memory/05-kinds/plan/reviewers/00-base.md +12 -0
  17. package/dist/builtin-memory/05-kinds/plan/reviewers/architecture-fit.md +0 -2
  18. package/dist/builtin-memory/05-kinds/plan/reviewers/code-smells.md +0 -2
  19. package/dist/builtin-memory/05-kinds/plan/reviewers/pattern-consistency.md +0 -2
  20. package/dist/builtin-memory/05-kinds/plan/reviewers/requirements-coverage.md +1 -1
  21. package/dist/builtin-memory/05-kinds/plan/reviewers/security.md +0 -2
  22. package/dist/builtin-memory/05-kinds/review/00-base.md +0 -2
  23. package/dist/builtin-memory/05-kinds/review/01-orchestrator.md +1 -3
  24. package/dist/builtin-memory/05-kinds/spec/00-base.md +1 -1
  25. package/dist/builtin-memory/05-kinds/spec/01-orchestrator.md +2 -4
  26. package/dist/builtin-memory/05-kinds/spec/requirements.md +1 -1
  27. package/dist/builtin-memory/advisor/council.md +40 -0
  28. package/dist/builtin-memory/design.md +8 -11
  29. package/dist/builtin-memory/development.md +6 -9
  30. package/dist/builtin-memory/internal/INDEX.md +4 -5
  31. package/dist/builtin-memory/internal/agent-shaping.md +5 -7
  32. package/dist/builtin-memory/internal/examples/imessage-assistant.md +3 -3
  33. package/dist/builtin-memory/internal/marketplaces.md +13 -14
  34. package/dist/builtin-memory/internal/nodes-and-canvas.md +4 -4
  35. package/dist/builtin-memory/internal/plugins.md +61 -45
  36. package/dist/builtin-memory/planning.md +4 -7
  37. package/dist/builtin-memory/spec.md +9 -12
  38. package/dist/builtin-memory/wedged-child-on-runaway-bash.md +8 -22
  39. package/dist/cli.js +1 -1
  40. package/dist/clients/attach/__tests__/attach-keybindings.test.js +17 -4
  41. package/dist/clients/attach/__tests__/context-message.test.js +62 -22
  42. package/dist/clients/attach/__tests__/crtr-output.test.js +39 -30
  43. package/dist/clients/attach/render/chat-view.d.ts +20 -20
  44. package/dist/clients/attach/render/chat-view.js +40 -54
  45. package/dist/clients/attach/render/{frozen-history.d.ts → condensed-history.d.ts} +1 -18
  46. package/dist/clients/attach/render/condensed-history.js +60 -0
  47. package/dist/clients/attach/render/context-message.d.ts +1 -1
  48. package/dist/clients/attach/render/context-message.js +18 -41
  49. package/dist/clients/attach/session/bindings.d.ts +5 -3
  50. package/dist/clients/attach/session/bindings.js +7 -13
  51. package/dist/clients/attach/session/keys.d.ts +2 -0
  52. package/dist/clients/attach/session/keys.js +36 -37
  53. package/dist/clients/attach/session/profile-files.d.ts +8 -0
  54. package/dist/clients/attach/session/profile-files.js +157 -0
  55. package/dist/clients/attach/viewer.js +528 -529
  56. package/dist/commands/node-context.js +3 -2
  57. package/dist/commands/node.js +2 -2
  58. package/dist/commands/pkg/plugin-inspect.js +6 -7
  59. package/dist/commands/pkg/plugin-manage.d.ts +1 -1
  60. package/dist/commands/pkg/plugin-manage.js +131 -19
  61. package/dist/commands/pkg/plugin.js +2 -2
  62. package/dist/commands/pkg.js +6 -11
  63. package/dist/commands/profile/env.js +3 -3
  64. package/dist/commands/sys/config.js +17 -76
  65. package/dist/commands/sys/doctor.js +5 -91
  66. package/dist/commands/sys/setup-wizard.d.ts +9 -11
  67. package/dist/commands/sys/setup-wizard.js +47 -81
  68. package/dist/core/__tests__/base-worker-prompt.test.js +18 -21
  69. package/dist/core/__tests__/command-plugins-surfaces.test.js +39 -5
  70. package/dist/core/__tests__/command-plugins.test.js +75 -16
  71. package/dist/core/__tests__/review-model-floor.test.js +2 -2
  72. package/dist/core/__tests__/tmux-surface.test.js +10 -1
  73. package/dist/core/command-manifests/manifest.d.ts +24 -0
  74. package/dist/core/{configured-clis → command-manifests}/manifest.js +28 -25
  75. package/dist/core/command-manifests/registry.d.ts +1 -2
  76. package/dist/core/command-manifests/registry.js +2 -2
  77. package/dist/core/command-manifests/schema.d.ts +11 -13
  78. package/dist/core/command-manifests/schema.js +53 -192
  79. package/dist/core/command-plugins/compose.d.ts +0 -6
  80. package/dist/core/command-plugins/compose.js +32 -75
  81. package/dist/core/command-plugins/discovery.d.ts +25 -58
  82. package/dist/core/command-plugins/discovery.js +171 -261
  83. package/dist/core/command-plugins/endpoint.d.ts +24 -0
  84. package/dist/core/command-plugins/endpoint.js +48 -0
  85. package/dist/core/command-plugins/store.d.ts +16 -0
  86. package/dist/core/command-plugins/store.js +64 -0
  87. package/dist/core/command-plugins/{adapter.d.ts → transport/exec-invoke.d.ts} +3 -3
  88. package/dist/core/command-plugins/{adapter.js → transport/exec-invoke.js} +4 -4
  89. package/dist/core/{configured-clis/fetch.d.ts → command-plugins/transport/http-fetch.d.ts} +9 -18
  90. package/dist/core/{configured-clis/fetch.js → command-plugins/transport/http-fetch.js} +15 -35
  91. package/dist/core/{configured-clis/invoker.d.ts → command-plugins/transport/http-invoke.d.ts} +7 -7
  92. package/dist/core/{configured-clis/invoker.js → command-plugins/transport/http-invoke.js} +21 -23
  93. package/dist/core/command.d.ts +8 -9
  94. package/dist/core/command.js +6 -9
  95. package/dist/core/config.js +6 -10
  96. package/dist/core/env-name.d.ts +6 -0
  97. package/dist/core/env-name.js +9 -0
  98. package/dist/core/io.d.ts +1 -1
  99. package/dist/core/keybindings/__tests__/resolve.test.js +40 -3
  100. package/dist/core/keybindings/attach-control.d.ts +37 -0
  101. package/dist/core/keybindings/attach-control.js +38 -0
  102. package/dist/core/keybindings/catalog.d.ts +5 -4
  103. package/dist/core/keybindings/catalog.js +16 -8
  104. package/dist/core/keybindings/index.d.ts +1 -0
  105. package/dist/core/keybindings/index.js +1 -0
  106. package/dist/core/keybindings/types.d.ts +1 -1
  107. package/dist/core/preview-registry.js +41 -74
  108. package/dist/core/runtime/bearings.d.ts +2 -5
  109. package/dist/core/runtime/bearings.js +2 -5
  110. package/dist/core/runtime/broker.js +3 -2
  111. package/dist/core/runtime/front-door.d.ts +1 -1
  112. package/dist/core/runtime/front-door.js +2 -2
  113. package/dist/core/runtime/kickoff.d.ts +3 -3
  114. package/dist/core/runtime/kickoff.js +4 -3
  115. package/dist/core/runtime/lifecycle.js +2 -2
  116. package/dist/core/runtime/situational-context.d.ts +1 -1
  117. package/dist/core/runtime/situational-context.js +1 -1
  118. package/dist/core/runtime/spawn.js +9 -9
  119. package/dist/core/runtime/tmux.js +29 -2
  120. package/dist/core/scope.d.ts +0 -5
  121. package/dist/core/scope.js +0 -10
  122. package/dist/core/user-settings.d.ts +193 -0
  123. package/dist/core/user-settings.js +252 -0
  124. package/dist/index.d.ts +4 -0
  125. package/dist/index.js +3 -0
  126. package/dist/pi-extensions/canvas-stophook.js +3 -2
  127. package/dist/prompts/review.js +4 -2
  128. package/dist/shared/generated-context.d.ts +34 -0
  129. package/dist/shared/generated-context.js +98 -0
  130. package/dist/types.d.ts +23 -16
  131. package/dist/types.js +3 -14
  132. package/dist/web-client/assets/index-BgLGlZ3D.css +2 -0
  133. package/dist/web-client/assets/{index-NIuSCOHM.js → index-CmoNqcCv.js} +19 -19
  134. package/dist/web-client/index.html +2 -2
  135. package/dist/web-client/sw.js +1 -1
  136. package/docs/public-api.md +1 -0
  137. package/package.json +1 -1
  138. package/runtime.lock.json +2 -2
  139. package/dist/builtin-memory/05-kinds/product/00-base.md +0 -25
  140. package/dist/builtin-memory/05-kinds/product/01-orchestrator.md +0 -15
  141. package/dist/builtin-memory/05-kinds/product/teardown.md +0 -15
  142. package/dist/builtin-memory/internal/workflow-codification.md +0 -82
  143. package/dist/builtin-memory/product.md +0 -80
  144. package/dist/clients/attach/render/frozen-history.js +0 -100
  145. package/dist/commands/pkg/cli-inspect.d.ts +0 -17
  146. package/dist/commands/pkg/cli-inspect.js +0 -190
  147. package/dist/commands/pkg/cli-manage.d.ts +0 -3
  148. package/dist/commands/pkg/cli-manage.js +0 -206
  149. package/dist/commands/pkg/cli.d.ts +0 -1
  150. package/dist/commands/pkg/cli.js +0 -14
  151. package/dist/core/configured-clis/cache.d.ts +0 -16
  152. package/dist/core/configured-clis/cache.js +0 -57
  153. package/dist/core/configured-clis/compose.d.ts +0 -14
  154. package/dist/core/configured-clis/compose.js +0 -60
  155. package/dist/core/configured-clis/discovery.d.ts +0 -47
  156. package/dist/core/configured-clis/discovery.js +0 -173
  157. package/dist/core/configured-clis/manifest.d.ts +0 -24
  158. package/dist/core/configured-clis/registration.d.ts +0 -40
  159. package/dist/core/configured-clis/registration.js +0 -201
  160. package/dist/web-client/assets/index-CqLKj8Xu.css +0 -2
@@ -1,6 +1,7 @@
1
1
  import type { BindingDefinition, SafetyRequirement } from './types.js';
2
- type TmuxMenuAction = 'open' | 'show' | 'view-settings' | 'fold-tools' | 'metadata' | 'promote' | 'resume' | 'fork' | 'demote' | 'detach' | 'close-subtree' | 'background-bash' | 'file-review' | 'pin' | 'reload-viewer' | 'context' | 'providers' | 'graph' | 'focus-manager' | 'copy-id' | 'issues';
3
- type TmuxMenuEntryAction = Exclude<TmuxMenuAction, 'open'> | `issue.${'idea' | 'bug'}`;
2
+ import type { AttachBindingId, AttachMenuBindingId } from './attach-control.js';
3
+ type TmuxMenuAction = 'open' | 'attach' | 'show' | 'view-settings' | 'fold-tools' | 'metadata' | 'promote' | 'resume' | 'fork' | 'demote' | 'detach' | 'close-subtree' | 'background-bash' | 'file-review' | 'pin' | 'reload-viewer' | 'context' | 'providers' | 'graph' | 'focus-manager' | 'copy-id' | 'issues';
4
+ type TmuxMenuEntryAction = Exclude<TmuxMenuAction, 'open' | 'attach'> | `issue.${'idea' | 'bug'}`;
4
5
  type GraphAction = 'down' | 'up' | 'first' | 'last' | 'collapse-or-manager' | 'expand-or-child' | 'focus' | 'revive' | 'focus-manager' | 'close-subtree' | 'dismiss';
5
6
  type InboxAction = 'down' | 'up' | 'open' | 'reply' | 'react' | 'filter' | 'refresh' | 'connect-linkedin' | 'connect-gmail' | 'quit' | 'submit-reply' | 'cancel' | 'reaction-previous' | 'reaction-next' | 'submit-reaction';
6
7
  type LinkedinAction = Exclude<InboxAction, 'filter' | 'connect-linkedin' | 'connect-gmail'>;
@@ -9,8 +10,8 @@ type ProfileMenuAction = 'up' | 'down' | 'select' | 'accept-default' | 'abort' |
9
10
  type SetupAction = 'cancel' | 'tab-next' | 'tab-previous' | 'open' | 'list-down' | 'list-up' | 'toggle' | 'details' | 'advance' | 'cell-previous' | 'cell-next';
10
11
  type SetupKeybindingAction = 'edit' | 'commit-edit' | 'cancel-edit' | 'unbind' | 'reset-row' | 'reset-all' | 'save' | 'discard' | 'page-up' | 'page-down' | 'filter' | 'filter-delete' | 'filter-clear';
11
12
  type SetupModelsAction = 'open' | 'commit' | 'cancel' | 'scope-next';
12
- export type BindingId = `crtr.tmux.menu.${TmuxMenuAction}` | `crtr.tmux.menu.issue.${'idea' | 'bug'}` | `crtr.tmux.menu-global.${TmuxMenuEntryAction}` | `crtr.tmux.node.${'next' | 'previous'}` | `crtr.tmux.view.${'next' | 'previous'}` | 'crtr.tmux.inbox.toggle' | `crtr.attach.${'detach' | 'clear-or-detach' | 'graph.toggle' | 'model-ladder.next' | 'model-ladder.previous' | 'command.inspect' | 'file-review'}` | 'crtr.mode.cycle' | `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}`;
13
- export declare const BINDING_CATALOG: readonly [BindingDefinition<"crtr.tmux.menu.open">, ...(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.detach"> | BindingDefinition<"crtr.attach.clear-or-detach"> | BindingDefinition<"crtr.attach.graph.toggle"> | BindingDefinition<"crtr.attach.model-ladder.next"> | BindingDefinition<"crtr.attach.model-ladder.previous"> | BindingDefinition<"crtr.attach.command.inspect"> | BindingDefinition<"crtr.attach.file-review"> | BindingDefinition<"crtr.mode.cycle"> | 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.7" | "crtr.profile.menu.slot.6">)[], 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' | 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">];
14
15
  export declare const BINDING_IDS: ReadonlySet<string>;
15
16
  export declare const SAFETY_REQUIREMENTS: readonly SafetyRequirement[];
16
17
  export {};
@@ -20,6 +20,12 @@ function menuEntry(action, name, description, defaults, contexts) {
20
20
  b(globalId, 'Global tmux', name, description, [], 'tmux-global-action', ['tmux.root'], undefined, { field: 'global', pairedId: menuId }),
21
21
  ];
22
22
  }
23
+ function attachEntry(menuId, actionId, name, description, menuDefault, directDefaults) {
24
+ return [
25
+ b(menuId, 'Attach', name, description, [menuDefault], 'tmux-menu-selector', ['tmux.menu.attach'], undefined, { field: 'menu', pairedId: actionId }),
26
+ b(actionId, 'Attach', name, description, directDefaults, 'host-global', ATTACH_CONTEXTS, undefined, { field: 'direct', pairedId: menuId }),
27
+ ];
28
+ }
23
29
  const ATTACH_CONTEXTS = ['attach', 'graph', 'graph.confirm'];
24
30
  const VIEW_CONTEXTS = [
25
31
  'view.canvas', 'view.chat', 'view.git-pr',
@@ -36,6 +42,7 @@ const SETUP_CANCEL_CONTEXTS = [
36
42
  const SETUP_TAB_CONTEXTS = ['setup.login', 'setup.list', 'setup.keybindings', 'setup.models'];
37
43
  export const BINDING_CATALOG = Object.freeze([
38
44
  b('crtr.tmux.menu.open', 'Global tmux', 'Open crouter menu', 'Open the crouter action menu.', ['alt+c'], 'host-global', ['tmux.root']),
45
+ b('crtr.tmux.menu.attach', 'Global tmux', 'Attach actions', 'Open the attach-viewer action submenu.', ['a'], 'tmux-menu-selector', ['tmux.menu']),
39
46
  ...menuEntry('promote', 'Promote node', 'Promote the focused node to orchestrator.', ['o'], ['tmux.menu']),
40
47
  ...menuEntry('resume', 'Resume node', 'Open the node resume picker.', ['r'], ['tmux.menu']),
41
48
  ...menuEntry('fork', 'Fork node', 'Fork the focused node into an independent idle root.', ['f'], ['tmux.menu']),
@@ -63,14 +70,15 @@ export const BINDING_CATALOG = Object.freeze([
63
70
  b('crtr.tmux.inbox.toggle', 'Global tmux', 'Toggle inbox', 'Open or close the human inbox popup.', ['alt+i'], 'host-global', ['tmux.root']),
64
71
  b('crtr.tmux.view.next', 'Global tmux', 'Next view', 'Focus the next view.', ['alt+v > ]'], 'tmux-sequence', ['tmux.root']),
65
72
  b('crtr.tmux.view.previous', 'Global tmux', 'Previous view', 'Focus the previous view.', ['alt+v > ['], 'tmux-sequence', ['tmux.root']),
66
- b('crtr.attach.detach', 'Attach', 'Detach', 'Detach from the node.', ['ctrl+d'], 'host-global', ATTACH_CONTEXTS),
67
- b('crtr.attach.clear-or-detach', 'Attach', 'Clear or detach', 'Clear input or detach when input is empty.', ['ctrl+c'], 'host-global', ATTACH_CONTEXTS),
68
- b('crtr.attach.graph.toggle', 'Attach', 'Toggle graph', 'Open or close the graph overlay.', ['alt+g'], 'host-global', ATTACH_CONTEXTS),
69
- b('crtr.attach.model-ladder.next', 'Attach', 'Next model ladder', 'Move to the next model ladder rung.', ['alt+m'], 'host-global', ATTACH_CONTEXTS),
70
- b('crtr.attach.model-ladder.previous', 'Attach', 'Previous model ladder', 'Move to the previous model ladder rung.', ['alt+shift+m'], 'host-global', ATTACH_CONTEXTS),
71
- b('crtr.attach.command.inspect', 'Attach', 'Inspect loaded command', 'Open the loaded slash command’s expanded prompt.', ['alt+shift+h'], 'host-global', ATTACH_CONTEXTS),
72
- b('crtr.attach.file-review', 'Attach', 'Review a file', 'Open a line-anchored review of a file named in the transcript.', ['alt+shift+r'], 'host-global', ATTACH_CONTEXTS),
73
- b('crtr.mode.cycle', 'Attach', 'Cycle mode', 'Cycle the active agent mode.', ['alt+shift+p'], 'host-global', ATTACH_CONTEXTS),
73
+ ...attachEntry('crtr.tmux.menu.attach.detach', 'crtr.attach.detach', 'Detach', 'Detach from the node.', 'd', ['ctrl+d']),
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
+ ...attachEntry('crtr.tmux.menu.attach.mode-cycle', 'crtr.mode.cycle', 'Cycle mode', 'Cycle the active agent mode.', 'p', ['alt+shift+p']),
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.model-ladder.next', 'crtr.attach.model-ladder.next', 'Next model ladder', 'Move to the next model ladder rung.', ']', ['alt+m']),
78
+ ...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
+ ...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
+ ...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
+ ...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', []),
74
82
  b('crtr.graph.down', 'GRAPH', 'Move down', 'Move to the next graph row.', ['j'], 'terminal', ['graph']),
75
83
  b('crtr.graph.up', 'GRAPH', 'Move up', 'Move to the previous graph row.', ['k'], 'terminal', ['graph']),
76
84
  b('crtr.graph.first', 'GRAPH', 'First row', 'Move to the first graph row.', ['g'], 'terminal', ['graph']),
@@ -3,5 +3,6 @@ export { GestureSyntaxError, KeybindingValidationError, normalizeGesture, normal
3
3
  export { canonicalTerminalStroke, formatBinding, formatGesture, formatStroke, matchesPiTuiInput, matchesTerminalInput, type PiTuiMatcher, type RawTerminalInput, } from './match.js';
4
4
  export { inboxOpenHint, inboxOpenInstruction, inboxPopupHint, inboxShortcut, } from './inbox.js';
5
5
  export { backgroundBashHint, backgroundBashShortcut, } from './background-bash.js';
6
+ export { ATTACH_CONTROL_BINDINGS, decodeAttachControlInput, encodeAttachControlInput, extractAttachControlInput, type AttachBindingId, type AttachMenuBindingId, type ExtractedAttachControlInput, } from './attach-control.js';
6
7
  export { KeybindingConcurrentEditError, persistUserKeybindings, type PersistedKeybindings, type PersistKeybindingsOptions, } from './persistence.js';
7
8
  export type { BindingDefinition, BindingInputKind, BindingPair, BindingResolution, BindingSafetyCapability, EffectiveBinding, KeybindingDiagnostic, KeybindingDiagnosticCode, SafetyRequirement, SparseKeybindingOverrides, } from './types.js';
@@ -3,4 +3,5 @@ export { GestureSyntaxError, KeybindingValidationError, normalizeGesture, normal
3
3
  export { canonicalTerminalStroke, formatBinding, formatGesture, formatStroke, matchesPiTuiInput, matchesTerminalInput, } from './match.js';
4
4
  export { inboxOpenHint, inboxOpenInstruction, inboxPopupHint, inboxShortcut, } from './inbox.js';
5
5
  export { backgroundBashHint, backgroundBashShortcut, } from './background-bash.js';
6
+ export { ATTACH_CONTROL_BINDINGS, decodeAttachControlInput, encodeAttachControlInput, extractAttachControlInput, } from './attach-control.js';
6
7
  export { KeybindingConcurrentEditError, persistUserKeybindings, } from './persistence.js';
@@ -1,6 +1,6 @@
1
1
  export type BindingInputKind = 'terminal' | 'tmux-sequence' | 'tmux-menu-selector' | 'tmux-global-action' | 'host-global';
2
2
  export interface BindingPair {
3
- readonly field: 'menu' | 'global';
3
+ readonly field: 'menu' | 'global' | 'direct';
4
4
  readonly pairedId: string;
5
5
  }
6
6
  export type BindingSafetyCapability = 'dismiss-modal' | 'leave-screen' | 'save-keybindings';
@@ -1592,7 +1592,7 @@ function summarizeNodeConfig(text) {
1592
1592
  ];
1593
1593
  }
1594
1594
  /** Compact an inspection result into a primary state line plus a bounded set
1595
- * of muted facts. Profile, configured-CLI, and config reads all use this
1595
+ * of muted facts. Profile and config reads both use this
1596
1596
  * rather than each inventing a bespoke card grammar. */
1597
1597
  const INSPECTION_DETAIL_CAP = 5;
1598
1598
  function inspectionGlance(head, details) {
@@ -1690,46 +1690,6 @@ function summarizeProfileEnvList(text) {
1690
1690
  return null;
1691
1691
  return inspectionGlance({ text: `${count} env var${count === 1 ? '' : 's'}`, tone: count === 0 ? 'muted' : 'plain' }, [id, ...names]);
1692
1692
  }
1693
- function summarizePkgCliList(text) {
1694
- const total = parseIntBullet(text, 'total');
1695
- const rows = parseTableRows(text, 'items');
1696
- if (total === null || rows === null || (total > 0 && rows.length === 0))
1697
- return null;
1698
- if (total === 0)
1699
- return inspectionGlance({ text: '0 configured CLIs', tone: 'muted' }, []);
1700
- const details = [];
1701
- for (const row of rows) {
1702
- const name = row['name'];
1703
- const scope = row['scope'];
1704
- const state = row['manifest_state'];
1705
- const commands = row['top_level_commands'];
1706
- if (name === undefined || name === '' || scope === undefined || scope === '' || (state !== 'stored' && state !== 'absent') || commands === undefined)
1707
- return null;
1708
- details.push(`${name} · ${scope} · ${state}${commands === '' ? '' : ` · ${commands}`}`);
1709
- }
1710
- return inspectionGlance({ text: `${total} configured CLI${total === 1 ? '' : 's'}` }, details);
1711
- }
1712
- function summarizePkgCliShow(text) {
1713
- const name = /^- name:\s*(\S+)\s*$/m.exec(text)?.[1];
1714
- const scope = /^- scope:\s*(\S+)\s*$/m.exec(text)?.[1];
1715
- const state = /^- manifest_state:\s*(stored|absent)\s*$/m.exec(text)?.[1];
1716
- const issuesStart = text.search(/^0 issues\.$|^\d+ issues:$/m);
1717
- if (name === undefined || scope === undefined || state === undefined || issuesStart === -1)
1718
- return null;
1719
- const commands = parseTableRows(text.slice(0, issuesStart), 'commands');
1720
- const issueText = text.slice(issuesStart);
1721
- const issues = parseTableRows(issueText, 'issues');
1722
- if (commands === null || issues === null)
1723
- return null;
1724
- if (commands.some((row) => row['command'] === undefined || row['command'] === '' || row['paths'] === undefined) || issues.some((row) => row['code'] === undefined || row['code'] === ''))
1725
- return null;
1726
- const details = [`${commands.length} command${commands.length === 1 ? '' : 's'} · ${issues.length} issue${issues.length === 1 ? '' : 's'}`];
1727
- details.push(...commands.map((row) => row['command']));
1728
- details.push(...issues.map((row) => `issue: ${row['code']}`));
1729
- return inspectionGlance({ text: `${name} · ${scope} · ${state}`, tone: state === 'stored' ? 'plain' : 'warning' }, details);
1730
- }
1731
- /** `canvas config show` already emits one concise line. List only earns a
1732
- * card once multiple targets produce a real multiline roster. */
1733
1693
  function summarizeCanvasConfigList(text) {
1734
1694
  const rows = text.split('\n').filter((line) => line.trim() !== '');
1735
1695
  if (rows.length < 2)
@@ -1904,36 +1864,31 @@ function summarizePkgMarketRemove(text) {
1904
1864
  return [{ text: `removed marketplace ${name}`, tone: 'success' }];
1905
1865
  }
1906
1866
  /** `crtr pkg plugin install` (pluginInstall.run, src/commands/pkg/
1907
- * plugin-manage.ts:280) has no custom `render`; the generic renderer
1908
- * bullets `name`/`scope` (always short) then `path` — almost always long
1909
- * enough to cross the prose threshold, and since it's the SOLE prose field
1910
- * it renders as a bare unlabeled paragraph (see soloProseAfterBullets),
1911
- * not a labeled one. Falls back to a `- path:` bullet for the rare
1912
- * short-path case. Returns null when `name`/`scope` aren't present as
1913
- * bullets — an error/unrecognized shape (path is a muted aside, not
1914
- * required for a recognized digest). */
1867
+ * plugin-manage.ts:418) has no custom `render`; the generic renderer
1868
+ * bullets `name`, `scope`, and optional `transport`, then `path` — almost
1869
+ * always long enough to cross the prose threshold, and since it is the sole
1870
+ * prose field it renders as a bare unlabeled paragraph (see
1871
+ * soloProseAfterBullets). Returns null when `name`/`scope` aren't present as
1872
+ * bullets — an error/unrecognized shape (path is a muted aside, not required
1873
+ * for a recognized digest). */
1915
1874
  function summarizePkgPluginInstall(text) {
1916
1875
  const name = /^- name:\s*(\S+)\s*$/m.exec(text)?.[1];
1917
1876
  const scope = /^- scope:\s*(\S+)\s*$/m.exec(text)?.[1];
1877
+ const transport = /^- transport:\s*(exec|http)\s*$/m.exec(text)?.[1];
1918
1878
  if (name === undefined || scope === undefined)
1919
1879
  return null;
1920
1880
  const path = readFieldFlexible(text, 'path') ?? soloProseAfterBullets(text);
1921
1881
  return [
1922
- { text: `installed ${name}`, tone: 'success' },
1882
+ { text: `installed ${name}${transport !== undefined ? ` · ${transport}` : ''}`, tone: 'success' },
1923
1883
  { text: path !== undefined ? `${scope} · ${path}` : scope, tone: 'muted' },
1924
1884
  ];
1925
1885
  }
1926
1886
  /** `crtr pkg plugin update` (pluginUpdate.run, src/commands/pkg/
1927
- * plugin-manage.ts:349) has no custom `render`; the generic renderer emits
1928
- * an `N updated:` table (columns `name,updated,sha`) — one row when
1929
- * `--name` targets a single plugin, one row per installed plugin
1930
- * otherwise. There is no version field anywhere in this output (unlike
1931
- * command-icons.md's hypothetical version-delta wording) — `sha` (short,
1932
- * 7 chars) is the only content available to show. Returns null when the
1933
- * table doesn't match this shape, or when any row's `updated` cell isn't
1934
- * exactly `true`/`false` (the multi-row loop mirrors the single-row
1935
- * validation above — a malformed cell must not be silently counted as
1936
- * "already current"). */
1887
+ * plugin-manage.ts:571) has no custom `render`; the generic renderer emits
1888
+ * an `N updated:` table. HTTP rows carry `transport=http` and no sha because
1889
+ * they replace commands.json after refetch; git rows retain their optional
1890
+ * `sha`. Returns null when the table doesn't match this shape or an `updated`
1891
+ * cell is not exactly `true`/`false`. */
1937
1892
  function summarizePkgPluginUpdate(text) {
1938
1893
  const rows = parseTableRows(text, 'updated');
1939
1894
  if (rows === null)
@@ -1944,31 +1899,40 @@ function summarizePkgPluginUpdate(text) {
1944
1899
  const row = rows[0];
1945
1900
  const name = row['name'];
1946
1901
  const updated = row['updated'];
1947
- if (name === undefined || (updated !== 'true' && updated !== 'false'))
1902
+ const transport = row['transport'];
1903
+ if (name === undefined || (updated !== 'true' && updated !== 'false') || (transport !== undefined && transport !== '' && transport !== 'exec' && transport !== 'http'))
1948
1904
  return null;
1949
1905
  const sha = (row['sha'] ?? '').slice(0, 7);
1950
1906
  const lines = [
1951
- updated === 'true' ? { text: `updated ${name}`, tone: 'success' } : { text: `${name} already current`, tone: 'muted' },
1907
+ updated === 'true' ? { text: `${transport === 'http' ? 'refreshed' : 'updated'} ${name}`, tone: 'success' } : { text: `${name} already current`, tone: 'muted' },
1952
1908
  ];
1909
+ if (transport !== undefined && transport !== '')
1910
+ lines.push({ text: transport, tone: 'muted' });
1953
1911
  if (sha !== '')
1954
1912
  lines.push({ text: sha, tone: 'muted' });
1955
1913
  return lines;
1956
1914
  }
1957
1915
  let updatedCount = 0;
1916
+ let httpCount = 0;
1958
1917
  for (const row of rows) {
1959
1918
  const updated = row['updated'];
1919
+ const transport = row['transport'];
1960
1920
  if (updated !== 'true' && updated !== 'false')
1961
1921
  return null;
1922
+ if (transport !== undefined && transport !== '' && transport !== 'exec' && transport !== 'http')
1923
+ return null;
1962
1924
  if (updated === 'true')
1963
1925
  updatedCount++;
1926
+ if (transport === 'http')
1927
+ httpCount++;
1964
1928
  }
1965
1929
  const current = rows.length - updatedCount;
1966
- return [{ text: `${updatedCount} updated · ${current} already current` }];
1930
+ return [{ text: `${updatedCount} updated · ${current} already current${httpCount > 0 ? ` · ${httpCount} HTTP` : ''}` }];
1967
1931
  }
1968
1932
  const PKG_LIST_NAME_CAP = 8;
1969
1933
  /** `crtr pkg plugin list` (pluginList.run, src/commands/pkg/
1970
- * plugin-inspect.ts:12) bullets `- total: N` then an `N items:` table
1971
- * (columns `name,scope,version,enabled,source_marketplace,path`).
1934
+ * plugin-inspect.ts:14) bullets `- total: N` then an `N items:` table
1935
+ * (columns `name,scope,version,enabled,transport,source_marketplace,path`).
1972
1936
  * `enabled`/name counts are read from the RETURNED page only — with the
1973
1937
  * default 50-per-page limit this matches `total` in practice, but a
1974
1938
  * narrower `--limit` would undercount enabled/shown names against the
@@ -1990,11 +1954,12 @@ function summarizePkgPluginList(text) {
1990
1954
  for (const row of rows) {
1991
1955
  const name = row['name'];
1992
1956
  const enabled = row['enabled'];
1993
- if (name === undefined || name === '' || (enabled !== 'true' && enabled !== 'false'))
1957
+ const transport = row['transport'];
1958
+ if (name === undefined || name === '' || (enabled !== 'true' && enabled !== 'false') || (transport !== 'exec' && transport !== 'http' && transport !== ''))
1994
1959
  return null;
1995
1960
  if (enabled === 'true')
1996
1961
  enabledCount++;
1997
- names.push(name);
1962
+ names.push(`${name}${transport === '' ? '' : ` (${transport})`}`);
1998
1963
  }
1999
1964
  const shown = names.slice(0, PKG_LIST_NAME_CAP);
2000
1965
  const remaining = names.length - shown.length;
@@ -2005,14 +1970,15 @@ function summarizePkgPluginList(text) {
2005
1970
  ];
2006
1971
  }
2007
1972
  /** `crtr pkg plugin show` (pluginShow.run, src/commands/pkg/
2008
- * plugin-inspect.ts:76) bullets `name`/`scope`/`path`/`enabled` (path is
1973
+ * plugin-inspect.ts:88) bullets `name`/`scope`/`path`/`enabled` (path is
2009
1974
  * usually short here — a plugin dir, not a nested interaction path — so
2010
1975
  * stays a bullet) then `manifest` — an OBJECT, so core/render.ts's
2011
1976
  * scalarStr always JSON.stringifies it to a bullet regardless of length
2012
1977
  * (isProse only ever triggers for strings) — then an `N docs:` table (or
2013
- * `0 docs.`). `version` is read from the parsed manifest JSON, not a
2014
- * top-level field. Returns null when `name`/`enabled`/`manifest` don't
2015
- * match, `manifest` isn't valid JSON, or the docs count line is missing. */
1978
+ * `0 docs.`). `version` and `transport.kind` are read from the parsed
1979
+ * manifest JSON, not top-level fields. Returns null when `name`/`enabled`/
1980
+ * `manifest` don't match, `manifest` isn't valid JSON, or the docs count
1981
+ * line is missing. */
2016
1982
  function summarizePkgPluginShow(text) {
2017
1983
  const name = /^- name:\s*(\S+)\s*$/m.exec(text)?.[1];
2018
1984
  const enabledMatch = /^- enabled:\s*(true|false)\s*$/m.exec(text);
@@ -2029,12 +1995,15 @@ function summarizePkgPluginShow(text) {
2029
1995
  const version = manifest !== null && typeof manifest === 'object' && 'version' in manifest && typeof manifest.version === 'string'
2030
1996
  ? manifest.version
2031
1997
  : undefined;
1998
+ const transport = manifest !== null && typeof manifest === 'object' && 'transport' in manifest && manifest.transport !== null && typeof manifest.transport === 'object' && ['exec', 'http'].includes(manifest.transport.kind)
1999
+ ? manifest.transport.kind
2000
+ : undefined;
2032
2001
  const docsCount = /^0 docs\.$/m.test(text) ? 0 : Number(/^(\d+) docs:$/m.exec(text)?.[1] ?? NaN);
2033
2002
  if (Number.isNaN(docsCount))
2034
2003
  return null;
2035
2004
  const enabled = enabledMatch[1] === 'true';
2036
2005
  return [
2037
- { text: `${name}${version !== undefined ? `@${version}` : ''} · ${enabled ? 'enabled' : 'disabled'}`, tone: enabled ? 'success' : 'muted' },
2006
+ { text: `${name}${version !== undefined ? `@${version}` : ''}${transport !== undefined ? ` · ${transport}` : ''} · ${enabled ? 'enabled' : 'disabled'}`, tone: enabled ? 'success' : 'muted' },
2038
2007
  { text: `${docsCount} substrate doc${docsCount === 1 ? '' : 's'}`, tone: 'muted' },
2039
2008
  ];
2040
2009
  }
@@ -2797,8 +2766,6 @@ const SUMMARIZERS = [
2797
2766
  { path: 'profile show', run: summarizeProfileShow },
2798
2767
  { path: 'profile default show', run: summarizeProfileDefaultShow },
2799
2768
  { path: 'profile env list', run: summarizeProfileEnvList },
2800
- { path: 'pkg cli list', run: summarizePkgCliList },
2801
- { path: 'pkg cli show', run: summarizePkgCliShow },
2802
2769
  { path: 'canvas config list', run: summarizeCanvasConfigList },
2803
2770
  { path: 'sys config get', run: summarizeSysConfigGet },
2804
2771
  { path: 'sys config path', run: summarizeSysConfigPath },
@@ -1,15 +1,12 @@
1
1
  import { type Cron } from '../canvas/index.js';
2
+ /** The bearings custom type is shared with every attached renderer. */
3
+ export { CONTEXT_INTRO_CUSTOM_TYPE } from '../../shared/generated-context.js';
2
4
  /** The `<project_context>` block — the `<environment>` snapshot only: a
3
5
  * host/runtime line (platform, hostname, node version, tmux-or-not — the
4
6
  * headless engine's own process env, which its bash tools inherit), the cwd
5
7
  * dir listing, and git status/worktrees. Project guidance lives in the
6
8
  * document substrate, so this wrapper stays environment-only. It always emits
7
9
  * because the environment snapshot is always present. Exported for testing. */
8
- /** The `customType` stamped on a node's injected bearings message. Lives here,
9
- * beside the builder, because BOTH delivery paths need it: the context-intro
10
- * pi-extension (session_start, the cold path) and the warm-pool claim's live
11
- * delivery. It is also the idempotency discriminator a later revive matches. */
12
- export declare const CONTEXT_INTRO_CUSTOM_TYPE = "crtr-context";
13
10
  export declare function buildProjectContextBlock(cwd: string): string;
14
11
  /** The context-directory note — names the path INLINE (no XML attribute, so it
15
12
  * never scopes a sibling block) and frames the dir as durable, shared scratch.
@@ -48,6 +48,8 @@ import { cadenceDisplay } from '../wake.js';
48
48
  import { renderKnowledgeBlock, renderWorkspaceOpenDocs } from '../substrate/index.js';
49
49
  import { loadProfileManifest } from '../profiles/manifest.js';
50
50
  import { situationalContextBlock } from './situational-context.js';
51
+ /** The bearings custom type is shared with every attached renderer. */
52
+ export { CONTEXT_INTRO_CUSTOM_TYPE } from '../../shared/generated-context.js';
51
53
  function escapeAttribute(value) {
52
54
  return value.replaceAll('&', '&amp;').replaceAll('"', '&quot;').replaceAll('<', '&lt;').replaceAll('>', '&gt;');
53
55
  }
@@ -144,11 +146,6 @@ function parseWorktrees(lines) {
144
146
  * dir listing, and git status/worktrees. Project guidance lives in the
145
147
  * document substrate, so this wrapper stays environment-only. It always emits
146
148
  * because the environment snapshot is always present. Exported for testing. */
147
- /** The `customType` stamped on a node's injected bearings message. Lives here,
148
- * beside the builder, because BOTH delivery paths need it: the context-intro
149
- * pi-extension (session_start, the cold path) and the warm-pool claim's live
150
- * delivery. It is also the idempotency discriminator a later revive matches. */
151
- export const CONTEXT_INTRO_CUSTOM_TYPE = 'crtr-context';
152
149
  export function buildProjectContextBlock(cwd) {
153
150
  const envLines = directoryListingLines(cwd);
154
151
  const git = gitSnapshot(cwd);
@@ -475,8 +475,9 @@ export async function runBroker(nodeId, startupAt = process.hrtime.bigint(), sta
475
475
  });
476
476
  };
477
477
  // Defensive: any `crtr` child the engine/extensions spawn must inherit the
478
- // front-door recursion guard (runtime/CLAUDE.md fork-bomb invariant). The host
479
- // (T6) also sets this; we set it again so the broker is self-sufficient.
478
+ // front-door recursion guard (see
479
+ // src/core/runtime/.crouter/memory/INDEX.md). The host (T6) also sets this;
480
+ // setting it here keeps the broker self-sufficient.
480
481
  process.env[FRONT_DOOR_ENV] = '1';
481
482
  // A successful in-turn crtr command stamps this process id into its stop
482
483
  // signal, so a crash-revived broker cannot consume a prior broker's outcome.
@@ -10,7 +10,7 @@ export declare const FRONT_DOOR_ENV = "CRTR_FRONT_DOOR";
10
10
  * Takes NO command tree: it decides from argv plus the static `SUBTREE_NAMES`
11
11
  * list, so bare `crtr` never pays for assembling the full tree (measured 520ms
12
12
  * of the front door's ~1.6s — every subtree's module graph plus external
13
- * plugin/configured-CLI discovery, none of which a root boot reads). The one
13
+ * plugin/HTTP-transport plugin discovery, none of which a root boot reads). The one
14
14
  * case that genuinely needs external command names — a bare word that is also
15
15
  * an existing directory — builds the tree lazily, below. */
16
16
  export declare function maybeBootRoot(argv: string[]): Promise<boolean>;
@@ -101,7 +101,7 @@ export const FRONT_DOOR_ENV = 'CRTR_FRONT_DOOR';
101
101
  * Takes NO command tree: it decides from argv plus the static `SUBTREE_NAMES`
102
102
  * list, so bare `crtr` never pays for assembling the full tree (measured 520ms
103
103
  * of the front door's ~1.6s — every subtree's module graph plus external
104
- * plugin/configured-CLI discovery, none of which a root boot reads). The one
104
+ * plugin/HTTP-transport plugin discovery, none of which a root boot reads). The one
105
105
  * case that genuinely needs external command names — a bare word that is also
106
106
  * an existing directory — builds the tree lazily, below. */
107
107
  export async function maybeBootRoot(argv) {
@@ -138,7 +138,7 @@ export async function maybeBootRoot(argv) {
138
138
  return false;
139
139
  // A bare word that is an existing directory is the ONLY token shape that
140
140
  // could also be an EXTERNAL top-level command name (a command plugin or a
141
- // configured CLI) — a prompt carries whitespace and a front-door flag is
141
+ // HTTP-transport plugin) — a prompt carries whitespace and a front-door flag is
142
142
  // `-`-prefixed, and neither can name a command. Resolve the full tree only
143
143
  // for that collision check, keeping it off the bare-`crtr` boot path.
144
144
  if (looksLikeDir) {
@@ -1,5 +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
4
  /** The goal file — the prompt/task a node was spawned with, persisted at birth
4
5
  * so a fresh revive can re-read its mandate. */
5
6
  export declare function goalPath(nodeId: string): string;
@@ -13,9 +14,8 @@ export declare function writeGoal(nodeId: string, text: string): void;
13
14
  * the text was empty. Guarded so a later message never clobbers the mandate. */
14
15
  export declare function captureGoalIfAbsent(nodeId: string, text: string): boolean;
15
16
  /** Sentinel opening the fresh-revive kickoff message (see buildReviveKickoff).
16
- * The goal-capture extension skips any input starting with this so a kickoff
17
- * prompt is never mistaken for a user's first mandate. */
18
- export declare const REVIVE_KICKOFF_SENTINEL = "You have been revived fresh after a context refresh";
17
+ * The goal-capture extension and attached renderers share its pure definition,
18
+ * so the same exact contract controls both prompt exclusion and display. */
19
19
  /** Injected only when a broker cleanly persisted an aborted in-flight turn
20
20
  * before a daemon restart. The transcript already carries the full picture, so
21
21
  * this is a bare nudge — a longer explanation only destabilizes the resume. */
@@ -24,6 +24,8 @@ import { readRoadmap, roadmapPath } from './roadmap.js';
24
24
  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
+ import { REVIVE_KICKOFF_SENTINEL } from '../../shared/generated-context.js';
28
+ export { REVIVE_KICKOFF_SENTINEL } from '../../shared/generated-context.js';
27
29
  // ---------------------------------------------------------------------------
28
30
  // Companion context files: the goal (the spawning mandate) and the one-shot
29
31
  // yield message (a note from the prior self to the revived self).
@@ -61,9 +63,8 @@ export function captureGoalIfAbsent(nodeId, text) {
61
63
  return true;
62
64
  }
63
65
  /** Sentinel opening the fresh-revive kickoff message (see buildReviveKickoff).
64
- * The goal-capture extension skips any input starting with this so a kickoff
65
- * prompt is never mistaken for a user's first mandate. */
66
- export const REVIVE_KICKOFF_SENTINEL = 'You have been revived fresh after a context refresh';
66
+ * The goal-capture extension and attached renderers share its pure definition,
67
+ * so the same exact contract controls both prompt exclusion and display. */
67
68
  /** Injected only when a broker cleanly persisted an aborted in-flight turn
68
69
  * before a daemon restart. The transcript already carries the full picture, so
69
70
  * this is a bare nudge — a longer explanation only destabilizes the resume. */
@@ -33,8 +33,8 @@
33
33
  // Layering note: lifecycle.ts is runtime, but it is the canvas write surface's
34
34
  // `transition` verb (the only writer of status+intent), so it owns its atomic
35
35
  // row UPDATE directly via openDb — the one sanctioned exception to "only
36
- // canvas.ts touches the db" (see canvas/CLAUDE.md), exactly as db.ts's backfill
37
- // is the sanctioned exception for a data migration.
36
+ // canvas.ts touches the db" (see src/core/canvas/.crouter/memory/INDEX.md),
37
+ // exactly as db.ts's backfill is the sanctioned exception for a data migration.
38
38
  import { openDb, getNode, cancelCronsOnWake } from '../canvas/index.js';
39
39
  const ANY = '*';
40
40
  /** The supervised statuses — a live node the daemon watches. */
@@ -1,6 +1,6 @@
1
1
  /** The `customType` stamped on the hidden custom message the inbox watcher
2
2
  * sends for an existing node's situational-context update. */
3
- export declare const SITUATIONAL_CONTEXT_CUSTOM_TYPE = "crtr-situational-context";
3
+ export { SITUATIONAL_CONTEXT_CUSTOM_TYPE } from '../../shared/generated-context.js';
4
4
  /** Upsert the node's current situational context (replace, not append) — the
5
5
  * one sanctioned writer for the sidecar. No-op for blank text, so a caller
6
6
  * can pass through an optional/empty value with no guard at the call site. */
@@ -21,7 +21,7 @@ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
21
21
  import { situationalContextPath, nodeDir } from '../canvas/paths.js';
22
22
  /** The `customType` stamped on the hidden custom message the inbox watcher
23
23
  * sends for an existing node's situational-context update. */
24
- export const SITUATIONAL_CONTEXT_CUSTOM_TYPE = 'crtr-situational-context';
24
+ export { SITUATIONAL_CONTEXT_CUSTOM_TYPE } from '../../shared/generated-context.js';
25
25
  /** Upsert the node's current situational context (replace, not append) — the
26
26
  * one sanctioned writer for the sidecar. No-op for blank text, so a caller
27
27
  * can pass through an optional/empty value with no guard at the call site. */
@@ -30,6 +30,7 @@ import { beginBootFaultAttempt } from './fault.js';
30
30
  import { piSessionsRoot } from './pi-vendored.js';
31
31
  import { headlessBrokerHost } from './host.js';
32
32
  import { ensureDaemon } from '../../daemon/manage.js';
33
+ import { readConfig } from '../config.js';
33
34
  // ---------------------------------------------------------------------------
34
35
  // Shared broker-launch wrapper — catch launch/preflight failures at the call
35
36
  // site, mark the node crashed, then rethrow a clear error.
@@ -371,15 +372,14 @@ export async function spawnChildPrepared(opts, beforeBrokerLaunch) {
371
372
  }
372
373
  }
373
374
  }
374
- else if (!root && spawner !== null) {
375
- // A managed child is normally born headless (no viewer). But when a HUMAN is
376
- // actively watching the spawner in a tmux viewer pane, pop the child's viewer
377
- // open beside it so the human sees background work start immediately instead of
378
- // having to hunt for it. The broker is headless (TMUX stripped in broker.ts), so
379
- // we can't read $TMUX — instead we find the spawner's live viewer pane from the
380
- // focus registry (focusOf prunes a dead pane and returns null) and split beside
381
- // it. No viewer ⇒ nobody is watching ⇒ stay headless as before. Best-effort:
382
- // never fail a spawn on viewer placement.
375
+ else if (!root && spawner !== null && readConfig('user').auto_open_child_viewers) {
376
+ // When enabled, a managed child opens beside a HUMAN actively watching
377
+ // its spawner. Turning the setting off leaves every child headless until
378
+ // someone explicitly focuses or attaches it. The broker is headless
379
+ // (TMUX stripped in broker.ts), so we can't read $TMUX — instead we find
380
+ // the spawner's live viewer pane from the focus registry (focusOf prunes
381
+ // a dead pane and returns null) and split beside it. No viewer ⇒ nobody is
382
+ // watching ⇒ stay headless. Best-effort: never fail a spawn on placement.
383
383
  try {
384
384
  const parentViewer = focusOf(spawner);
385
385
  if (parentViewer !== null && parentViewer.pane !== null && parentViewer.pane !== '') {