@aragon-agent/cli 0.6.46 → 0.6.47

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 (49) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +53 -6
  3. package/dist/agent/coalesce.d.ts +4 -0
  4. package/dist/agent/coalesce.js +13 -0
  5. package/dist/agent/controller.d.ts +21 -0
  6. package/dist/agent/controller.js +56 -3
  7. package/dist/agent/reducer.d.ts +20 -0
  8. package/dist/agent/reducer.js +31 -2
  9. package/dist/agent/user-attention.d.ts +17 -0
  10. package/dist/agent/user-attention.js +32 -0
  11. package/dist/cli.js +2 -3
  12. package/dist/config/load.js +4 -25
  13. package/dist/config/schema.d.ts +4 -4
  14. package/dist/config/schema.js +7 -1
  15. package/dist/proc/limits.d.ts +27 -13
  16. package/dist/proc/limits.js +27 -13
  17. package/dist/proc/progress.d.ts +7 -0
  18. package/dist/proc/progress.js +35 -7
  19. package/dist/proc/prompt.js +7 -4
  20. package/dist/proc/supervisor.js +7 -1
  21. package/dist/proc/types.d.ts +6 -0
  22. package/dist/proc/wait-plan.d.ts +39 -0
  23. package/dist/proc/wait-plan.js +77 -0
  24. package/dist/proc/wait-view.d.ts +65 -0
  25. package/dist/proc/wait-view.js +66 -0
  26. package/dist/proc/wait.d.ts +36 -3
  27. package/dist/proc/wait.js +67 -4
  28. package/dist/session/checkpoint.js +2 -0
  29. package/dist/session/persist.js +19 -2
  30. package/dist/session/validate-session.js +3 -0
  31. package/dist/tools/job-tools.d.ts +13 -2
  32. package/dist/tools/job-tools.js +156 -33
  33. package/dist/ui/ActivityLine.js +5 -2
  34. package/dist/ui/App.js +34 -0
  35. package/dist/ui/StatusBar.d.ts +1 -0
  36. package/dist/ui/Transcript.js +7 -0
  37. package/dist/ui/entries/ToolCard.js +11 -2
  38. package/dist/ui/entries/WaitCard.d.ts +37 -0
  39. package/dist/ui/entries/WaitCard.js +92 -0
  40. package/dist/ui/interaction-copy.d.ts +2 -0
  41. package/dist/ui/interaction-copy.js +3 -0
  42. package/dist/ui/layout/status-layout.d.ts +1 -0
  43. package/dist/ui/layout/status-layout.js +10 -1
  44. package/dist/ui/layout/virtual-window.js +7 -1
  45. package/dist/ui/layout/wait-bar.d.ts +34 -0
  46. package/dist/ui/layout/wait-bar.js +48 -0
  47. package/dist/ui/run-status-row.d.ts +4 -2
  48. package/dist/ui/scrollback/live-preview.js +12 -0
  49. package/package.json +2 -2
