@aragon-agent/cli 0.5.3 → 0.5.6
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/CHANGELOG.md +670 -540
- package/README.md +1105 -932
- package/dist/agent/controller.d.ts +71 -1
- package/dist/agent/controller.js +135 -1
- package/dist/agent/headless.d.ts +29 -0
- package/dist/agent/headless.js +86 -1
- package/dist/agent/reducer.d.ts +45 -0
- package/dist/agent/reducer.js +80 -1
- package/dist/agent/system-prompt.d.ts +8 -0
- package/dist/agent/system-prompt.js +2 -0
- package/dist/cli.js +72 -6
- package/dist/commands/builtins.d.ts +2 -2
- package/dist/commands/builtins.js +217 -3
- package/dist/commands/registry.d.ts +27 -1
- package/dist/config/cli-commands.js +20 -2
- package/dist/config/env.d.ts +2 -1
- package/dist/config/env.js +60 -5
- package/dist/config/load.d.ts +27 -0
- package/dist/config/load.js +67 -2
- package/dist/config/schema.d.ts +111 -2
- package/dist/config/schema.js +111 -2
- package/dist/config/store.js +37 -1
- package/dist/session/persist.d.ts +19 -1
- package/dist/session/persist.js +21 -2
- package/dist/team/subagent.js +11 -0
- package/dist/todo/follow-through.d.ts +117 -0
- package/dist/todo/follow-through.js +186 -0
- package/dist/todo/limits.d.ts +114 -0
- package/dist/todo/limits.js +114 -0
- package/dist/todo/normalize.d.ts +33 -0
- package/dist/todo/normalize.js +117 -0
- package/dist/todo/panel-rows.d.ts +53 -0
- package/dist/todo/panel-rows.js +103 -0
- package/dist/todo/prompt.d.ts +54 -0
- package/dist/todo/prompt.js +76 -0
- package/dist/todo/store.d.ts +86 -0
- package/dist/todo/store.js +183 -0
- package/dist/todo/todo-tool.d.ts +38 -0
- package/dist/todo/todo-tool.js +134 -0
- package/dist/todo/types.d.ts +62 -0
- package/dist/todo/types.js +12 -0
- package/dist/tools/index.d.ts +16 -2
- package/dist/tools/index.js +13 -0
- package/dist/ui/App.d.ts +22 -1
- package/dist/ui/App.js +292 -13
- package/dist/ui/StatusBar.d.ts +18 -0
- package/dist/ui/StatusBar.js +5 -2
- package/dist/ui/TodoPanel.d.ts +48 -0
- package/dist/ui/TodoPanel.js +74 -0
- package/dist/ui/TodoStrip.d.ts +36 -0
- package/dist/ui/TodoStrip.js +32 -0
- package/dist/ui/Transcript.js +11 -1
- package/dist/ui/entries/TodoCard.d.ts +31 -0
- package/dist/ui/entries/TodoCard.js +35 -0
- package/dist/ui/glyphs.d.ts +12 -0
- package/dist/ui/glyphs.js +8 -0
- package/dist/ui/layout/AppShell.d.ts +34 -1
- package/dist/ui/layout/AppShell.js +3 -3
- package/dist/ui/layout/ScrollViewport.d.ts +13 -1
- package/dist/ui/layout/ScrollViewport.js +2 -2
- package/dist/ui/layout/rail.d.ts +56 -0
- package/dist/ui/layout/rail.js +68 -0
- package/dist/ui/overlays/HelpOverlay.js +5 -0
- package/dist/ui/overlays/SettingsScreen.d.ts +12 -1
- package/dist/ui/overlays/SettingsScreen.js +38 -1
- package/package.json +3 -2
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TodoStrip — the inline-mode plan surface (todo-plan-followthrough §3.7 / W2).
|
|
3
|
+
*
|
|
4
|
+
* ASCII ONLY: every glyph comes from `pickGlyphs`; a literal here bypasses the
|
|
5
|
+
* capability probe and shows mojibake on a legacy console. This file is inside
|
|
6
|
+
* the glyph scanner's scope because it is under `ui/`, NOT because of the
|
|
7
|
+
* `todo/` clause (C-4) — moving it would not move the guard rail with it.
|
|
8
|
+
*
|
|
9
|
+
* WHY A STRIP AND NOT THE RAIL. `decideRenderMode` picks inline for every pipe,
|
|
10
|
+
* every `CI=1`, every `TERM=dumb` and every terminal under 12 rows, and inline
|
|
11
|
+
* has no fixed frame to hang a column off (round 1's non-goal 4). Before this,
|
|
12
|
+
* such a session had the tool and a `todo 3/7` counter in the status bar, and no
|
|
13
|
+
* way at all to see WHICH step was running (OQ-1).
|
|
14
|
+
*
|
|
15
|
+
* WHY NOT IN THE STATUS BAR. The bar's left cluster is `flexShrink={0}` and its
|
|
16
|
+
* own comment records what happens when the row over-subscribes: Ink drops a
|
|
17
|
+
* character from EACH cluster and it renders `idl` / `? hel`. A variable-length
|
|
18
|
+
* step title cannot go there (C-7), which is what forces this into its own row.
|
|
19
|
+
*
|
|
20
|
+
* EXACTLY ONE RENDERED ROW, ALWAYS (AC-29). A strip that wrapped would push the
|
|
21
|
+
* composer down by an unpredictable number of rows on every keystroke, which is
|
|
22
|
+
* the worst possible behaviour for the mode with no frame to absorb it — hence
|
|
23
|
+
* `wrap="truncate"` inside a `flexGrow`/`flexShrink` box and no exceptions.
|
|
24
|
+
*/
|
|
25
|
+
import React from 'react';
|
|
26
|
+
import type { Theme } from './theme.js';
|
|
27
|
+
import type { TermCapabilities } from './capabilities.js';
|
|
28
|
+
import type { TodoSnapshot } from '../todo/types.js';
|
|
29
|
+
export interface TodoStripProps {
|
|
30
|
+
snapshot: TodoSnapshot;
|
|
31
|
+
/** Full terminal width; the strip spans the row in inline mode. */
|
|
32
|
+
cols: number;
|
|
33
|
+
theme: Theme;
|
|
34
|
+
caps: TermCapabilities;
|
|
35
|
+
}
|
|
36
|
+
export declare function TodoStrip({ snapshot, cols, theme, caps }: TodoStripProps): React.ReactElement;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
import { pickGlyphs } from './glyphs.js';
|
|
4
|
+
import { TODO_LIMITS } from '../todo/limits.js';
|
|
5
|
+
import { todoAnchorIndex } from '../todo/panel-rows.js';
|
|
6
|
+
export function TodoStrip({ snapshot, cols, theme, caps }) {
|
|
7
|
+
const glyphs = pickGlyphs(caps);
|
|
8
|
+
// THE SAME FUNCTION THE RAIL USES (R-9 / AC-30). Two surfaces that each decide
|
|
9
|
+
// for themselves which step is "current" is two surfaces that disagree, and
|
|
10
|
+
// this one is on screen in exactly the mode where the rail is not, so the
|
|
11
|
+
// disagreement would never be seen side by side and never be reported.
|
|
12
|
+
const anchor = todoAnchorIndex(snapshot.items);
|
|
13
|
+
const item = snapshot.items[anchor];
|
|
14
|
+
const active = item?.status === 'in_progress';
|
|
15
|
+
// `activeForm` while in progress, `content` otherwise — `TodoPanel`'s rule.
|
|
16
|
+
const label = item ? (active ? item.activeForm : item.content) : '';
|
|
17
|
+
// The same degradation the status bar already applies, so the two counters can
|
|
18
|
+
// never disagree about how much room they need.
|
|
19
|
+
const counter = cols >= TODO_LIMITS.statusCompactCols
|
|
20
|
+
? `todo ${snapshot.doneCount}/${snapshot.total}`
|
|
21
|
+
: `[${snapshot.doneCount}/${snapshot.total}]`;
|
|
22
|
+
const showDone = snapshot.doneCount > 0 && cols >= TODO_LIMITS.stripDoneCols;
|
|
23
|
+
return (
|
|
24
|
+
// `width` IS LOAD-BEARING, exactly as it is on `TodoPanel` and for a related
|
|
25
|
+
// reason. Inline mode has no fixed frame, so nothing upstream constrains
|
|
26
|
+
// this row: without an explicit width the flexible middle cell is sized by
|
|
27
|
+
// whatever the parent offers, and a long item overflows the terminal and
|
|
28
|
+
// WRAPS — the one thing this component exists not to do. Pinning it here
|
|
29
|
+
// makes the truncation deterministic and self-contained rather than a
|
|
30
|
+
// property of the tree above.
|
|
31
|
+
_jsxs(Box, { flexDirection: "row", width: cols, overflow: "hidden", children: [_jsx(Box, { flexShrink: 0, children: _jsx(Text, { wrap: "truncate", color: theme.accent, children: counter }) }), _jsx(Box, { flexShrink: 0, children: _jsxs(Text, { wrap: "truncate", color: theme.muted, children: [' ', glyphs.arrowRight, ' '] }) }), _jsx(Box, { flexGrow: 1, flexShrink: 1, overflow: "hidden", children: _jsx(Text, { wrap: "truncate", color: active ? theme.primary : theme.muted, bold: active, children: label }) }), showDone && (_jsx(Box, { flexShrink: 0, children: _jsxs(Text, { wrap: "truncate", color: theme.muted, children: [' ', "+", snapshot.doneCount, " done"] }) }))] }));
|
|
32
|
+
}
|
package/dist/ui/Transcript.js
CHANGED
|
@@ -20,13 +20,14 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
20
20
|
import { useRef } from 'react';
|
|
21
21
|
import { Box, Static, Text } from 'ink';
|
|
22
22
|
import Spinner from 'ink-spinner';
|
|
23
|
-
import { pickGlyphs } from './glyphs.js';
|
|
23
|
+
import { pickGlyphs, toolGlyph } from './glyphs.js';
|
|
24
24
|
import { separationRows } from './density.js';
|
|
25
25
|
import { EntryFrame } from './entries/EntryFrame.js';
|
|
26
26
|
import { UserEntry } from './entries/UserEntry.js';
|
|
27
27
|
import { AssistantEntry } from './entries/AssistantEntry.js';
|
|
28
28
|
import { ToolCard, statusColor, toolEntryGlyph } from './entries/ToolCard.js';
|
|
29
29
|
import { TeamCard, teamCardColor } from './entries/TeamCard.js';
|
|
30
|
+
import { TodoCard, todoCardColor } from './entries/TodoCard.js';
|
|
30
31
|
/** Keep the last K entries in the live region so a mutating tail stays hot. */
|
|
31
32
|
const LIVE_TAIL = 1;
|
|
32
33
|
/**
|
|
@@ -55,6 +56,13 @@ export function computeSettledCount(entries, expandedToolIds) {
|
|
|
55
56
|
// session — the failure `session/persist.ts` normalizes away on load (P1-5).
|
|
56
57
|
if (e.kind === 'team' && e.active)
|
|
57
58
|
break;
|
|
59
|
+
// A live todo card is not settled either: it is rewritten on every
|
|
60
|
+
// `todoUpdate` for the whole turn, and `<Static>` cannot un-print what it has
|
|
61
|
+
// already drawn (C-5 / I-6). `session/persist.ts` forces `live: false` on
|
|
62
|
+
// load, which is the other half — a card that never settles is re-rendered
|
|
63
|
+
// on every frame for the rest of the session.
|
|
64
|
+
if (e.kind === 'todo' && e.live)
|
|
65
|
+
break;
|
|
58
66
|
count = i + 1;
|
|
59
67
|
}
|
|
60
68
|
return count;
|
|
@@ -91,6 +99,8 @@ function EntryView({ entry, prev, expanded, thinkingVisible, reducedMotion, dens
|
|
|
91
99
|
return frame(toolEntryGlyph(entry.name, caps), statusColor(entry.status, theme), _jsx(ToolCard, { name: entry.name, label: entry.label, argsRaw: entry.argsRaw, args: entry.args, status: entry.status, preview: entry.preview, durationMs: entry.durationMs, isError: entry.isError, expanded: expanded, reducedMotion: reducedMotion, theme: theme, caps: caps }));
|
|
92
100
|
case 'team':
|
|
93
101
|
return frame(glyphs.teamAgent, teamCardColor(entry.runs, entry.active, entry.aborted, theme), _jsx(TeamCard, { requested: entry.requested, runs: entry.runs, aborted: entry.aborted, durationMs: entry.durationMs, active: entry.active, expanded: expanded, reducedMotion: reducedMotion, theme: theme, caps: caps }));
|
|
102
|
+
case 'todo':
|
|
103
|
+
return frame(toolGlyph(glyphs, 'todo_write'), todoCardColor(entry.doneCount, entry.total, entry.live, theme), _jsx(TodoCard, { items: entry.items, doneCount: entry.doneCount, total: entry.total, live: entry.live, interrupted: entry.interrupted, theme: theme, caps: caps }));
|
|
94
104
|
case 'notice':
|
|
95
105
|
return frame(noticeSymbol(entry.level, theme), noticeColor(entry.level, theme), _jsx(Text, { color: noticeColor(entry.level, theme), children: entry.text }));
|
|
96
106
|
default:
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TodoCard — the transcript checklist entry (todo-plan-execution §6.2).
|
|
3
|
+
*
|
|
4
|
+
* ASCII ONLY: every glyph comes from `pickGlyphs`.
|
|
5
|
+
*
|
|
6
|
+
* ONE CARD PER USER TURN, REWRITTEN IN PLACE. The rail is EPHEMERAL and this is
|
|
7
|
+
* the HISTORY, exactly as `TeamPanel` and `TeamCard` divide the same work. It
|
|
8
|
+
* renders through the shared `EntryFrame` supplied by `EntryView`, so a plan
|
|
9
|
+
* reads as one more step in the transcript rather than a second kind of object.
|
|
10
|
+
*
|
|
11
|
+
* THE FULL LIST, NO WINDOWING (the transcript scrolls; the rail does not), and
|
|
12
|
+
* NEVER ANIMATED even while `live` — a resumed session would otherwise spin
|
|
13
|
+
* forever on a card whose run ended days ago.
|
|
14
|
+
*/
|
|
15
|
+
import React from 'react';
|
|
16
|
+
import type { Theme } from '../theme.js';
|
|
17
|
+
import type { TermCapabilities } from '../capabilities.js';
|
|
18
|
+
import type { TodoItem } from '../../todo/types.js';
|
|
19
|
+
export interface TodoCardProps {
|
|
20
|
+
items: TodoItem[];
|
|
21
|
+
doneCount: number;
|
|
22
|
+
total: number;
|
|
23
|
+
live: boolean;
|
|
24
|
+
/** Saved mid-run and resumed: the run behind this card died with the process. */
|
|
25
|
+
interrupted?: boolean;
|
|
26
|
+
theme: Theme;
|
|
27
|
+
caps: TermCapabilities;
|
|
28
|
+
}
|
|
29
|
+
/** The card's aggregate colour: complete is done, anything else is in flight. */
|
|
30
|
+
export declare function todoCardColor(doneCount: number, total: number, live: boolean, theme: Theme): string | undefined;
|
|
31
|
+
export declare function TodoCard(props: TodoCardProps): React.ReactElement;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
import { pickGlyphs } from '../glyphs.js';
|
|
4
|
+
import { railBorderProps } from '../layout/Gutter.js';
|
|
5
|
+
/** The card's aggregate colour: complete is done, anything else is in flight. */
|
|
6
|
+
export function todoCardColor(doneCount, total, live, theme) {
|
|
7
|
+
if (live)
|
|
8
|
+
return theme.toolRunning;
|
|
9
|
+
if (total > 0 && doneCount === total)
|
|
10
|
+
return theme.toolDone;
|
|
11
|
+
return theme.muted;
|
|
12
|
+
}
|
|
13
|
+
function marker(item, glyphs) {
|
|
14
|
+
if (item.status === 'completed')
|
|
15
|
+
return glyphs.todoDone;
|
|
16
|
+
if (item.status === 'in_progress')
|
|
17
|
+
return glyphs.todoActive;
|
|
18
|
+
return glyphs.todoPending;
|
|
19
|
+
}
|
|
20
|
+
function rowColor(item, theme) {
|
|
21
|
+
if (item.status === 'completed')
|
|
22
|
+
return theme.muted;
|
|
23
|
+
if (item.status === 'in_progress')
|
|
24
|
+
return theme.primary;
|
|
25
|
+
return theme.hintFg ?? theme.muted;
|
|
26
|
+
}
|
|
27
|
+
export function TodoCard(props) {
|
|
28
|
+
const { items, doneCount, total, live, interrupted, theme, caps } = props;
|
|
29
|
+
const glyphs = pickGlyphs(caps);
|
|
30
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { flexDirection: "row", children: [_jsx(Text, { color: theme.accent, bold: true, children: "Todos" }), _jsxs(Text, { color: todoCardColor(doneCount, total, live, theme), children: [' ', doneCount, "/", total] }), interrupted && (
|
|
31
|
+
// A resumed `2/7` would otherwise read as a run still in flight
|
|
32
|
+
// (P2-6). Saying so plainly is the same fix `TeamCard` makes for a
|
|
33
|
+
// dispatch that never got a duration.
|
|
34
|
+
_jsxs(Text, { color: theme.muted, children: [' ', "interrupted (session resumed)"] }))] }), _jsx(Box, { flexDirection: "column", flexShrink: 0, paddingLeft: 1, ...railBorderProps(glyphs.railVertical, theme.border), children: items.map((item, index) => (_jsxs(Text, { wrap: "truncate", color: rowColor(item, theme), children: [marker(item, glyphs).padEnd(3), item.status === 'in_progress' ? item.activeForm : item.content] }, `${index}-${item.content}`))) })] }));
|
|
35
|
+
}
|
package/dist/ui/glyphs.d.ts
CHANGED
|
@@ -96,6 +96,18 @@ export interface Glyphs {
|
|
|
96
96
|
*/
|
|
97
97
|
teamAgent: string;
|
|
98
98
|
teamMail: string;
|
|
99
|
+
/**
|
|
100
|
+
* Todo planning (todo-plan-execution §6.1). One marker per item state, plus
|
|
101
|
+
* the rail marker for the transcript card via `tool.todo_write`.
|
|
102
|
+
*
|
|
103
|
+
* THE ASCII TIER USES BRACKETED FORMS FOR THE TWO SETTLED STATES, because a
|
|
104
|
+
* bare single letter cannot distinguish "done" from "failed" on a monochrome
|
|
105
|
+
* terminal. The panel pads the marker cell to 3 columns, which is what makes
|
|
106
|
+
* the mixed widths line up without a per-tier branch.
|
|
107
|
+
*/
|
|
108
|
+
todoPending: string;
|
|
109
|
+
todoActive: string;
|
|
110
|
+
todoDone: string;
|
|
99
111
|
/**
|
|
100
112
|
* Ink `borderStyle` name for every boxed region (composer, completion popup,
|
|
101
113
|
* overlay frame).
|
package/dist/ui/glyphs.js
CHANGED
|
@@ -61,6 +61,9 @@ const UNICODE_GLYPHS = {
|
|
|
61
61
|
boxStyle: 'round',
|
|
62
62
|
teamAgent: '◆',
|
|
63
63
|
teamMail: '✉',
|
|
64
|
+
todoPending: '○',
|
|
65
|
+
todoActive: '▸',
|
|
66
|
+
todoDone: '✔',
|
|
64
67
|
tool: {
|
|
65
68
|
read_file: '▤',
|
|
66
69
|
write_file: '✎',
|
|
@@ -72,6 +75,7 @@ const UNICODE_GLYPHS = {
|
|
|
72
75
|
ask_user: '?',
|
|
73
76
|
submit_plan: '◈',
|
|
74
77
|
task: '◆',
|
|
78
|
+
todo_write: '☰',
|
|
75
79
|
},
|
|
76
80
|
toolDefault: '•',
|
|
77
81
|
};
|
|
@@ -118,6 +122,9 @@ const ASCII_GLYPHS = {
|
|
|
118
122
|
boxStyle: 'classic',
|
|
119
123
|
teamAgent: '*',
|
|
120
124
|
teamMail: '@',
|
|
125
|
+
todoPending: '[ ]',
|
|
126
|
+
todoActive: '>',
|
|
127
|
+
todoDone: '[x]',
|
|
121
128
|
tool: {
|
|
122
129
|
read_file: '=',
|
|
123
130
|
write_file: '+',
|
|
@@ -129,6 +136,7 @@ const ASCII_GLYPHS = {
|
|
|
129
136
|
ask_user: '?',
|
|
130
137
|
submit_plan: '#',
|
|
131
138
|
task: '*',
|
|
139
|
+
todo_write: '=',
|
|
132
140
|
},
|
|
133
141
|
toolDefault: '*',
|
|
134
142
|
};
|
|
@@ -28,6 +28,39 @@ export interface AppShellProps {
|
|
|
28
28
|
* composer band boundary stale the instant a dispatch started.
|
|
29
29
|
*/
|
|
30
30
|
team?: React.ReactNode;
|
|
31
|
+
/**
|
|
32
|
+
* The right-hand region of the MIDDLE band (todo-plan-execution §3.9), or
|
|
33
|
+
* nothing.
|
|
34
|
+
*
|
|
35
|
+
* NAMED FOR ITS POSITION, NOT ITS CONTENT (D-18): this file is a layout
|
|
36
|
+
* primitive and has no business knowing what a todo is. `team` above already
|
|
37
|
+
* leaks content vocabulary in here; there is no reason to repeat it.
|
|
38
|
+
*
|
|
39
|
+
* IT MUST NOT BE RENDERED INSIDE `bottomRef` (C-6 / I-4). That box is MEASURED
|
|
40
|
+
* and the wheel router reads the composer band boundary from it; a column
|
|
41
|
+
* added there would inflate the measurement and start routing transcript
|
|
42
|
+
* scrolls into prompt history.
|
|
43
|
+
*
|
|
44
|
+
* The INLINE branch does not include it at all — a structural guarantee rather
|
|
45
|
+
* than a promise that the caller passes `null` (non-goal 4).
|
|
46
|
+
*/
|
|
47
|
+
rail?: React.ReactNode;
|
|
48
|
+
/**
|
|
49
|
+
* The one-row plan strip for INLINE mode (todo-plan-followthrough §3.7), or
|
|
50
|
+
* nothing.
|
|
51
|
+
*
|
|
52
|
+
* THE STRUCTURAL MIRROR OF `rail` ABOVE, in the opposite direction: the
|
|
53
|
+
* FULL-SCREEN branch does not reference it at all. The reason is the same one
|
|
54
|
+
* `rail`'s inline omission records — a prop that is merely SUPPOSED to be null
|
|
55
|
+
* in one mode becomes non-null eventually, and then the rail and the strip are
|
|
56
|
+
* both on screen showing the same list (I-6). Fullscreen has the rail; that is
|
|
57
|
+
* the whole design.
|
|
58
|
+
*
|
|
59
|
+
* It sits between `viewport` and `team`, i.e. OUTSIDE the measured box in the
|
|
60
|
+
* other branch — but inline has no measured box at all (`geometryRef` is set
|
|
61
|
+
* to `UNMEASURED_GEOMETRY` there), so there is nothing here to invalidate.
|
|
62
|
+
*/
|
|
63
|
+
strip?: React.ReactNode;
|
|
31
64
|
toast: React.ReactNode;
|
|
32
65
|
composer: React.ReactNode;
|
|
33
66
|
status: React.ReactNode;
|
|
@@ -40,4 +73,4 @@ export interface AppShellProps {
|
|
|
40
73
|
*/
|
|
41
74
|
geometryRef?: React.MutableRefObject<FrameGeometry>;
|
|
42
75
|
}
|
|
43
|
-
export declare function AppShell({ mode, rows, cols, header, viewport, team, toast, composer, status, geometryRef, }: AppShellProps): React.ReactElement;
|
|
76
|
+
export declare function AppShell({ mode, rows, cols, header, viewport, team, rail, strip, toast, composer, status, geometryRef, }: AppShellProps): React.ReactElement;
|
|
@@ -14,7 +14,7 @@ import { useLayoutEffect, useRef } from 'react';
|
|
|
14
14
|
import { Box, measureElement } from 'ink';
|
|
15
15
|
import { frameHeight } from './frame.js';
|
|
16
16
|
import { UNMEASURED_GEOMETRY } from './regions.js';
|
|
17
|
-
export function AppShell({ mode, rows, cols, header, viewport, team, toast, composer, status, geometryRef, }) {
|
|
17
|
+
export function AppShell({ mode, rows, cols, header, viewport, team, rail, strip, toast, composer, status, geometryRef, }) {
|
|
18
18
|
const bottomRef = useRef(null);
|
|
19
19
|
// DECLARED ABOVE THE INLINE EARLY RETURN, and it has to stay there: React
|
|
20
20
|
// keys hooks by call order, and a hook that only runs in one mode changes
|
|
@@ -38,7 +38,7 @@ export function AppShell({ mode, rows, cols, header, viewport, team, toast, comp
|
|
|
38
38
|
};
|
|
39
39
|
});
|
|
40
40
|
if (mode === 'inline') {
|
|
41
|
-
return (_jsxs(Box, { flexDirection: "column", children: [header, viewport, team, toast, composer, status] }));
|
|
41
|
+
return (_jsxs(Box, { flexDirection: "column", children: [header, viewport, strip, team, toast, composer, status] }));
|
|
42
42
|
}
|
|
43
|
-
return (_jsxs(Box, { flexDirection: "column", height: frameHeight(rows), width: cols, overflow: "hidden", children: [_jsx(Box, { flexDirection: "column", flexShrink: 0, children: header }), _jsx(Box, { flexDirection: "column", flexGrow: 1, flexShrink: 1, overflow: "hidden", children: viewport }), _jsxs(Box, { ref: bottomRef, flexDirection: "column", flexShrink: 0, children: [team, toast, composer, status] })] }));
|
|
43
|
+
return (_jsxs(Box, { flexDirection: "column", height: frameHeight(rows), width: cols, overflow: "hidden", children: [_jsx(Box, { flexDirection: "column", flexShrink: 0, children: header }), _jsxs(Box, { flexDirection: "row", flexGrow: 1, flexShrink: 1, overflow: "hidden", children: [_jsx(Box, { flexDirection: "column", flexGrow: 1, flexShrink: 1, overflow: "hidden", children: viewport }), rail] }), _jsxs(Box, { ref: bottomRef, flexDirection: "column", flexShrink: 0, children: [team, toast, composer, status] })] }));
|
|
44
44
|
}
|
|
@@ -32,8 +32,20 @@ export interface ScrollViewportProps {
|
|
|
32
32
|
onScrolledLinesChange?: (lines: number) => void;
|
|
33
33
|
/** Reserve the right-edge scroll-position rail (mouse-wheel §4.8). */
|
|
34
34
|
showScrollIndicator?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* The viewport's own width, when it is narrower than the terminal
|
|
37
|
+
* (todo-plan-execution §3.9 / C-7).
|
|
38
|
+
*
|
|
39
|
+
* This component is the ONLY one inside the viewport subtree that reads
|
|
40
|
+
* `stdout.columns` directly, and both places it uses the number — the terse
|
|
41
|
+
* hint threshold and the `MIN_INDICATOR_COLS` gate — are about how much room
|
|
42
|
+
* THIS BOX has, not how wide the terminal is. Once the todo rail takes a fifth
|
|
43
|
+
* of the frame those two stop being the same number. Optional so every
|
|
44
|
+
* existing caller (and every test) is unchanged.
|
|
45
|
+
*/
|
|
46
|
+
cols?: number;
|
|
35
47
|
theme: Theme;
|
|
36
48
|
caps: TermCapabilities;
|
|
37
49
|
children: React.ReactNode;
|
|
38
50
|
}
|
|
39
|
-
export declare function ScrollViewport({ intent, pinToBottomNonce, onScrolledLinesChange, showScrollIndicator, theme, caps, children, }: ScrollViewportProps): React.ReactElement;
|
|
51
|
+
export declare function ScrollViewport({ intent, pinToBottomNonce, onScrolledLinesChange, showScrollIndicator, cols: colsProp, theme, caps, children, }: ScrollViewportProps): React.ReactElement;
|
|
@@ -21,9 +21,9 @@ import { thumbRange } from './scroll-indicator.js';
|
|
|
21
21
|
import { MIN_INDICATOR_COLS, ScrollIndicator } from './ScrollIndicator.js';
|
|
22
22
|
/** Below this the full hint sentence wraps and eats a second viewport row. */
|
|
23
23
|
const TERSE_HINT_COLS = 42;
|
|
24
|
-
export function ScrollViewport({ intent, pinToBottomNonce = 0, onScrolledLinesChange, showScrollIndicator = false, theme, caps, children, }) {
|
|
24
|
+
export function ScrollViewport({ intent, pinToBottomNonce = 0, onScrolledLinesChange, showScrollIndicator = false, cols: colsProp, theme, caps, children, }) {
|
|
25
25
|
const { stdout } = useStdout();
|
|
26
|
-
const cols = stdout?.columns ?? 80;
|
|
26
|
+
const cols = colsProp ?? stdout?.columns ?? 80;
|
|
27
27
|
const glyphs = pickGlyphs(caps);
|
|
28
28
|
const clipRef = useRef(null);
|
|
29
29
|
const innerRef = useRef(null);
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rail geometry (todo-plan-execution §3.9) — the ONE place that says how wide
|
|
3
|
+
* and how tall the todo rail is allowed to be.
|
|
4
|
+
*
|
|
5
|
+
* Pure and React-free, mirroring `budget.ts`, so `todo-rail.test.ts` can pin the
|
|
6
|
+
* arithmetic without mounting anything. Deliberately NOT part of `budget.ts`:
|
|
7
|
+
* that module answers "how many ROWS does the viewport get" and stays a function
|
|
8
|
+
* of `rows` alone; the rail spends COLUMNS.
|
|
9
|
+
*
|
|
10
|
+
* NAMED FOR ITS POSITION, NOT ITS CONTENT, like `AppShellProps.rail` (D-18):
|
|
11
|
+
* this is a layout primitive and `viewportRows` is its neighbour, not
|
|
12
|
+
* `TodoPanel`.
|
|
13
|
+
*/
|
|
14
|
+
/** Below this the marker + a two-word title do not fit and the column is noise. */
|
|
15
|
+
export declare const TODO_RAIL_MIN_COLS = 18;
|
|
16
|
+
/**
|
|
17
|
+
* Above this, 20% is being spent on whitespace: at 36 columns a step title
|
|
18
|
+
* already fits on one line, and the transcript is the surface that benefits from
|
|
19
|
+
* a 200-column terminal. A deliberate, revertible deviation from a literal
|
|
20
|
+
* reading of R-e; it only binds above 180 columns.
|
|
21
|
+
*/
|
|
22
|
+
export declare const TODO_RAIL_MAX_COLS = 36;
|
|
23
|
+
/** Under 80 columns the transcript needs every column; no rail at all. */
|
|
24
|
+
export declare const TODO_RAIL_MIN_TOTAL_COLS = 80;
|
|
25
|
+
/** Below this rail width the 2-column index prefix is dropped for content. */
|
|
26
|
+
export declare const TODO_RAIL_INDEX_MIN_COLS = 22;
|
|
27
|
+
/**
|
|
28
|
+
* Two properties are pinned by tests, for the reason `budget.ts` records about
|
|
29
|
+
* the viewport being non-monotonic before anyone measured it:
|
|
30
|
+
*
|
|
31
|
+
* - NON-DECREASING in `cols` across [40, 300]. A user dragging a window wider
|
|
32
|
+
* must never see the rail get narrower.
|
|
33
|
+
* - `cols - todoRailWidth(cols) >= 62` for every `cols >= 80`. Every existing
|
|
34
|
+
* width heuristic inside the viewport (`TERSE_HINT_COLS` 42,
|
|
35
|
+
* `MIN_INDICATOR_COLS` 50, the status bar's 60/72 steps) sits below that
|
|
36
|
+
* floor, so no existing behaviour changes because a rail appeared (R-3).
|
|
37
|
+
*/
|
|
38
|
+
export declare function todoRailWidth(cols: number): number;
|
|
39
|
+
/**
|
|
40
|
+
* How many rows the rail may actually draw.
|
|
41
|
+
*
|
|
42
|
+
* IT IS NOT `viewportBudget`, AND THE DIFFERENCE IS NOT COSMETIC (P1-3 / D-23).
|
|
43
|
+
* `viewportRows()` subtracts the STATIC chrome only, and says so; the live team
|
|
44
|
+
* roster is mounted inside `AppShell`'s measured bottom box, where it costs a
|
|
45
|
+
* header row, up to `TEAM_LIMITS.panelMaxRows` child rows, a `+N more` row and a
|
|
46
|
+
* mail row that `viewportBudget` knows nothing about. `ScrollViewport` is immune
|
|
47
|
+
* because it MEASURES itself; the rail does not measure - a second
|
|
48
|
+
* measure -> setState -> measure loop is exactly what §1.2 refuses - so it has
|
|
49
|
+
* to subtract.
|
|
50
|
+
*
|
|
51
|
+
* Ink clips overflow from the BOTTOM, so an over-request does not error: it
|
|
52
|
+
* silently eats the last row, which is the `+N below` marker - the one row whose
|
|
53
|
+
* absence is indistinguishable from "the list is short". That is why this is
|
|
54
|
+
* arithmetic rather than a shrug at `overflow: hidden`.
|
|
55
|
+
*/
|
|
56
|
+
export declare function todoRailRows(viewportBudget: number, teamActive: boolean): number;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rail geometry (todo-plan-execution §3.9) — the ONE place that says how wide
|
|
3
|
+
* and how tall the todo rail is allowed to be.
|
|
4
|
+
*
|
|
5
|
+
* Pure and React-free, mirroring `budget.ts`, so `todo-rail.test.ts` can pin the
|
|
6
|
+
* arithmetic without mounting anything. Deliberately NOT part of `budget.ts`:
|
|
7
|
+
* that module answers "how many ROWS does the viewport get" and stays a function
|
|
8
|
+
* of `rows` alone; the rail spends COLUMNS.
|
|
9
|
+
*
|
|
10
|
+
* NAMED FOR ITS POSITION, NOT ITS CONTENT, like `AppShellProps.rail` (D-18):
|
|
11
|
+
* this is a layout primitive and `viewportRows` is its neighbour, not
|
|
12
|
+
* `TodoPanel`.
|
|
13
|
+
*/
|
|
14
|
+
import { TODO_LIMITS } from '../../todo/limits.js';
|
|
15
|
+
/** R-e, literally: the rail asks for a fifth of the terminal. */
|
|
16
|
+
const RAIL_FRACTION = 0.2;
|
|
17
|
+
/** Below this the marker + a two-word title do not fit and the column is noise. */
|
|
18
|
+
export const TODO_RAIL_MIN_COLS = 18;
|
|
19
|
+
/**
|
|
20
|
+
* Above this, 20% is being spent on whitespace: at 36 columns a step title
|
|
21
|
+
* already fits on one line, and the transcript is the surface that benefits from
|
|
22
|
+
* a 200-column terminal. A deliberate, revertible deviation from a literal
|
|
23
|
+
* reading of R-e; it only binds above 180 columns.
|
|
24
|
+
*/
|
|
25
|
+
export const TODO_RAIL_MAX_COLS = 36;
|
|
26
|
+
/** Under 80 columns the transcript needs every column; no rail at all. */
|
|
27
|
+
export const TODO_RAIL_MIN_TOTAL_COLS = 80;
|
|
28
|
+
/** Below this rail width the 2-column index prefix is dropped for content. */
|
|
29
|
+
export const TODO_RAIL_INDEX_MIN_COLS = 22;
|
|
30
|
+
/**
|
|
31
|
+
* Two properties are pinned by tests, for the reason `budget.ts` records about
|
|
32
|
+
* the viewport being non-monotonic before anyone measured it:
|
|
33
|
+
*
|
|
34
|
+
* - NON-DECREASING in `cols` across [40, 300]. A user dragging a window wider
|
|
35
|
+
* must never see the rail get narrower.
|
|
36
|
+
* - `cols - todoRailWidth(cols) >= 62` for every `cols >= 80`. Every existing
|
|
37
|
+
* width heuristic inside the viewport (`TERSE_HINT_COLS` 42,
|
|
38
|
+
* `MIN_INDICATOR_COLS` 50, the status bar's 60/72 steps) sits below that
|
|
39
|
+
* floor, so no existing behaviour changes because a rail appeared (R-3).
|
|
40
|
+
*/
|
|
41
|
+
export function todoRailWidth(cols) {
|
|
42
|
+
if (!Number.isFinite(cols) || cols < TODO_RAIL_MIN_TOTAL_COLS)
|
|
43
|
+
return 0;
|
|
44
|
+
return Math.min(TODO_RAIL_MAX_COLS, Math.max(TODO_RAIL_MIN_COLS, Math.round(cols * RAIL_FRACTION)));
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* How many rows the rail may actually draw.
|
|
48
|
+
*
|
|
49
|
+
* IT IS NOT `viewportBudget`, AND THE DIFFERENCE IS NOT COSMETIC (P1-3 / D-23).
|
|
50
|
+
* `viewportRows()` subtracts the STATIC chrome only, and says so; the live team
|
|
51
|
+
* roster is mounted inside `AppShell`'s measured bottom box, where it costs a
|
|
52
|
+
* header row, up to `TEAM_LIMITS.panelMaxRows` child rows, a `+N more` row and a
|
|
53
|
+
* mail row that `viewportBudget` knows nothing about. `ScrollViewport` is immune
|
|
54
|
+
* because it MEASURES itself; the rail does not measure - a second
|
|
55
|
+
* measure -> setState -> measure loop is exactly what §1.2 refuses - so it has
|
|
56
|
+
* to subtract.
|
|
57
|
+
*
|
|
58
|
+
* Ink clips overflow from the BOTTOM, so an over-request does not error: it
|
|
59
|
+
* silently eats the last row, which is the `+N below` marker - the one row whose
|
|
60
|
+
* absence is indistinguishable from "the list is short". That is why this is
|
|
61
|
+
* arithmetic rather than a shrug at `overflow: hidden`.
|
|
62
|
+
*/
|
|
63
|
+
export function todoRailRows(viewportBudget, teamActive) {
|
|
64
|
+
if (!Number.isFinite(viewportBudget))
|
|
65
|
+
return 0;
|
|
66
|
+
const reserved = teamActive ? TODO_LIMITS.railReservedRows : 0;
|
|
67
|
+
return Math.max(0, viewportBudget - reserved);
|
|
68
|
+
}
|
|
@@ -25,7 +25,12 @@ const COMMANDS = [
|
|
|
25
25
|
['/plan [on|off|status]', 'Toggle plan mode (same as Shift+Tab)'],
|
|
26
26
|
['/theme <name>', 'auto | warm | cool | light'],
|
|
27
27
|
['/thinking <level>', 'Set thinking level'],
|
|
28
|
+
['/max-tokens [n|auto]', 'Output token cap; no argument reports the effective one'],
|
|
28
29
|
['/team [on|off|max n]', 'Team subagents: status, switch, fan-out width'],
|
|
30
|
+
[
|
|
31
|
+
'/todo [on|off|panel|follow|clear|continue]',
|
|
32
|
+
'Todo planning: status, switches, the rail, follow-through',
|
|
33
|
+
],
|
|
29
34
|
['/tools', 'List active tools'],
|
|
30
35
|
['/clear', 'Clear the visible transcript'],
|
|
31
36
|
['/reset', 'New conversation'],
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* otherwise.
|
|
9
9
|
*/
|
|
10
10
|
import React from 'react';
|
|
11
|
-
import type
|
|
11
|
+
import { type ThinkingLevel } from '@aragon-agent/core';
|
|
12
12
|
import { type LogLevelName } from '../../logging/levels.js';
|
|
13
13
|
import type { Theme } from '../theme.js';
|
|
14
14
|
import type { TermCapabilities } from '../capabilities.js';
|
|
@@ -40,5 +40,16 @@ interface SettingsScreenProps {
|
|
|
40
40
|
caps: TermCapabilities;
|
|
41
41
|
onSave: (values: SettingsValues) => void;
|
|
42
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* The cap this setting will ACTUALLY produce against the selected model.
|
|
45
|
+
*
|
|
46
|
+
* Exported for the tests, and computed on every render rather than in an effect:
|
|
47
|
+
* `resolveOutputTokens` is pure, allocation-light and does no I/O — the ceiling
|
|
48
|
+
* lookup is a `Map.get` plus at most seven regex tests.
|
|
49
|
+
*
|
|
50
|
+
* Without this row the settings screen can only show what the user typed, and
|
|
51
|
+
* "I set 64000 but answers still stop early" has no answer anywhere in the UI.
|
|
52
|
+
*/
|
|
53
|
+
export declare function effectiveCapLine(values: Pick<SettingsValues, 'provider' | 'model' | 'maxTokens'>): string;
|
|
43
54
|
export declare function SettingsScreen({ initial, apiKeys, maxRows, cols, scrollOffset, onScrollClamp, theme, caps, onSave, }: SettingsScreenProps): React.ReactElement;
|
|
44
55
|
export {};
|
|
@@ -10,7 +10,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
10
10
|
*/
|
|
11
11
|
import { useState } from 'react';
|
|
12
12
|
import { Text, useInput } from 'ink';
|
|
13
|
-
import {
|
|
13
|
+
import { DEFAULT_MAX_OUTPUT_TOKENS, resolveOutputTokens, } from '@aragon-agent/core';
|
|
14
|
+
import { ADAPTER_PROVIDERS, THINKING_LEVELS, maskSecret, parseMaxTokensInput, } from '../../config/schema.js';
|
|
14
15
|
import { LOG_LEVEL_NAMES } from '../../logging/levels.js';
|
|
15
16
|
import { pickGlyphs } from '../glyphs.js';
|
|
16
17
|
import { OverlayFrame } from '../layout/OverlayFrame.js';
|
|
@@ -23,6 +24,34 @@ const FIELDS = [
|
|
|
23
24
|
{ key: 'apiKey', label: 'API key', kind: 'secret' },
|
|
24
25
|
{ key: 'logLevel', label: 'Log level', kind: 'enum', options: LOG_LEVEL_NAMES },
|
|
25
26
|
];
|
|
27
|
+
/**
|
|
28
|
+
* The cap this setting will ACTUALLY produce against the selected model.
|
|
29
|
+
*
|
|
30
|
+
* Exported for the tests, and computed on every render rather than in an effect:
|
|
31
|
+
* `resolveOutputTokens` is pure, allocation-light and does no I/O — the ceiling
|
|
32
|
+
* lookup is a `Map.get` plus at most seven regex tests.
|
|
33
|
+
*
|
|
34
|
+
* Without this row the settings screen can only show what the user typed, and
|
|
35
|
+
* "I set 64000 but answers still stop early" has no answer anywhere in the UI.
|
|
36
|
+
*/
|
|
37
|
+
export function effectiveCapLine(values) {
|
|
38
|
+
const parsed = parseMaxTokensInput(values.maxTokens);
|
|
39
|
+
if (parsed.kind === 'invalid')
|
|
40
|
+
return 'Effective: - (not a number; use a value or "auto")';
|
|
41
|
+
const requested = parsed.kind === 'value' ? parsed.value : undefined;
|
|
42
|
+
const resolution = resolveOutputTokens({
|
|
43
|
+
providerId: values.provider,
|
|
44
|
+
modelId: values.model,
|
|
45
|
+
...(requested !== undefined ? { requested } : {}),
|
|
46
|
+
});
|
|
47
|
+
if (resolution.clampedBy === 'ceiling') {
|
|
48
|
+
const ambition = requested ?? DEFAULT_MAX_OUTPUT_TOKENS;
|
|
49
|
+
return `Effective: ${resolution.value} (clamped from ${ambition} by the ${values.model} ceiling)`;
|
|
50
|
+
}
|
|
51
|
+
if (requested === undefined)
|
|
52
|
+
return `Effective: ${resolution.value} (auto)`;
|
|
53
|
+
return `Effective: ${resolution.value}`;
|
|
54
|
+
}
|
|
26
55
|
export function SettingsScreen({ initial, apiKeys, maxRows, cols, scrollOffset, onScrollClamp, theme, caps, onSave, }) {
|
|
27
56
|
const [values, setValues] = useState(initial);
|
|
28
57
|
const [index, setIndex] = useState(0);
|
|
@@ -99,6 +128,10 @@ export function SettingsScreen({ initial, apiKeys, maxRows, cols, scrollOffset,
|
|
|
99
128
|
}
|
|
100
129
|
if (f.kind === 'enum')
|
|
101
130
|
return raw;
|
|
131
|
+
// An empty cap field is AUTO, not "unset". `(none)` would read as a missing
|
|
132
|
+
// setting, which is the one thing this field can never be.
|
|
133
|
+
if (f.key === 'maxTokens' && raw.length === 0)
|
|
134
|
+
return 'auto';
|
|
102
135
|
return raw.length > 0 ? raw : selected ? '(type to set)' : '(none)';
|
|
103
136
|
};
|
|
104
137
|
// One element per row, each `wrap="truncate"` — the contract for OverlayFrame's
|
|
@@ -108,6 +141,10 @@ export function SettingsScreen({ initial, apiKeys, maxRows, cols, scrollOffset,
|
|
|
108
141
|
const selected = i === index;
|
|
109
142
|
return (_jsxs(Text, { wrap: "truncate", children: [_jsx(Text, { color: selected ? theme.accent : theme.muted, children: selected ? `${glyphs.caret} ` : ' ' }), _jsx(Text, { color: selected ? theme.assistant : theme.muted, children: (f.key === 'apiKey' ? `API key (${values.provider})` : f.label).padEnd(18) }), _jsx(Text, { color: selected ? theme.primary : theme.muted, children: displayValue(f, selected) }), f.kind === 'enum' && selected && (_jsxs(Text, { color: theme.muted, children: [' (', glyphs.arrowLeft, "/", glyphs.arrowRight, ')'] }))] }, f.key));
|
|
110
143
|
});
|
|
144
|
+
// One element, `wrap="truncate"`, pushed like every other row — OverlayFrame's
|
|
145
|
+
// controlled mode slices by ELEMENT, so a row that wraps desynchronises the
|
|
146
|
+
// position indicator.
|
|
147
|
+
rows.push(_jsx(Text, { wrap: "truncate", color: theme.muted, children: effectiveCapLine(values) }, "__effective"));
|
|
111
148
|
rows.push(_jsx(Text, { wrap: "truncate", color: theme.muted, children: "Enter saves. Keys persist to the config file (0600)." }, "__save"));
|
|
112
149
|
return (_jsx(OverlayFrame, { title: "Settings", hint: `${glyphs.arrowUp}${glyphs.arrowDown} field ${glyphs.midDot} ${glyphs.arrowLeft}${glyphs.arrowRight} change ${glyphs.midDot} Enter save ${glyphs.midDot} Esc close`, maxRows: maxRows, cols: cols, rows: rows, scrollOffset: scrollOffset, onScrollClamp: onScrollClamp, theme: theme, caps: caps }));
|
|
113
150
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aragon-agent/cli",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.6",
|
|
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",
|
|
@@ -46,12 +46,13 @@
|
|
|
46
46
|
"scripts": {
|
|
47
47
|
"build": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.json && node scripts/prepend-shebang.mjs",
|
|
48
48
|
"dev": "tsc -p tsconfig.json --watch",
|
|
49
|
+
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.test.json --noEmit",
|
|
49
50
|
"test": "vitest run",
|
|
50
51
|
"start": "node dist/cli.js",
|
|
51
52
|
"prepublishOnly": "npm run build"
|
|
52
53
|
},
|
|
53
54
|
"dependencies": {
|
|
54
|
-
"@aragon-agent/core": "^0.2.
|
|
55
|
+
"@aragon-agent/core": "^0.2.6",
|
|
55
56
|
"chalk": "^5.6.2",
|
|
56
57
|
"cli-highlight": "^2.0.0",
|
|
57
58
|
"commander": "^12.1.0",
|