@north-light/crouter 0.3.164 → 0.3.165
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 +6 -6
- package/dist/build-root.js +12 -13
- package/dist/builtin-memory/00-runtime-base.md +3 -4
- package/dist/builtin-memory/01-spine/01-no-manager.md +1 -1
- package/dist/builtin-memory/02-lifecycle/00-terminal.md +2 -0
- package/dist/builtin-memory/04-orchestration-kernel.md +16 -18
- package/dist/builtin-memory/05-kinds/advisor/00-base.md +0 -2
- package/dist/builtin-memory/05-kinds/advisor/01-orchestrator.md +3 -9
- package/dist/builtin-memory/05-kinds/developer/00-base.md +1 -3
- package/dist/builtin-memory/05-kinds/developer/01-orchestrator.md +2 -10
- package/dist/builtin-memory/05-kinds/explore/00-base.md +2 -2
- package/dist/builtin-memory/05-kinds/explore/01-orchestrator.md +0 -2
- package/dist/builtin-memory/05-kinds/general/00-base.md +3 -5
- package/dist/builtin-memory/05-kinds/general/01-orchestrator.md +0 -4
- package/dist/builtin-memory/05-kinds/plan/01-orchestrator.md +1 -3
- package/dist/builtin-memory/05-kinds/plan/reviewers/00-base.md +12 -0
- package/dist/builtin-memory/05-kinds/plan/reviewers/architecture-fit.md +0 -2
- package/dist/builtin-memory/05-kinds/plan/reviewers/code-smells.md +0 -2
- package/dist/builtin-memory/05-kinds/plan/reviewers/pattern-consistency.md +0 -2
- package/dist/builtin-memory/05-kinds/plan/reviewers/requirements-coverage.md +1 -1
- package/dist/builtin-memory/05-kinds/plan/reviewers/security.md +0 -2
- package/dist/builtin-memory/05-kinds/review/00-base.md +0 -2
- package/dist/builtin-memory/05-kinds/review/01-orchestrator.md +1 -3
- package/dist/builtin-memory/05-kinds/spec/00-base.md +1 -1
- package/dist/builtin-memory/05-kinds/spec/01-orchestrator.md +2 -4
- package/dist/builtin-memory/05-kinds/spec/requirements.md +1 -1
- package/dist/builtin-memory/advisor/council.md +40 -0
- package/dist/builtin-memory/design.md +8 -11
- package/dist/builtin-memory/development.md +6 -9
- package/dist/builtin-memory/internal/INDEX.md +4 -5
- package/dist/builtin-memory/internal/agent-shaping.md +5 -7
- package/dist/builtin-memory/internal/examples/imessage-assistant.md +3 -3
- package/dist/builtin-memory/internal/marketplaces.md +13 -14
- package/dist/builtin-memory/internal/nodes-and-canvas.md +4 -4
- package/dist/builtin-memory/internal/plugins.md +61 -45
- package/dist/builtin-memory/planning.md +4 -7
- package/dist/builtin-memory/spec.md +9 -12
- package/dist/builtin-memory/wedged-child-on-runaway-bash.md +8 -22
- package/dist/cli.js +1 -1
- package/dist/clients/attach/__tests__/attach-keybindings.test.js +17 -4
- package/dist/clients/attach/__tests__/context-message.test.js +31 -20
- package/dist/clients/attach/__tests__/crtr-output.test.js +39 -30
- package/dist/clients/attach/render/chat-view.d.ts +20 -20
- package/dist/clients/attach/render/chat-view.js +42 -54
- package/dist/clients/attach/render/{frozen-history.d.ts → condensed-history.d.ts} +1 -18
- package/dist/clients/attach/render/condensed-history.js +60 -0
- package/dist/clients/attach/render/context-message.js +9 -14
- package/dist/clients/attach/session/bindings.d.ts +5 -3
- package/dist/clients/attach/session/bindings.js +7 -13
- package/dist/clients/attach/session/keys.d.ts +2 -0
- package/dist/clients/attach/session/keys.js +36 -37
- package/dist/clients/attach/session/profile-files.d.ts +8 -0
- package/dist/clients/attach/session/profile-files.js +157 -0
- package/dist/clients/attach/viewer.js +525 -525
- package/dist/commands/node.js +2 -2
- package/dist/commands/pkg/plugin-inspect.js +6 -7
- package/dist/commands/pkg/plugin-manage.d.ts +1 -1
- package/dist/commands/pkg/plugin-manage.js +131 -19
- package/dist/commands/pkg/plugin.js +2 -2
- package/dist/commands/pkg.js +6 -11
- package/dist/commands/profile/env.js +3 -3
- package/dist/commands/sys/config.js +17 -76
- package/dist/commands/sys/doctor.js +5 -91
- package/dist/commands/sys/setup-wizard.d.ts +9 -11
- package/dist/commands/sys/setup-wizard.js +47 -81
- package/dist/core/__tests__/base-worker-prompt.test.js +18 -21
- package/dist/core/__tests__/command-plugins-surfaces.test.js +39 -5
- package/dist/core/__tests__/command-plugins.test.js +36 -16
- package/dist/core/__tests__/review-model-floor.test.js +2 -2
- package/dist/core/__tests__/tmux-surface.test.js +10 -1
- package/dist/core/command-manifests/manifest.d.ts +24 -0
- package/dist/core/{configured-clis → command-manifests}/manifest.js +21 -25
- package/dist/core/command-manifests/registry.d.ts +1 -2
- package/dist/core/command-manifests/registry.js +2 -2
- package/dist/core/command-manifests/schema.d.ts +11 -13
- package/dist/core/command-manifests/schema.js +53 -192
- package/dist/core/command-plugins/compose.d.ts +0 -6
- package/dist/core/command-plugins/compose.js +28 -75
- package/dist/core/command-plugins/discovery.d.ts +25 -58
- package/dist/core/command-plugins/discovery.js +152 -259
- package/dist/core/command-plugins/endpoint.d.ts +24 -0
- package/dist/core/command-plugins/endpoint.js +48 -0
- package/dist/core/command-plugins/store.d.ts +16 -0
- package/dist/core/command-plugins/store.js +64 -0
- package/dist/core/command-plugins/{adapter.d.ts → transport/exec-invoke.d.ts} +3 -3
- package/dist/core/command-plugins/{adapter.js → transport/exec-invoke.js} +4 -4
- package/dist/core/{configured-clis/fetch.d.ts → command-plugins/transport/http-fetch.d.ts} +9 -18
- package/dist/core/{configured-clis/fetch.js → command-plugins/transport/http-fetch.js} +15 -35
- package/dist/core/{configured-clis/invoker.d.ts → command-plugins/transport/http-invoke.d.ts} +7 -7
- package/dist/core/{configured-clis/invoker.js → command-plugins/transport/http-invoke.js} +21 -23
- package/dist/core/command.d.ts +8 -9
- package/dist/core/command.js +6 -9
- package/dist/core/config.js +6 -10
- package/dist/core/env-name.d.ts +6 -0
- package/dist/core/env-name.js +9 -0
- package/dist/core/io.d.ts +1 -1
- package/dist/core/keybindings/__tests__/resolve.test.js +40 -3
- package/dist/core/keybindings/attach-control.d.ts +37 -0
- package/dist/core/keybindings/attach-control.js +38 -0
- package/dist/core/keybindings/catalog.d.ts +5 -4
- package/dist/core/keybindings/catalog.js +16 -8
- package/dist/core/keybindings/index.d.ts +1 -0
- package/dist/core/keybindings/index.js +1 -0
- package/dist/core/keybindings/types.d.ts +1 -1
- package/dist/core/preview-registry.js +41 -74
- package/dist/core/runtime/bearings.d.ts +2 -5
- package/dist/core/runtime/bearings.js +2 -5
- package/dist/core/runtime/front-door.d.ts +1 -1
- package/dist/core/runtime/front-door.js +2 -2
- package/dist/core/runtime/kickoff.d.ts +3 -3
- package/dist/core/runtime/kickoff.js +4 -3
- package/dist/core/runtime/situational-context.d.ts +1 -1
- package/dist/core/runtime/situational-context.js +1 -1
- package/dist/core/runtime/spawn.js +9 -9
- package/dist/core/runtime/tmux.js +29 -2
- package/dist/core/scope.d.ts +0 -5
- package/dist/core/scope.js +0 -10
- package/dist/core/user-settings.d.ts +193 -0
- package/dist/core/user-settings.js +252 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/pi-extensions/canvas-stophook.js +3 -2
- package/dist/shared/generated-context.d.ts +34 -0
- package/dist/shared/generated-context.js +98 -0
- package/dist/types.d.ts +23 -16
- package/dist/types.js +3 -14
- package/dist/web-client/assets/{index-NIuSCOHM.js → index-BMTOGuOZ.js} +19 -19
- package/dist/web-client/assets/index-DvA6Zw-R.css +2 -0
- package/dist/web-client/index.html +2 -2
- package/dist/web-client/sw.js +1 -1
- package/docs/public-api.md +1 -0
- package/package.json +1 -1
- package/runtime.lock.json +2 -2
- package/dist/builtin-memory/05-kinds/product/00-base.md +0 -25
- package/dist/builtin-memory/05-kinds/product/01-orchestrator.md +0 -15
- package/dist/builtin-memory/05-kinds/product/teardown.md +0 -15
- package/dist/builtin-memory/internal/workflow-codification.md +0 -82
- package/dist/builtin-memory/product.md +0 -80
- package/dist/clients/attach/render/frozen-history.js +0 -100
- package/dist/commands/pkg/cli-inspect.d.ts +0 -17
- package/dist/commands/pkg/cli-inspect.js +0 -190
- package/dist/commands/pkg/cli-manage.d.ts +0 -3
- package/dist/commands/pkg/cli-manage.js +0 -206
- package/dist/commands/pkg/cli.d.ts +0 -1
- package/dist/commands/pkg/cli.js +0 -14
- package/dist/core/configured-clis/cache.d.ts +0 -16
- package/dist/core/configured-clis/cache.js +0 -57
- package/dist/core/configured-clis/compose.d.ts +0 -14
- package/dist/core/configured-clis/compose.js +0 -60
- package/dist/core/configured-clis/discovery.d.ts +0 -47
- package/dist/core/configured-clis/discovery.js +0 -173
- package/dist/core/configured-clis/manifest.d.ts +0 -24
- package/dist/core/configured-clis/registration.d.ts +0 -40
- package/dist/core/configured-clis/registration.js +0 -201
- 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
|
|
3
|
-
type
|
|
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' |
|
|
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.
|
|
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
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
|
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:
|
|
1908
|
-
* bullets `name
|
|
1909
|
-
* enough to cross the prose threshold, and since it
|
|
1910
|
-
* it renders as a bare unlabeled paragraph (see
|
|
1911
|
-
*
|
|
1912
|
-
*
|
|
1913
|
-
*
|
|
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:
|
|
1928
|
-
* an `N updated:` table
|
|
1929
|
-
*
|
|
1930
|
-
*
|
|
1931
|
-
*
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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:
|
|
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`
|
|
2014
|
-
* top-level
|
|
2015
|
-
* match, `manifest` isn't valid JSON, or the docs count
|
|
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('&', '&').replaceAll('"', '"').replaceAll('<', '<').replaceAll('>', '>');
|
|
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);
|
|
@@ -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/
|
|
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/
|
|
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
|
-
//
|
|
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
|
|
17
|
-
*
|
|
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
|
|
65
|
-
*
|
|
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. */
|
|
@@ -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
|
|
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
|
|
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
|
-
//
|
|
376
|
-
//
|
|
377
|
-
//
|
|
378
|
-
//
|
|
379
|
-
//
|
|
380
|
-
//
|
|
381
|
-
//
|
|
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 !== '') {
|
|
@@ -11,7 +11,7 @@ import { spawnSync } from 'node:child_process';
|
|
|
11
11
|
import { readFileSync, rmSync } from 'node:fs';
|
|
12
12
|
import { homedir } from 'node:os';
|
|
13
13
|
import { join } from 'node:path';
|
|
14
|
-
import { BINDING_CATALOG, formatGesture, resolveUserKeybindings, } from '../keybindings/index.js';
|
|
14
|
+
import { ATTACH_CONTROL_BINDINGS, BINDING_CATALOG, encodeAttachControlInput, formatGesture, resolveUserKeybindings, } from '../keybindings/index.js';
|
|
15
15
|
import { bundledPiCommandForShell } from './pi-cli.js';
|
|
16
16
|
import { surfaceTmuxStyleArgs } from './surface-bg.js';
|
|
17
17
|
import { inboxToggleTmuxCommand } from '@crouton-kit/humanloop';
|
|
@@ -554,6 +554,13 @@ function menuActionCommand(action) {
|
|
|
554
554
|
menu: `send-keys -t '#{pane_id}' ${shellQuote(keys)}`,
|
|
555
555
|
};
|
|
556
556
|
}
|
|
557
|
+
case 'literal-input': {
|
|
558
|
+
const input = escapeTmuxFormats(action.input);
|
|
559
|
+
return {
|
|
560
|
+
argv: ['send-keys', '-l', input],
|
|
561
|
+
menu: `send-keys -l -t '#{pane_id}' ${shellQuote(input)}`,
|
|
562
|
+
};
|
|
563
|
+
}
|
|
557
564
|
case 'command': return chordCommand(action.run);
|
|
558
565
|
case 'direct': return directCommand(action.run);
|
|
559
566
|
case 'popup': return chordCommand(action.run, true);
|
|
@@ -640,6 +647,22 @@ function resolvedMenuActions(bindings) {
|
|
|
640
647
|
if (entry !== undefined)
|
|
641
648
|
entries.set(id, entry);
|
|
642
649
|
}
|
|
650
|
+
for (const { menuId, actionId } of ATTACH_CONTROL_BINDINGS) {
|
|
651
|
+
const definition = BINDING_CATALOG.find((candidate) => candidate.id === actionId);
|
|
652
|
+
if (definition === undefined)
|
|
653
|
+
throw new Error(`missing attach binding definition ${actionId}`);
|
|
654
|
+
entries.set(menuId, {
|
|
655
|
+
description: definition.name.toLowerCase(),
|
|
656
|
+
action: { kind: 'literal-input', input: encodeAttachControlInput(actionId) },
|
|
657
|
+
});
|
|
658
|
+
}
|
|
659
|
+
const attachItems = boundMenuItems(ATTACH_CONTROL_BINDINGS.map(({ menuId }) => menuId), entries, bindings);
|
|
660
|
+
if (attachItems.length > 0) {
|
|
661
|
+
entries.set('crtr.tmux.menu.attach', {
|
|
662
|
+
description: 'attach ›',
|
|
663
|
+
action: { kind: 'submenu', title: ' attach ', items: attachItems },
|
|
664
|
+
});
|
|
665
|
+
}
|
|
643
666
|
const showItems = boundMenuItems([
|
|
644
667
|
'crtr.tmux.menu.metadata',
|
|
645
668
|
'crtr.tmux.menu.context',
|
|
@@ -687,6 +710,7 @@ function menuItems(bindings, entries) {
|
|
|
687
710
|
'crtr.tmux.menu.view-settings',
|
|
688
711
|
]));
|
|
689
712
|
addGroup('Current node', boundItems([
|
|
713
|
+
'crtr.tmux.menu.attach',
|
|
690
714
|
'crtr.tmux.menu.background-bash',
|
|
691
715
|
'crtr.tmux.menu.file-review',
|
|
692
716
|
'crtr.tmux.menu.pin',
|
|
@@ -865,8 +889,11 @@ export function installTmuxBindings(bindings = resolveUserKeybindings()) {
|
|
|
865
889
|
for (const definition of BINDING_CATALOG) {
|
|
866
890
|
if (definition.pair?.field !== 'menu')
|
|
867
891
|
continue;
|
|
892
|
+
const paired = BINDING_CATALOG.find((candidate) => candidate.id === definition.pair?.pairedId);
|
|
893
|
+
if (paired?.pair?.field !== 'global')
|
|
894
|
+
continue;
|
|
868
895
|
const menuId = definition.id;
|
|
869
|
-
const globalId =
|
|
896
|
+
const globalId = paired.id;
|
|
870
897
|
const entry = menuActions.get(menuId);
|
|
871
898
|
const command = entry === undefined ? null : menuActionCommand(entry.action);
|
|
872
899
|
if (command === null)
|