@@ -0,0 +1,37 @@
1
+ /**
2
+ * WaitCard - the five-row card a running `job_wait` is drawn as
3
+ * (extended-job-wait §3.8.2).
4
+ *
5
+ * ASCII ONLY: every non-ASCII cell is a `pickGlyphs` result and every sentence the
6
+ * user did not get from the job itself is in `interactionCopy`.
7
+ *
8
+ * FIVE ROWS, IN EVERY STATE (I-10). A branch may change what a row SAYS, never how
9
+ * many rows there are: `estimateEntryRows` charges exactly `separation + 5`, and a
10
+ * card that is one row short makes the viewport jump while one row long makes the
11
+ * height estimate an under-count - the direction `virtual-window.ts` names unsafe.
12
+ * Every row is `wrap="truncate"` for the same reason.
13
+ *
14
+ * ONE CLOCK. Every number is a subtraction between an epoch stamped by
15
+ * `buildWaitView` and the `nowSec` the transcript already ticks at 1 Hz; there is
16
+ * no timer in this file, and the spinner is the app's shared factory, which this
17
+ * card REPLACES `ToolCard`'s badge with rather than adding to.
18
+ */
19
+ import React from 'react';
20
+ import type { Theme } from '../theme.js';
21
+ import type { TermCapabilities } from '../capabilities.js';
22
+ import type { WaitView } from '../../proc/wait-view.js';
23
+ export interface WaitCardProps {
24
+ view: WaitView;
25
+ /** Wall-clock seconds from the transcript's 1 Hz clock; absent before the first tick. */
26
+ nowSec?: number | undefined;
27
+ reducedMotion?: boolean | undefined;
28
+ theme: Theme;
29
+ caps: TermCapabilities;
30
+ }
31
+ declare function WaitCardImpl(props: WaitCardProps): React.ReactElement;
32
+ /**
33
+ * `React.memo` with the DEFAULT comparator: the reducer writes a fresh `view`
34
+ * object once a second, which is exactly the one change that must re-render.
35
+ */
36
+ export declare const WaitCard: React.MemoExoticComponent<typeof WaitCardImpl>;
37
+ export {};
@@ -0,0 +1,92 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * WaitCard - the five-row card a running `job_wait` is drawn as
4
+ * (extended-job-wait §3.8.2).
5
+ *
6
+ * ASCII ONLY: every non-ASCII cell is a `pickGlyphs` result and every sentence the
7
+ * user did not get from the job itself is in `interactionCopy`.
8
+ *
9
+ * FIVE ROWS, IN EVERY STATE (I-10). A branch may change what a row SAYS, never how
10
+ * many rows there are: `estimateEntryRows` charges exactly `separation + 5`, and a
11
+ * card that is one row short makes the viewport jump while one row long makes the
12
+ * height estimate an under-count - the direction `virtual-window.ts` names unsafe.
13
+ * Every row is `wrap="truncate"` for the same reason.
14
+ *
15
+ * ONE CLOCK. Every number is a subtraction between an epoch stamped by
16
+ * `buildWaitView` and the `nowSec` the transcript already ticks at 1 Hz; there is
17
+ * no timer in this file, and the spinner is the app's shared factory, which this
18
+ * card REPLACES `ToolCard`'s badge with rather than adding to.
19
+ */
20
+ import React from 'react';
21
+ import { Box, Text, useStdout } from 'ink';
22
+ import { pickGlyphs } from '../glyphs.js';
23
+ import { liveSpinner } from '../ActivityLine.js';
24
+ import { railBorderProps } from '../layout/Gutter.js';
25
+ import { interactionCopy } from '../interaction-copy.js';
26
+ import { WAIT_BAR_MIN_COLS, barCellsFor, formatWaitClock, percentOf, renderBar, } from '../layout/wait-bar.js';
27
+ /** Empty `<Text>` measures zero rows in Ink, so a blank row is drawn as a space. */
28
+ function filled(text) {
29
+ return text.length > 0 ? text : ' ';
30
+ }
31
+ function WaitCardImpl(props) {
32
+ const { view, reducedMotion, theme, caps } = props;
33
+ const glyphs = pickGlyphs(caps);
34
+ const { stdout } = useStdout();
35
+ const cols = stdout?.columns ?? 80;
36
+ // Before the first tick the clock reads the instant the wait began.
37
+ const nowMs = Math.max(view.waitStartedAt, props.nowSec !== undefined ? props.nowSec * 1000 : view.waitStartedAt);
38
+ const waited = nowMs - view.waitStartedAt;
39
+ const remaining = Math.max(0, view.upToMs - waited);
40
+ const upTo = formatWaitClock(view.upToMs);
41
+ const dot = ` ${glyphs.midDot} `;
42
+ // ROW 1 - what, and the clock.
43
+ const spinner = liveSpinner(reducedMotion ?? false, caps);
44
+ const title = `Waiting for ${view.jobLabel}`;
45
+ const clock = `${formatWaitClock(waited)} of ${upTo}`;
46
+ // ROW 2 - the bar. THE JOB'S OWN PROGRESS WINS; with none, the bar shows the wait
47
+ // window itself and the words say so (D-10), so the two meanings never share a
48
+ // bar silently.
49
+ const jobFraction = view.progress?.fraction ?? null;
50
+ const windowFraction = view.upToMs > 0 ? waited / view.upToMs : 0;
51
+ const barFraction = jobFraction ?? windowFraction;
52
+ const showBar = cols >= WAIT_BAR_MIN_COLS;
53
+ const bar = showBar
54
+ ? `${renderBar(barFraction, barCellsFor(cols), glyphs)} `
55
+ : '';
56
+ let barText;
57
+ if (jobFraction !== null && view.progress) {
58
+ barText =
59
+ view.progress.kind === 'percent'
60
+ ? view.progress.text
61
+ : `${percentOf(jobFraction)}% ${view.progress.text}`;
62
+ }
63
+ else {
64
+ barText = `${percentOf(windowFraction)}% of this ${upTo} wait`;
65
+ if (view.progress)
66
+ barText += ` ${view.progress.text}`;
67
+ }
68
+ // ROW 3 - the two clocks.
69
+ let clocks;
70
+ if (view.jobLabel.endsWith(' jobs')) {
71
+ const rule = view.mode === 'any' ? 'ANY finishes' : 'ALL finish';
72
+ clocks = `${view.liveJobs} ${view.liveJobs === 1 ? 'job' : 'jobs'} live${dot}this wait ends when ${rule}`;
73
+ }
74
+ else {
75
+ clocks =
76
+ `job ${view.status} ${formatWaitClock(Math.max(0, nowMs - view.jobStartedAt))}${dot}` +
77
+ `this wait ends in ${formatWaitClock(remaining)}, or sooner if the job finishes`;
78
+ }
79
+ // ROW 4 - what the job last said, or a calm note that silence is not failure (D-11).
80
+ const quietMs = Math.max(0, nowMs - view.lastOutputAt);
81
+ const quiet = view.lastRow !== undefined && quietMs > view.stallSeconds * 1000;
82
+ const lastRowText = quiet
83
+ ? `quiet for ${formatWaitClock(quietMs)} - the job is still alive; this is not a failure`
84
+ : (view.lastRow ?? 'no output yet');
85
+ const ago = view.lastRow !== undefined && !quiet ? `${formatWaitClock(quietMs)} ago` : '';
86
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { flexDirection: "row", children: [spinner ? _jsxs(Text, { color: theme.toolRunning, children: [spinner, " "] }) : (_jsxs(Text, { color: theme.toolRunning, children: [glyphs.spinnerStill, " "] })), _jsx(Text, { color: theme.accent, bold: true, children: title }), _jsx(Box, { flexGrow: 1, flexShrink: 1, minWidth: 0, children: _jsx(Text, { color: theme.muted, wrap: "truncate", children: view.command.length > 0 ? ` ${view.command}` : ' ' }) }), _jsx(Box, { flexShrink: 0, children: _jsxs(Text, { color: theme.muted, children: [" ", clock] }) })] }), _jsxs(Box, { flexDirection: "column", flexShrink: 0, paddingLeft: 1, ...railBorderProps(glyphs.railVertical, theme.border), children: [_jsxs(Text, { wrap: "truncate", children: [_jsx(Text, { color: theme.toolRunning, children: bar }), _jsx(Text, { color: theme.primary, children: filled(barText) })] }), _jsx(Text, { color: theme.muted, wrap: "truncate", children: filled(clocks) }), _jsxs(Box, { flexDirection: "row", children: [_jsx(Box, { flexGrow: 1, flexShrink: 1, minWidth: 0, children: _jsx(Text, { color: quiet ? theme.noticeWarn : theme.muted, wrap: "truncate", children: filled(lastRowText) }) }), _jsx(Box, { flexShrink: 0, children: _jsx(Text, { color: theme.muted, children: ago.length > 0 ? ` ${ago}` : ' ' }) })] }), _jsxs(Text, { color: theme.muted, wrap: "truncate", children: [interactionCopy.waitHintSend, dot, interactionCopy.waitHintStop] })] })] }));
87
+ }
88
+ /**
89
+ * `React.memo` with the DEFAULT comparator: the reducer writes a fresh `view`
90
+ * object once a second, which is exactly the one change that must re-render.
91
+ */
92
+ export const WaitCard = React.memo(WaitCardImpl);
@@ -77,6 +77,8 @@ export declare const interactionCopy: {
77
77
  readonly shiftNewline: "Shift+Enter newline needs terminal support";
78
78
  readonly mode: "Shift+Tab switch mode";
79
79
  readonly update: "/update";
80
+ readonly waitHintSend: "Send a message to end the wait early";
81
+ readonly waitHintStop: "Esc x2 stops the whole run";
80
82
  readonly idlePlaceholder: "Ask a question or describe a task...";
81
83
  readonly runningPlaceholder: "Add a follow-up...";
82
84
  };
