@aragon-agent/cli 0.6.38 → 0.6.39

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 (156) hide show
  1. package/CHANGELOG.md +2523 -2326
  2. package/README.md +3614 -3173
  3. package/dist/agent/controller.d.ts +142 -1
  4. package/dist/agent/controller.js +171 -3
  5. package/dist/agent/reducer.d.ts +41 -1
  6. package/dist/agent/reducer.js +25 -0
  7. package/dist/agent/system-prompt.d.ts +14 -0
  8. package/dist/agent/system-prompt.js +5 -0
  9. package/dist/cli.js +85 -27
  10. package/dist/commands/builtins.js +13 -1
  11. package/dist/commands/keys-command.d.ts +23 -0
  12. package/dist/commands/keys-command.js +38 -0
  13. package/dist/commands/registry.d.ts +39 -0
  14. package/dist/commands/task-command.d.ts +39 -0
  15. package/dist/commands/task-command.js +102 -0
  16. package/dist/config/cli-commands.d.ts +23 -0
  17. package/dist/config/cli-commands.js +36 -0
  18. package/dist/config/env.js +17 -4
  19. package/dist/config/load.js +6 -1
  20. package/dist/config/schema.d.ts +43 -4
  21. package/dist/config/schema.js +31 -5
  22. package/dist/config/store.js +17 -2
  23. package/dist/diagnostics/doctor.d.ts +9 -0
  24. package/dist/diagnostics/doctor.js +34 -0
  25. package/dist/diagnostics/info.d.ts +71 -0
  26. package/dist/diagnostics/info.js +91 -5
  27. package/dist/exec/bridge/caller-tools.d.ts +96 -0
  28. package/dist/exec/bridge/caller-tools.js +213 -0
  29. package/dist/exec/bridge/decisions.d.ts +78 -0
  30. package/dist/exec/bridge/decisions.js +116 -0
  31. package/dist/exec/bridge/human-answers.d.ts +38 -0
  32. package/dist/exec/bridge/human-answers.js +164 -0
  33. package/dist/exec/bridge/limits.d.ts +68 -0
  34. package/dist/exec/bridge/limits.js +68 -0
  35. package/dist/exec/bridge/ndjson.d.ts +17 -0
  36. package/dist/exec/bridge/ndjson.js +83 -0
  37. package/dist/exec/bridge/pending.d.ts +70 -0
  38. package/dist/exec/bridge/pending.js +132 -0
  39. package/dist/exec/bridge/protocol.d.ts +346 -0
  40. package/dist/exec/bridge/protocol.js +256 -0
  41. package/dist/exec/bridge/server.d.ts +142 -0
  42. package/dist/exec/bridge/server.js +502 -0
  43. package/dist/exec/bridge/source.d.ts +58 -0
  44. package/dist/exec/bridge/source.js +145 -0
  45. package/dist/exec/bridge/writer.d.ts +26 -0
  46. package/dist/exec/bridge/writer.js +156 -0
  47. package/dist/exec/cli-commands.js +30 -2
  48. package/dist/exec/emitter.d.ts +16 -2
  49. package/dist/exec/emitter.js +26 -6
  50. package/dist/exec/events.d.ts +465 -10
  51. package/dist/exec/events.js +47 -1
  52. package/dist/exec/hooks/dispatch.d.ts +76 -0
  53. package/dist/exec/hooks/dispatch.js +169 -0
  54. package/dist/exec/hooks/index.d.ts +83 -0
  55. package/dist/exec/hooks/index.js +205 -0
  56. package/dist/exec/hooks/limits.d.ts +56 -0
  57. package/dist/exec/hooks/limits.js +49 -0
  58. package/dist/exec/hooks/registry.d.ts +49 -0
  59. package/dist/exec/hooks/registry.js +91 -0
  60. package/dist/exec/hooks/tool-wrapper.d.ts +94 -0
  61. package/dist/exec/hooks/tool-wrapper.js +154 -0
  62. package/dist/exec/hooks/turn.d.ts +61 -0
  63. package/dist/exec/hooks/turn.js +59 -0
  64. package/dist/exec/hooks/validate.d.ts +85 -0
  65. package/dist/exec/hooks/validate.js +310 -0
  66. package/dist/exec/index.d.ts +130 -4
  67. package/dist/exec/index.js +501 -10
  68. package/dist/exec/options.d.ts +124 -2
  69. package/dist/exec/options.js +413 -6
  70. package/dist/exec/permission.d.ts +9 -1
  71. package/dist/exec/permission.js +7 -1
  72. package/dist/exec/request/limits.d.ts +51 -0
  73. package/dist/exec/request/limits.js +49 -0
  74. package/dist/exec/request/scope.d.ts +106 -0
  75. package/dist/exec/request/scope.js +149 -0
  76. package/dist/exec/result/limits.d.ts +74 -0
  77. package/dist/exec/result/limits.js +72 -0
  78. package/dist/exec/result/prompt.d.ts +28 -0
  79. package/dist/exec/result/prompt.js +74 -0
  80. package/dist/exec/result/schema.d.ts +99 -0
  81. package/dist/exec/result/schema.js +464 -0
  82. package/dist/exec/result/sink.d.ts +56 -0
  83. package/dist/exec/result/sink.js +50 -0
  84. package/dist/exec/result/tool.d.ts +37 -0
  85. package/dist/exec/result/tool.js +118 -0
  86. package/dist/exec/runner.d.ts +395 -1
  87. package/dist/exec/runner.js +860 -8
  88. package/dist/exec/threads/aggregate.d.ts +34 -0
  89. package/dist/exec/threads/aggregate.js +30 -0
  90. package/dist/exec/threads/capacity.d.ts +23 -0
  91. package/dist/exec/threads/capacity.js +38 -0
  92. package/dist/exec/threads/dispatch-source.d.ts +60 -0
  93. package/dist/exec/threads/dispatch-source.js +106 -0
  94. package/dist/exec/threads/execute-threads.d.ts +53 -0
  95. package/dist/exec/threads/execute-threads.js +234 -0
  96. package/dist/exec/threads/gate.d.ts +42 -0
  97. package/dist/exec/threads/gate.js +81 -0
  98. package/dist/exec/threads/identity.d.ts +36 -0
  99. package/dist/exec/threads/identity.js +67 -0
  100. package/dist/exec/threads/interrupt.d.ts +29 -0
  101. package/dist/exec/threads/interrupt.js +79 -0
  102. package/dist/exec/threads/limits.d.ts +58 -0
  103. package/dist/exec/threads/limits.js +35 -0
  104. package/dist/exec/threads/outcome.d.ts +47 -0
  105. package/dist/exec/threads/outcome.js +26 -0
  106. package/dist/exec/threads/registry.d.ts +81 -0
  107. package/dist/exec/threads/registry.js +427 -0
  108. package/dist/exec/threads/runtime.d.ts +107 -0
  109. package/dist/exec/threads/runtime.js +523 -0
  110. package/dist/exec/threads/thread-source.d.ts +20 -0
  111. package/dist/exec/threads/thread-source.js +134 -0
  112. package/dist/fast/limits.d.ts +54 -0
  113. package/dist/fast/limits.js +54 -0
  114. package/dist/fast/summary-call.d.ts +72 -0
  115. package/dist/fast/summary-call.js +133 -0
  116. package/dist/fast/summary-prompt.d.ts +106 -0
  117. package/dist/fast/summary-prompt.js +320 -0
  118. package/dist/fast/task-summary-types.d.ts +66 -0
  119. package/dist/fast/task-summary-types.js +17 -0
  120. package/dist/logging/logger.d.ts +1 -1
  121. package/dist/proc/limits.d.ts +7 -0
  122. package/dist/proc/limits.js +7 -0
  123. package/dist/proc/output-streams.d.ts +50 -0
  124. package/dist/proc/output-streams.js +54 -0
  125. package/dist/team/runtime.d.ts +9 -0
  126. package/dist/team/runtime.js +8 -0
  127. package/dist/team/subagent.d.ts +15 -0
  128. package/dist/team/subagent.js +45 -1
  129. package/dist/tools/bash-tool.d.ts +10 -0
  130. package/dist/tools/bash-tool.js +71 -6
  131. package/dist/tools/index.d.ts +93 -1
  132. package/dist/tools/index.js +112 -3
  133. package/dist/tools/tool-gate.d.ts +100 -0
  134. package/dist/tools/tool-gate.js +87 -0
  135. package/dist/ui/App.js +224 -11
  136. package/dist/ui/Header.d.ts +28 -16
  137. package/dist/ui/Header.js +21 -19
  138. package/dist/ui/interaction-hints.js +6 -0
  139. package/dist/ui/layout/OverlayFrame.d.ts +18 -0
  140. package/dist/ui/layout/OverlayFrame.js +19 -4
  141. package/dist/ui/layout/header-hints.d.ts +55 -62
  142. package/dist/ui/layout/header-hints.js +59 -166
  143. package/dist/ui/layout/header-left.d.ts +115 -0
  144. package/dist/ui/layout/header-left.js +206 -0
  145. package/dist/ui/layout/shortcut-panel-layout.d.ts +191 -0
  146. package/dist/ui/layout/shortcut-panel-layout.js +321 -0
  147. package/dist/ui/layout/status-detail-layout.js +5 -1
  148. package/dist/ui/layout/task-summary-cell.d.ts +61 -0
  149. package/dist/ui/layout/task-summary-cell.js +65 -0
  150. package/dist/ui/overlays/HelpOverlay.d.ts +12 -0
  151. package/dist/ui/overlays/HelpOverlay.js +29 -2
  152. package/dist/ui/overlays/ShortcutPanel.d.ts +39 -0
  153. package/dist/ui/overlays/ShortcutPanel.js +106 -0
  154. package/dist/ui/shortcuts.d.ts +81 -0
  155. package/dist/ui/shortcuts.js +221 -0
  156. package/package.json +2 -2
@@ -0,0 +1,106 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * The keyboard drawer (tui-shortcut-drawer-and-task-summary §4.5).
4
+ *
5
+ * ASCII ONLY: `src/ui/**` is inside `glyphs.test.ts::inScope`.
6
+ *
7
+ * IT OWNS NO CHROME AND NO ARITHMETIC. `OverlayFrame` draws the frame, the
8
+ * window and the position indicator; `shortcut-panel-layout.ts` decides the
9
+ * columns, the rows and which window contains the cursor. This component adds two
10
+ * things and nothing else: its own key handling and the text-run colours. v1
11
+ * planned 260 lines that re-implemented the frame's windowing and clamping - a
12
+ * second source of truth for the one thing overlays have already been rewritten
13
+ * once to unify.
14
+ *
15
+ * IT DOES NOT REGISTER `Esc` AND DOES NOT TOUCH ANY `ctrl`/`meta` COMBINATION:
16
+ * `Esc` belongs to `App` (it closes every overlay and cancels the pending
17
+ * question/plan), and `Ctrl+G` is handled there too. Two listeners both acting on
18
+ * one byte is how a panel closes twice.
19
+ */
20
+ import { useMemo, useState } from 'react';
21
+ import { Text, useInput } from 'ink';
22
+ import { pickGlyphs } from '../glyphs.js';
23
+ import { OverlayFrame, overlayBodyRows, overlayPageSize } from '../layout/OverlayFrame.js';
24
+ import { buildShortcutRows, shortcutPanelWidth, } from '../layout/shortcut-panel-layout.js';
25
+ import { filterShortcuts, isAvailable, SHORTCUTS } from '../shortcuts.js';
26
+ /** Colour per tone. `dim` is `muted` plus the dim attribute, never a second colour. */
27
+ function toneOf(row, theme) {
28
+ if (row.tone === 'accent')
29
+ return { color: theme.accent };
30
+ if (row.tone === 'primary')
31
+ return { color: theme.primary };
32
+ if (row.tone === 'dim')
33
+ return { color: theme.muted, dimColor: true };
34
+ return { color: theme.muted };
35
+ }
36
+ export function ShortcutPanel(props) {
37
+ const { cols, maxRows, theme, caps, isActive, native, running } = props;
38
+ const glyphs = pickGlyphs(caps);
39
+ const [cursor, setCursor] = useState(0);
40
+ const entries = useMemo(() => filterShortcuts(SHORTCUTS, props.query ?? ''), [props.query]);
41
+ const bodyRows = overlayBodyRows(maxRows, cols);
42
+ const page = overlayPageSize(maxRows, cols);
43
+ const result = useMemo(() => buildShortcutRows({
44
+ cols,
45
+ rows: bodyRows,
46
+ cursor,
47
+ entries,
48
+ task: props.task,
49
+ entryAvailable: (entry) => isAvailable(entry, { native, running }),
50
+ unavailableReason: native ? 'this mode leaves it to the terminal' : 'a run is in flight',
51
+ glyphs: {
52
+ ellipsis: glyphs.ellipsis,
53
+ cursor: glyphs.cursor,
54
+ hrule: glyphs.hrule,
55
+ midDot: glyphs.midDot,
56
+ },
57
+ }), [cols, bodyRows, cursor, entries, props.task, native, running,
58
+ glyphs.ellipsis, glyphs.cursor, glyphs.hrule, glyphs.midDot]);
59
+ const last = Math.max(0, entries.length - 1);
60
+ useInput((input, key) => {
61
+ // `ctrl`/`meta` ARE NOT OURS: `Ctrl+G` closes this panel and `Ctrl+C` owns the
62
+ // exit ladder, both in `App`. Consuming them here would double-handle a byte.
63
+ if (key.ctrl || key.meta)
64
+ return;
65
+ if (key.upArrow || input === 'k') {
66
+ setCursor((value) => Math.max(0, value - 1));
67
+ return;
68
+ }
69
+ if (key.downArrow || input === 'j') {
70
+ setCursor((value) => Math.min(last, value + 1));
71
+ return;
72
+ }
73
+ // PAGING MOVES THE CURSOR, one page minus one row of overlap - the same rule
74
+ // `overlayPageSize` uses for every other overlay, so a page turn keeps a row of
75
+ // context. An independent offset would let the selected row - and the detail
76
+ // line that explains it - slide off screen (P1-7).
77
+ if (key.pageUp) {
78
+ setCursor((value) => Math.max(0, value - Math.max(1, page - 1)));
79
+ return;
80
+ }
81
+ if (key.pageDown) {
82
+ setCursor((value) => Math.min(last, value + Math.max(1, page - 1)));
83
+ return;
84
+ }
85
+ if (input === 'd') {
86
+ props.onToggleDetails();
87
+ return;
88
+ }
89
+ if (input === 'r') {
90
+ props.onRefresh();
91
+ }
92
+ }, { isActive });
93
+ const rows = result.rows.map((row, index) => (_jsx(Text, { wrap: "truncate", ...toneOf(row, theme), children: row.text }, `${row.kind}-${row.entryId ?? 'x'}-${index}`)));
94
+ // THE `d` MARKER LIVES ON THE FRAME'S OWN TITLE LINE (D-6), which is chrome that is
95
+ // already paid for. It is spelled `d:on` / `d:off` rather than `details on|off`
96
+ // because the title row also carries the frame's position indicator (`v 1-13/37`,
97
+ // 13 cells) and the drawer's content is only 26 cells wide at 80 columns: the long
98
+ // form is truncated to `details...`, which is a marker that says nothing. The
99
+ // footer's `d details` clause names the key, so the pair reads as one sentence.
100
+ const title = `Keys d:${props.detailsExpanded ? 'on' : 'off'}`;
101
+ return (_jsx(OverlayFrame, { title: title, hint: result.hint, maxRows: maxRows, cols: cols, width: shortcutPanelWidth(cols), align: "right", rows: rows,
102
+ // THE WINDOW IS DERIVED FROM THE CURSOR, so the offset handed to the frame is
103
+ // a conclusion rather than state. `onScrollClamp` is deliberately not passed:
104
+ // there is nothing here that could drift out of step with it.
105
+ scrollOffset: result.window.start, theme: theme, caps: caps }));
106
+ }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * THE shortcut table (tui-shortcut-drawer-and-task-summary §4.6 / appendix B).
3
+ *
4
+ * ASCII ONLY, AND THAT IS A HARD CONSTRAINT RATHER THAN A STYLE CHOICE: this file
5
+ * is inside `glyphs.test.ts::inScope` (`ui/` prefix), whose `A-1` case fails on a
6
+ * single non-ASCII byte. Every `keyword` and `detail` below is English on
7
+ * purpose; translating them would turn the scanner red, and the only escape
8
+ * hatch - adding this file to the exemptions - is the thing that helper's own
9
+ * comment argues against.
10
+ *
11
+ * THIS IS THE ONLY TRUTH ABOUT SHORTCUTS. The drawer, `/keys` and the tests all
12
+ * derive from it, and `shortcut-table.test.ts` holds it in a BIDIRECTIONAL set
13
+ * relation with `HelpOverlay`'s key column (D-8). The reverse direction is the
14
+ * one that matters: without it `Alt+K`, `Esc twice` and `Esc again` could sit in
15
+ * `/help` forever and never appear in the panel whose entire requirement is
16
+ * "list ALL of them".
17
+ *
18
+ * `keyword` IS CAPPED AT 10 CELLS (`SHORTCUT_PANEL_LIMITS.keywordMaxCells`). A
19
+ * longer one is a spec error, not a width problem: at 80 columns the keyword
20
+ * column is 11 cells wide, and the only remaining remedy would be truncating it -
21
+ * which is the exact defect (a column of `promp...`) this table exists to avoid.
22
+ */
23
+ export type ShortcutGroupId = 'compose' | 'run' | 'panels' | 'session' | 'view';
24
+ /**
25
+ * When a row can actually be used. Unavailable rows are STILL LISTED - the user
26
+ * needs to know the key exists - but they render dim and explain themselves in
27
+ * the detail line when selected.
28
+ */
29
+ export type ShortcutAvailability = 'always' | 'idle' | 'running' | 'app' | 'native';
30
+ export interface ShortcutEntry {
31
+ /** Stable id used by tests and by `/keys <query>`. */
32
+ id: string;
33
+ /** The primary binding, spelled in full the way `HelpOverlay` spells it. */
34
+ keys: string;
35
+ /** One to two words, ASCII only, at most 10 columns. The requirement's second column. */
36
+ keyword: string;
37
+ /** One ASCII sentence, shown when the row is selected. */
38
+ detail: string;
39
+ group: ShortcutGroupId;
40
+ availability: ShortcutAvailability;
41
+ /** Extra spellings that must also resolve in `/keys <query>`. */
42
+ aliases?: readonly string[];
43
+ }
44
+ export declare const SHORTCUT_GROUPS: readonly {
45
+ id: ShortcutGroupId;
46
+ title: string;
47
+ }[];
48
+ /**
49
+ * The 31 rows, in reading order. Group order is fixed by `SHORTCUT_GROUPS`, and
50
+ * within a group the order is "how often a user reaches for it", not alphabetical:
51
+ * a reference panel is scanned from the top.
52
+ */
53
+ export declare const SHORTCUTS: readonly ShortcutEntry[];
54
+ /**
55
+ * The longest `keys` string in cells - the input the column derivation needs.
56
+ *
57
+ * DERIVED, NEVER HARD-CODED: v1 fixed the key column at 21 cells, which left six
58
+ * for the keyword at 80 columns and turned `prompt library` into `promp...`. A
59
+ * derived value cannot go stale the day someone adds a longer binding.
60
+ */
61
+ export declare function widestKeysCells(entries: readonly ShortcutEntry[]): number;
62
+ /**
63
+ * Filter for `/keys <query>`: case-insensitive substring over id, keys, keyword
64
+ * and aliases.
65
+ *
66
+ * NO KEYBOARD SEARCH IN THE PANEL ITSELF (§11 F-2): typing would fight `Esc` for
67
+ * "clear the filter or close the panel", and `Esc` is App-owned. The command is
68
+ * the zero-conflict way to reach the same filter.
69
+ */
70
+ export declare function filterShortcuts(entries: readonly ShortcutEntry[], query: string): ShortcutEntry[];
71
+ /**
72
+ * Whether a row can be used right now.
73
+ *
74
+ * `running` MEANS "ONLY WHILE RUNNING", not "unavailable while running" - the two
75
+ * halves of the table would otherwise need two different predicates, which is the
76
+ * kind of asymmetry a later reader gets backwards.
77
+ */
78
+ export declare function isAvailable(entry: ShortcutEntry, context: {
79
+ native: boolean;
80
+ running: boolean;
81
+ }): boolean;
@@ -0,0 +1,221 @@
1
+ /**
2
+ * THE shortcut table (tui-shortcut-drawer-and-task-summary §4.6 / appendix B).
3
+ *
4
+ * ASCII ONLY, AND THAT IS A HARD CONSTRAINT RATHER THAN A STYLE CHOICE: this file
5
+ * is inside `glyphs.test.ts::inScope` (`ui/` prefix), whose `A-1` case fails on a
6
+ * single non-ASCII byte. Every `keyword` and `detail` below is English on
7
+ * purpose; translating them would turn the scanner red, and the only escape
8
+ * hatch - adding this file to the exemptions - is the thing that helper's own
9
+ * comment argues against.
10
+ *
11
+ * THIS IS THE ONLY TRUTH ABOUT SHORTCUTS. The drawer, `/keys` and the tests all
12
+ * derive from it, and `shortcut-table.test.ts` holds it in a BIDIRECTIONAL set
13
+ * relation with `HelpOverlay`'s key column (D-8). The reverse direction is the
14
+ * one that matters: without it `Alt+K`, `Esc twice` and `Esc again` could sit in
15
+ * `/help` forever and never appear in the panel whose entire requirement is
16
+ * "list ALL of them".
17
+ *
18
+ * `keyword` IS CAPPED AT 10 CELLS (`SHORTCUT_PANEL_LIMITS.keywordMaxCells`). A
19
+ * longer one is a spec error, not a width problem: at 80 columns the keyword
20
+ * column is 11 cells wide, and the only remaining remedy would be truncating it -
21
+ * which is the exact defect (a column of `promp...`) this table exists to avoid.
22
+ */
23
+ import { cellWidth } from './layout/cells.js';
24
+ export const SHORTCUT_GROUPS = [
25
+ { id: 'compose', title: 'COMPOSE' },
26
+ { id: 'run', title: 'RUN' },
27
+ { id: 'panels', title: 'PANELS' },
28
+ { id: 'session', title: 'SESSION' },
29
+ { id: 'view', title: 'VIEW' },
30
+ ];
31
+ /**
32
+ * The 31 rows, in reading order. Group order is fixed by `SHORTCUT_GROUPS`, and
33
+ * within a group the order is "how often a user reaches for it", not alphabetical:
34
+ * a reference panel is scanned from the top.
35
+ */
36
+ export const SHORTCUTS = [
37
+ // --- COMPOSE ---------------------------------------------------------------
38
+ {
39
+ id: 'enter', keys: 'Enter', keyword: 'send', group: 'compose', availability: 'always',
40
+ detail: 'Submits when idle; queues as steering while running;'
41
+ + ' re-pins the view to the newest output.',
42
+ },
43
+ {
44
+ id: 'alt-enter', keys: 'Alt+Enter', keyword: 'newline', group: 'compose',
45
+ availability: 'always',
46
+ detail: 'Multiline input; the host may intercept this combination.',
47
+ },
48
+ {
49
+ id: 'shift-enter', keys: 'Shift+Enter', keyword: 'newline', group: 'compose',
50
+ availability: 'always',
51
+ detail: 'Needs keyboard enhancement; /terminal-setup explains how to bind it.',
52
+ },
53
+ {
54
+ id: 'ctrl-j', keys: 'Ctrl+J', keyword: 'newline', group: 'compose', availability: 'always',
55
+ detail: 'Newline fallback that does not depend on keyboard enhancement.',
56
+ },
57
+ {
58
+ id: 'history', keys: 'Up / Down', keyword: 'history', group: 'compose', availability: 'always',
59
+ detail: 'Recalls earlier prompts when the input box is empty.',
60
+ },
61
+ {
62
+ id: 'paste', keys: 'Paste', keyword: 'paste', group: 'compose', availability: 'always',
63
+ detail: 'Up to 6 lines inserted as-is; larger becomes [Pasted text #N]; --no-paste disables.',
64
+ },
65
+ {
66
+ id: 'ctrl-o', keys: 'Ctrl+O', keyword: 'expand', group: 'compose', availability: 'always',
67
+ detail: 'Expands the newest tool output; in native mode it reprints it as a new block.',
68
+ },
69
+ {
70
+ id: 'ctrl-c', keys: 'Ctrl+C', keyword: 'copy/exit', group: 'compose', availability: 'always',
71
+ aliases: ['Ctrl+C (with a selection)'],
72
+ detail: 'Copies a pending selection; with a draft x2 clears and x3 exits;'
73
+ + ' empty input x2 exits.',
74
+ },
75
+ // --- RUN -------------------------------------------------------------------
76
+ {
77
+ id: 'esc', keys: 'Esc', keyword: 'close', group: 'run', availability: 'always',
78
+ detail: 'Closes the open overlay or menu; with nothing open it arms the interrupt ladder.',
79
+ },
80
+ {
81
+ id: 'esc-twice', keys: 'Esc twice', keyword: 'interrupt', group: 'run', availability: 'running',
82
+ aliases: ['Esc again'],
83
+ detail: 'Requests an interrupt within 1.5s; the next press forces the stop.',
84
+ },
85
+ {
86
+ id: 'shift-tab', keys: 'Shift+Tab', keyword: 'plan mode', group: 'run', availability: 'always',
87
+ detail: 'Toggles BUILD and PLAN; writes are refused and the agent only investigates.',
88
+ },
89
+ {
90
+ id: 'ctrl-n', keys: 'Ctrl+N', keyword: 'plan mode', group: 'run', availability: 'always',
91
+ detail: 'The same toggle, for Windows consoles that cannot deliver Shift+Tab.',
92
+ },
93
+ {
94
+ id: 'ctrl-t', keys: 'Ctrl+T', keyword: 'thinking', group: 'run', availability: 'always',
95
+ detail: "Shows or hides the model's thinking (off by default).",
96
+ },
97
+ {
98
+ id: 'ctrl-r', keys: 'Ctrl+R', keyword: 'redraw', group: 'run', availability: 'always',
99
+ detail: 'Repaints the whole frame; use it when the terminal is garbled.',
100
+ },
101
+ // --- PANELS ----------------------------------------------------------------
102
+ {
103
+ id: 'ctrl-g', keys: 'Ctrl+G', keyword: 'all keys', group: 'panels', availability: 'always',
104
+ detail: 'Opens this panel; a second Ctrl+G closes it. Every shortcut is listed here.',
105
+ },
106
+ {
107
+ id: 'ctrl-b', keys: 'Ctrl+B', keyword: 'agents', group: 'panels', availability: 'always',
108
+ detail: 'Read-only subagent board: every child, its facts and its timeline.',
109
+ },
110
+ {
111
+ id: 'ctrl-p', keys: 'Ctrl+P', keyword: 'prompts', group: 'panels', availability: 'always',
112
+ detail: 'Quick prompt library: pick, edit, reorder.',
113
+ },
114
+ {
115
+ id: 'ctrl-k', keys: 'Ctrl+K', keyword: 'kits', group: 'panels', availability: 'always',
116
+ detail: 'Switch the main / fast / subagent model kit for this session.',
117
+ },
118
+ {
119
+ id: 'ctrl-i', keys: 'Ctrl+I', keyword: 'index', group: 'panels', availability: 'idle',
120
+ detail: 'Unavailable while running; asks first, then runs the project-indexer skill.',
121
+ },
122
+ {
123
+ id: 'alt-k', keys: 'Alt+K', keyword: 'kill line', group: 'panels', availability: 'always',
124
+ detail: 'Deletes from the cursor to the end of the line'
125
+ + ' (this was Ctrl+K before the kit picker).',
126
+ },
127
+ {
128
+ id: 'help', keys: '/help', keyword: 'reference', group: 'panels', availability: 'always',
129
+ detail: 'Full reference: keys, slash commands, plan mode, team, skills.',
130
+ },
131
+ // --- SESSION ---------------------------------------------------------------
132
+ {
133
+ id: 'ctrl-l', keys: 'Ctrl+L', keyword: 'branch', group: 'session', availability: 'always',
134
+ detail: 'Opens this session in a new terminal window with its own session id.',
135
+ },
136
+ {
137
+ id: 'clear', keys: '/clear', keyword: 'new task', group: 'session', availability: 'always',
138
+ detail: 'Archives the old conversation, clears the context;'
139
+ + ' the task summary is cleared with it.',
140
+ },
141
+ {
142
+ id: 'resume', keys: '/resume', keyword: 'switch', group: 'session', availability: 'always',
143
+ detail: 'Loads a saved session; the current session moves to a new id.',
144
+ },
145
+ {
146
+ id: 'session', keys: '/session', keyword: 'identity', group: 'session', availability: 'always',
147
+ detail: 'Shows the session id and file, copies the resume command, pins the id.',
148
+ },
149
+ // --- VIEW ------------------------------------------------------------------
150
+ {
151
+ id: 'page', keys: 'PgUp / PgDn', keyword: 'page', group: 'view', availability: 'always',
152
+ detail: 'Pages the transcript, or the overlay that currently owns the keyboard.',
153
+ },
154
+ {
155
+ id: 'wheel', keys: 'Wheel', keyword: 'scroll', group: 'view', availability: 'app',
156
+ detail: 'Scrolls the transcript in app mode; in native mode the terminal owns this.',
157
+ },
158
+ {
159
+ id: 'shift-wheel', keys: 'Shift+Wheel', keyword: 'page', group: 'view', availability: 'app',
160
+ detail: 'Scrolls a whole page.',
161
+ },
162
+ {
163
+ id: 'shift-arrows', keys: 'Shift+Up / Shift+Down', keyword: 'line', group: 'view',
164
+ availability: 'app',
165
+ detail: 'Scrolls one line; native mode leaves this to the terminal.',
166
+ },
167
+ {
168
+ id: 'drag-edge', keys: 'Drag right edge', keyword: 'scrollbar', group: 'view',
169
+ availability: 'app',
170
+ detail: 'Drags the right-edge scrollbar; the input stays fixed.',
171
+ },
172
+ {
173
+ id: 'drag-text', keys: 'Drag text (left button)', keyword: 'select', group: 'view',
174
+ availability: 'app',
175
+ detail: 'Drags to select on-screen text; the highlight waits for a copy.',
176
+ },
177
+ ];
178
+ /**
179
+ * The longest `keys` string in cells - the input the column derivation needs.
180
+ *
181
+ * DERIVED, NEVER HARD-CODED: v1 fixed the key column at 21 cells, which left six
182
+ * for the keyword at 80 columns and turned `prompt library` into `promp...`. A
183
+ * derived value cannot go stale the day someone adds a longer binding.
184
+ */
185
+ export function widestKeysCells(entries) {
186
+ return entries.reduce((widest, entry) => Math.max(widest, cellWidth(entry.keys)), 0);
187
+ }
188
+ /**
189
+ * Filter for `/keys <query>`: case-insensitive substring over id, keys, keyword
190
+ * and aliases.
191
+ *
192
+ * NO KEYBOARD SEARCH IN THE PANEL ITSELF (§11 F-2): typing would fight `Esc` for
193
+ * "clear the filter or close the panel", and `Esc` is App-owned. The command is
194
+ * the zero-conflict way to reach the same filter.
195
+ */
196
+ export function filterShortcuts(entries, query) {
197
+ const needle = query.trim().toLowerCase();
198
+ if (needle.length === 0)
199
+ return [...entries];
200
+ return entries.filter((entry) => {
201
+ const haystack = [entry.id, entry.keys, entry.keyword, ...(entry.aliases ?? [])];
202
+ return haystack.some((field) => field.toLowerCase().includes(needle));
203
+ });
204
+ }
205
+ /**
206
+ * Whether a row can be used right now.
207
+ *
208
+ * `running` MEANS "ONLY WHILE RUNNING", not "unavailable while running" - the two
209
+ * halves of the table would otherwise need two different predicates, which is the
210
+ * kind of asymmetry a later reader gets backwards.
211
+ */
212
+ export function isAvailable(entry, context) {
213
+ switch (entry.availability) {
214
+ case 'always': return true;
215
+ case 'idle': return !context.running;
216
+ case 'running': return context.running;
217
+ case 'app': return !context.native;
218
+ case 'native': return context.native;
219
+ default: return true;
220
+ }
221
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aragon-agent/cli",
3
- "version": "0.6.38",
3
+ "version": "0.6.39",
4
4
  "description": "AragonAgent CLI — a Claude-Code / Codex-style interactive terminal UI (TUI) on top of the @aragon-agent/core engine. Installable and runnable via npm / npx.",
5
5
  "license": "MIT",
6
6
  "author": "AragonAgent contributors",
@@ -56,7 +56,7 @@
56
56
  "prepublishOnly": "npm run build"
57
57
  },
58
58
  "dependencies": {
59
- "@aragon-agent/core": "^0.2.50",
59
+ "@aragon-agent/core": "^0.2.51",
60
60
  "chalk": "^5.6.2",
61
61
  "cli-highlight": "^2.0.0",
62
62
  "commander": "^12.1.0",