@@ -34,5 +34,8 @@ export const interactionCopy = {
34
34
  governPausePending: 'pause pending: /gov pause cancel',
35
35
  help: '/help', shiftNewline: 'Shift+Enter newline needs terminal support',
36
36
  mode: 'Shift+Tab switch mode', update: '/update',
37
+ // The wait card's hint row (extended-job-wait): a user staring at a 20-minute
38
+ // wait needs to know they are not trapped in it.
39
+ waitHintSend: 'Send a message to end the wait early', waitHintStop: 'Esc x2 stops the whole run',
37
40
  idlePlaceholder: 'Ask a question or describe a task...', runningPlaceholder: 'Add a follow-up...',
38
41
  };
@@ -26,6 +26,7 @@ export interface StatusLayoutInput {
26
26
  wait?: {
27
27
  jobId: string;
28
28
  upToSeconds: number;
29
+ elapsedSeconds?: number;
29
30
  };
30
31
  runOutcome?: 'none' | 'ended' | 'interrupted' | 'failed';
31
32
  spinner?: string;
@@ -31,7 +31,16 @@ export function phaseLabels(input) {
31
31
  // quiet terminal actually has. Both forms carry it - the short rung is
32
32
  // truncated by width, not reworded.
33
33
  if (input.wait) {
34
- const label = `Waiting on ${cleanStatusText(input.wait.jobId)} ` +
34
+ const id = cleanStatusText(input.wait.jobId);
35
+ // WITH A CLOCK (extended-job-wait): `Waiting on t3 4m12s/10m00s`, and a shorter
36
+ // rung that keeps the id and the elapsed time. Without one the original
37
+ // sentence is byte-identical, which the older assertions rely on.
38
+ if (input.wait.elapsedSeconds !== undefined) {
39
+ const elapsed = shortDuration(Math.max(0, input.wait.elapsedSeconds) * 1000);
40
+ const upTo = shortDuration(Math.max(0, input.wait.upToSeconds) * 1000);
41
+ return [`Wait ${id} ${elapsed}`, `Waiting on ${id} ${elapsed}/${upTo}`];
42
+ }
43
+ const label = `Waiting on ${id} ` +
35
44
  `(up to ${Math.max(0, Math.round(input.wait.upToSeconds))}s)`;
36
45
  return [label, label];
37
46
  }
@@ -34,6 +34,7 @@
34
34
  */
35
35
  import stringWidth from 'string-width';
36
36
  import { governanceCardRows } from './governance-card.js';
37
+ import { WAIT_CARD_ROWS } from './wait-bar.js';
37
38
  import { FAST_LIMITS } from '../../fast/limits.js';
38
39
  import { COMPACTION_LIMITS } from '../../compaction/limits.js';
39
40
  import { GUTTER_WIDTH } from './Gutter.js';
@@ -96,7 +97,7 @@ export function entryRevision(entry) {
96
97
  // field makes it seven, and a term that is not O(1) would put the cost this
97
98
  // module exists to remove back on every frame.
98
99
  case 'tool':
99
- return `t${entry.status}.${entry.argsRaw.length}.${entry.preview?.length ?? 0}.${entry.durationMs ?? -1}.${entry.patch?.lineCount ?? -1}.${entry.liveSeq ?? -1}`;
100
+ return `t${entry.status}.${entry.argsRaw.length}.${entry.preview?.length ?? 0}.${entry.durationMs ?? -1}.${entry.patch?.lineCount ?? -1}.${entry.liveSeq ?? -1}.w${entry.waitSeq ?? -1}`;
100
101
  case 'team':
101
102
  return `m${entry.active ? 1 : 0}.${entry.runs.length}.${entry.runs
102
103
  .map((r) => r.phase[0])
@@ -320,6 +321,11 @@ export function estimateEntryRows(entry, cols, density, expanded, thinkingVisibl
320
321
  // string). A `!settled` block alone would drop the second into
321
322
  // `wrappedRows(entry.preview, usable)` with `undefined`.
322
323
  if (!settled) {
324
+ // A RUNNING `job_wait` WITH A VIEW IS THE FIVE-ROW WAIT CARD, EXACTLY
325
+ // (extended-job-wait I-10): constant height is what lets this be an
326
+ // equality rather than an upper bound. Keep in step with `WAIT_CARD_ROWS`.
327
+ if (entry.name === 'job_wait' && entry.wait)
328
+ return separation + WAIT_CARD_ROWS;
323
329
  const live = entry.live?.length ?? 0;
324
330
  if (live === 0)
325
331
  return separation + 1;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Pure pieces of the wait card (extended-job-wait §3.8.2).
3
+ *
4
+ * ASCII ONLY: `src/ui/**` is inside the glyph scanner's scope, so every
5
+ * non-ASCII cell arrives as an argument from `pickGlyphs`.
6
+ */
7
+ /**
8
+ * Rows the wait card occupies, header included, in every state (I-10).
9
+ * Here rather than beside the component so `virtual-window.ts` can import it
10
+ * without pulling React into a pure layout module.
11
+ */
12
+ export declare const WAIT_CARD_ROWS = 5;
13
+ /** The two glyphs a bar is made of; a subset of the `pickGlyphs` result. */
14
+ export interface BarGlyphs {
15
+ gaugeFull: string;
16
+ gaugeEmpty: string;
17
+ }
18
+ /** Narrowest terminal that still gets a bar; below it the row is text only. */
19
+ export declare const WAIT_BAR_MIN_COLS = 40;
20
+ /** Bar width for a terminal `cols` wide: about a third of the row, 8..28 cells. */
21
+ export declare function barCellsFor(cols: number): number;
22
+ /**
23
+ * A `cells`-wide bar for `fraction` in 0..1.
24
+ *
25
+ * AN UNFINISHED BAR IS NEVER FULL (I-8): anything strictly between 0 and 1 shows
26
+ * at least one filled and at least one empty cell, so a 99.9% job does not read
27
+ * as done. `NaN`, negatives and non-finite values are an empty bar rather than a
28
+ * throw - this runs inside a render.
29
+ */
30
+ export declare function renderBar(fraction: number, cells: number, glyphs: BarGlyphs): string;
31
+ /** `4m12s`, `10m00s`, `45s` - the one clock format of the card and the status bar. */
32
+ export declare function formatWaitClock(ms: number): string;
33
+ /** Whole percent for a 0..1 fraction, clamped. */
34
+ export declare function percentOf(fraction: number): number;
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Pure pieces of the wait card (extended-job-wait §3.8.2).
3
+ *
4
+ * ASCII ONLY: `src/ui/**` is inside the glyph scanner's scope, so every
5
+ * non-ASCII cell arrives as an argument from `pickGlyphs`.
6
+ */
7
+ import { shortDuration } from './status-layout.js';
8
+ /**
9
+ * Rows the wait card occupies, header included, in every state (I-10).
10
+ * Here rather than beside the component so `virtual-window.ts` can import it
11
+ * without pulling React into a pure layout module.
12
+ */
13
+ export const WAIT_CARD_ROWS = 5;
14
+ /** Narrowest terminal that still gets a bar; below it the row is text only. */
15
+ export const WAIT_BAR_MIN_COLS = 40;
16
+ /** Bar width for a terminal `cols` wide: about a third of the row, 8..28 cells. */
17
+ export function barCellsFor(cols) {
18
+ if (!Number.isFinite(cols))
19
+ return 8;
20
+ return Math.max(8, Math.min(28, Math.floor((cols - 4) * 0.35)));
21
+ }
22
+ /**
23
+ * A `cells`-wide bar for `fraction` in 0..1.
24
+ *
25
+ * AN UNFINISHED BAR IS NEVER FULL (I-8): anything strictly between 0 and 1 shows
26
+ * at least one filled and at least one empty cell, so a 99.9% job does not read
27
+ * as done. `NaN`, negatives and non-finite values are an empty bar rather than a
28
+ * throw - this runs inside a render.
29
+ */
30
+ export function renderBar(fraction, cells, glyphs) {
31
+ const width = Math.max(1, Math.floor(cells));
32
+ if (!Number.isFinite(fraction) || fraction <= 0)
33
+ return glyphs.gaugeEmpty.repeat(width);
34
+ if (fraction >= 1)
35
+ return glyphs.gaugeFull.repeat(width);
36
+ const filled = Math.min(width - 1, Math.max(1, Math.round(fraction * width)));
37
+ return glyphs.gaugeFull.repeat(filled) + glyphs.gaugeEmpty.repeat(width - filled);
38
+ }
39
+ /** `4m12s`, `10m00s`, `45s` - the one clock format of the card and the status bar. */
40
+ export function formatWaitClock(ms) {
41
+ return shortDuration(ms);
42
+ }
43
+ /** Whole percent for a 0..1 fraction, clamped. */
44
+ export function percentOf(fraction) {
45
+ if (!Number.isFinite(fraction))
46
+ return 0;
47
+ return Math.max(0, Math.min(100, Math.floor(fraction * 100)));
48
+ }
@@ -22,12 +22,14 @@ export interface RunActivity {
22
22
  *
23
23
  * `Running job_wait` is a TOOL NAME; `Waiting on t3 (up to 30s)` is a STATE, and
24
24
  * the state is what answers the user's two questions - what is it waiting for,
25
- * and how long may that take. No countdown: a ticking number would need its own
26
- * re-render, and the sentence is already complete.
25
+ * and how long may that take. `elapsedSeconds`, when present (extended-job-wait),
26
+ * turns the sentence into a running clock - the 1 Hz transcript tick already
27
+ * causes that render, so no timer is added.
27
28
  */
28
29
  wait?: {
29
30
  jobId: string;
30
31
  upToSeconds: number;
32
+ elapsedSeconds?: number;
31
33
  };
32
34
  }
33
35
  export interface RunRowPlanInput {
@@ -22,6 +22,7 @@ import { wrapToRows } from '../layout/wrap-rows.js';
22
22
  import { isExcluded } from './settled-boundary.js';
23
23
  import { isLiveTeamCard, outcomePhrase, rosterCounts } from '../team-status.js';
24
24
  import { clipLine } from './writer-shapes.js';
25
+ import { formatWaitClock } from '../layout/wait-bar.js';
25
26
  const MAX_TEAM_RUN_ROWS = 3;
26
27
  const TOOL_LIVE_ROWS = 6;
27
28
  function firstLine(text) {
@@ -49,6 +50,17 @@ function assistantRows(entry, cols, rows, thinkingVisible) {
49
50
  return out;
50
51
  }
51
52
  function toolRows(entry, cols) {
53
+ // A RUNNING WAIT IS ONE LINE HERE, not a miniature of the five-row card
54
+ // (extended-job-wait RV-3). `job_wait` never streams, so `live` is empty and the
55
+ // generic row would say only `> job_wait`; the clock comes from the view's own
56
+ // epoch stamps (`beatAt` is the view's last beat), keeping this function pure.
57
+ if (entry.name === 'job_wait' && entry.status === 'running' && entry.wait) {
58
+ const { wait } = entry;
59
+ const waited = Math.max(0, wait.beatAt - wait.waitStartedAt);
60
+ return [
61
+ fit(`> Waiting for ${wait.jobLabel} ${formatWaitClock(waited)} of ${formatWaitClock(wait.upToMs)}`, cols),
62
+ ];
63
+ }
52
64
  const head = entry.label && entry.label.length > 0 ? entry.label : entry.name;
53
65
  const out = [fit(`${entry.status === 'running' ? '>' : '.'} ${head}`, cols)];
54
66
  const live = (entry.live ?? []).slice(-TOOL_LIVE_ROWS);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aragon-agent/cli",
3
- "version": "0.6.46",
3
+ "version": "0.6.47",
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.58",
59
+ "@aragon-agent/core": "^0.2.59",
60
60
  "chalk": "^5.6.2",
61
61
  "cli-highlight": "^2.0.0",
62
62
  "commander": "^12.1.0",