@aragon-agent/cli 0.4.3
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 +292 -0
- package/README.md +558 -0
- package/dist/agent/coalesce.d.ts +14 -0
- package/dist/agent/coalesce.js +41 -0
- package/dist/agent/controller.d.ts +132 -0
- package/dist/agent/controller.js +332 -0
- package/dist/agent/headless.d.ts +22 -0
- package/dist/agent/headless.js +74 -0
- package/dist/agent/reducer.d.ts +181 -0
- package/dist/agent/reducer.js +420 -0
- package/dist/agent/system-prompt.d.ts +30 -0
- package/dist/agent/system-prompt.js +58 -0
- package/dist/agent/usage.d.ts +13 -0
- package/dist/agent/usage.js +41 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.js +482 -0
- package/dist/commands/builtins.d.ts +16 -0
- package/dist/commands/builtins.js +223 -0
- package/dist/commands/registry.d.ts +48 -0
- package/dist/commands/registry.js +45 -0
- package/dist/commands/skills.d.ts +22 -0
- package/dist/commands/skills.js +625 -0
- package/dist/config/app-paths.d.ts +11 -0
- package/dist/config/app-paths.js +16 -0
- package/dist/config/env.d.ts +28 -0
- package/dist/config/env.js +92 -0
- package/dist/config/load.d.ts +48 -0
- package/dist/config/load.js +158 -0
- package/dist/config/migrate-legacy-state.d.ts +78 -0
- package/dist/config/migrate-legacy-state.js +181 -0
- package/dist/config/schema.d.ts +249 -0
- package/dist/config/schema.js +247 -0
- package/dist/config/store.d.ts +44 -0
- package/dist/config/store.js +126 -0
- package/dist/input/keymap.d.ts +20 -0
- package/dist/input/keymap.js +85 -0
- package/dist/session/persist.d.ts +24 -0
- package/dist/session/persist.js +51 -0
- package/dist/skills/archive.d.ts +41 -0
- package/dist/skills/archive.js +152 -0
- package/dist/skills/cli-commands.d.ts +52 -0
- package/dist/skills/cli-commands.js +502 -0
- package/dist/skills/fetch-source.d.ts +104 -0
- package/dist/skills/fetch-source.js +448 -0
- package/dist/skills/installer.d.ts +117 -0
- package/dist/skills/installer.js +414 -0
- package/dist/skills/lock.d.ts +75 -0
- package/dist/skills/lock.js +223 -0
- package/dist/skills/manifest.d.ts +47 -0
- package/dist/skills/manifest.js +95 -0
- package/dist/skills/node-host.d.ts +23 -0
- package/dist/skills/node-host.js +59 -0
- package/dist/skills/paths.d.ts +61 -0
- package/dist/skills/paths.js +107 -0
- package/dist/skills/service.d.ts +256 -0
- package/dist/skills/service.js +730 -0
- package/dist/skills/tools.d.ts +35 -0
- package/dist/skills/tools.js +164 -0
- package/dist/skills/updater.d.ts +101 -0
- package/dist/skills/updater.js +330 -0
- package/dist/skills/usage.d.ts +72 -0
- package/dist/skills/usage.js +216 -0
- package/dist/tools/bash-tool.d.ts +12 -0
- package/dist/tools/bash-tool.js +131 -0
- package/dist/tools/diff.d.ts +15 -0
- package/dist/tools/diff.js +50 -0
- package/dist/tools/fs-tools.d.ts +16 -0
- package/dist/tools/fs-tools.js +215 -0
- package/dist/tools/index.d.ts +93 -0
- package/dist/tools/index.js +157 -0
- package/dist/tools/search-tools.d.ts +11 -0
- package/dist/tools/search-tools.js +225 -0
- package/dist/ui/App.d.ts +24 -0
- package/dist/ui/App.js +522 -0
- package/dist/ui/AutocompletePopup.d.ts +21 -0
- package/dist/ui/AutocompletePopup.js +19 -0
- package/dist/ui/Composer.d.ts +40 -0
- package/dist/ui/Composer.js +61 -0
- package/dist/ui/Header.d.ts +30 -0
- package/dist/ui/Header.js +25 -0
- package/dist/ui/Logo.d.ts +50 -0
- package/dist/ui/Logo.js +85 -0
- package/dist/ui/Markdown.d.ts +23 -0
- package/dist/ui/Markdown.js +122 -0
- package/dist/ui/PromptInput.d.ts +81 -0
- package/dist/ui/PromptInput.js +383 -0
- package/dist/ui/SessionOpener.d.ts +30 -0
- package/dist/ui/SessionOpener.js +12 -0
- package/dist/ui/StatusBar.d.ts +39 -0
- package/dist/ui/StatusBar.js +43 -0
- package/dist/ui/ToastStack.d.ts +24 -0
- package/dist/ui/ToastStack.js +38 -0
- package/dist/ui/Transcript.d.ts +62 -0
- package/dist/ui/Transcript.js +128 -0
- package/dist/ui/capabilities.d.ts +25 -0
- package/dist/ui/capabilities.js +59 -0
- package/dist/ui/console-bridge.d.ts +19 -0
- package/dist/ui/console-bridge.js +52 -0
- package/dist/ui/density.d.ts +26 -0
- package/dist/ui/density.js +34 -0
- package/dist/ui/entries/AssistantEntry.d.ts +23 -0
- package/dist/ui/entries/AssistantEntry.js +13 -0
- package/dist/ui/entries/EntryFrame.d.ts +23 -0
- package/dist/ui/entries/EntryFrame.js +6 -0
- package/dist/ui/entries/ToolCard.d.ts +38 -0
- package/dist/ui/entries/ToolCard.js +72 -0
- package/dist/ui/entries/ToolPreview.d.ts +57 -0
- package/dist/ui/entries/ToolPreview.js +144 -0
- package/dist/ui/entries/UserEntry.d.ts +14 -0
- package/dist/ui/entries/UserEntry.js +5 -0
- package/dist/ui/exit-snapshot.d.ts +27 -0
- package/dist/ui/exit-snapshot.js +26 -0
- package/dist/ui/gauge.d.ts +24 -0
- package/dist/ui/gauge.js +36 -0
- package/dist/ui/glyphs.d.ts +87 -0
- package/dist/ui/glyphs.js +127 -0
- package/dist/ui/gradient.d.ts +11 -0
- package/dist/ui/gradient.js +50 -0
- package/dist/ui/layout/AppShell.d.ts +24 -0
- package/dist/ui/layout/AppShell.js +9 -0
- package/dist/ui/layout/Gutter.d.ts +67 -0
- package/dist/ui/layout/Gutter.js +42 -0
- package/dist/ui/layout/OverlayFrame.d.ts +62 -0
- package/dist/ui/layout/OverlayFrame.js +92 -0
- package/dist/ui/layout/ScrollViewport.d.ts +33 -0
- package/dist/ui/layout/ScrollViewport.js +71 -0
- package/dist/ui/layout/budget.d.ts +42 -0
- package/dist/ui/layout/budget.js +47 -0
- package/dist/ui/layout/frame.d.ts +58 -0
- package/dist/ui/layout/frame.js +75 -0
- package/dist/ui/layout/overlay-window.d.ts +43 -0
- package/dist/ui/layout/overlay-window.js +51 -0
- package/dist/ui/layout/scroll.d.ts +28 -0
- package/dist/ui/layout/scroll.js +76 -0
- package/dist/ui/layout/useTerminalSize.d.ts +13 -0
- package/dist/ui/layout/useTerminalSize.js +50 -0
- package/dist/ui/markdown-blocks.d.ts +62 -0
- package/dist/ui/markdown-blocks.js +120 -0
- package/dist/ui/overlays/ConfirmDialog.d.ts +30 -0
- package/dist/ui/overlays/ConfirmDialog.js +25 -0
- package/dist/ui/overlays/HelpOverlay.d.ts +17 -0
- package/dist/ui/overlays/HelpOverlay.js +60 -0
- package/dist/ui/overlays/ModelPicker.d.ts +29 -0
- package/dist/ui/overlays/ModelPicker.js +29 -0
- package/dist/ui/overlays/SettingsScreen.d.ts +37 -0
- package/dist/ui/overlays/SettingsScreen.js +106 -0
- package/dist/ui/palettes.d.ts +79 -0
- package/dist/ui/palettes.js +115 -0
- package/dist/ui/screen.d.ts +27 -0
- package/dist/ui/screen.js +57 -0
- package/dist/ui/theme.d.ts +78 -0
- package/dist/ui/theme.js +127 -0
- package/dist/ui/transcript-text.d.ts +27 -0
- package/dist/ui/transcript-text.js +110 -0
- package/package.json +73 -0
- package/skills/skill-creator/SKILL.md +96 -0
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Search tools: glob / grep (spec §3.6).
|
|
3
|
+
*
|
|
4
|
+
* `glob` uses tinyglobby and sorts matches by mtime (newest first). `grep`
|
|
5
|
+
* prefers ripgrep when it is on PATH and falls back to a pure-JS scan otherwise;
|
|
6
|
+
* both produce `path:line:text` output.
|
|
7
|
+
*/
|
|
8
|
+
import { spawn } from 'node:child_process';
|
|
9
|
+
import { promises as fs } from 'node:fs';
|
|
10
|
+
import { isAbsolute, join, relative, resolve } from 'node:path';
|
|
11
|
+
import { glob as tinyGlob } from 'tinyglobby';
|
|
12
|
+
import { defineTool, errorResult, textResult, } from '@aragon-agent/core';
|
|
13
|
+
const MAX_GREP_MATCHES = 500;
|
|
14
|
+
const MAX_FILE_BYTES = 5_000_000;
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// glob
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
export function makeGlob(deps) {
|
|
19
|
+
return defineTool({
|
|
20
|
+
name: 'glob',
|
|
21
|
+
label: 'Glob',
|
|
22
|
+
description: 'Find files matching a glob pattern (e.g. "src/**/*.ts"). Returns paths ' +
|
|
23
|
+
'relative to the working directory, sorted by modification time (newest first).',
|
|
24
|
+
parameters: {
|
|
25
|
+
type: 'object',
|
|
26
|
+
properties: {
|
|
27
|
+
pattern: { type: 'string', description: 'Glob pattern.' },
|
|
28
|
+
cwd: { type: 'string', description: 'Directory to search from (default: working directory).' },
|
|
29
|
+
},
|
|
30
|
+
required: ['pattern'],
|
|
31
|
+
},
|
|
32
|
+
async execute(_id, rawParams) {
|
|
33
|
+
const params = rawParams;
|
|
34
|
+
const base = params.cwd
|
|
35
|
+
? isAbsolute(params.cwd)
|
|
36
|
+
? params.cwd
|
|
37
|
+
: resolve(deps.getCwd(), params.cwd)
|
|
38
|
+
: deps.getCwd();
|
|
39
|
+
try {
|
|
40
|
+
const matches = await tinyGlob(params.pattern, {
|
|
41
|
+
cwd: base,
|
|
42
|
+
absolute: false,
|
|
43
|
+
dot: false,
|
|
44
|
+
onlyFiles: true,
|
|
45
|
+
});
|
|
46
|
+
if (matches.length === 0)
|
|
47
|
+
return textResult('(no matches)');
|
|
48
|
+
const withMtime = await Promise.all(matches.map(async (m) => {
|
|
49
|
+
try {
|
|
50
|
+
const st = await fs.stat(join(base, m));
|
|
51
|
+
return { path: m, mtime: st.mtimeMs };
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return { path: m, mtime: 0 };
|
|
55
|
+
}
|
|
56
|
+
}));
|
|
57
|
+
withMtime.sort((a, b) => b.mtime - a.mtime);
|
|
58
|
+
return textResult(withMtime.map((x) => x.path).join('\n'));
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
return errorResult(err instanceof Error ? err.message : String(err));
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
// grep
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
export function makeGrep(deps) {
|
|
70
|
+
return defineTool({
|
|
71
|
+
name: 'grep',
|
|
72
|
+
label: 'Grep',
|
|
73
|
+
description: 'Search file contents for a regular expression. Returns matching lines as ' +
|
|
74
|
+
'`path:line:text`. Optionally restrict to a `path` subtree and/or a `glob`.',
|
|
75
|
+
parameters: {
|
|
76
|
+
type: 'object',
|
|
77
|
+
properties: {
|
|
78
|
+
pattern: { type: 'string', description: 'Regular expression to search for.' },
|
|
79
|
+
path: { type: 'string', description: 'File or directory to search (default: working directory).' },
|
|
80
|
+
glob: { type: 'string', description: 'Only search files matching this glob.' },
|
|
81
|
+
ignoreCase: { type: 'boolean', description: 'Case-insensitive match.' },
|
|
82
|
+
},
|
|
83
|
+
required: ['pattern'],
|
|
84
|
+
},
|
|
85
|
+
async execute(_id, rawParams) {
|
|
86
|
+
const params = rawParams;
|
|
87
|
+
const cwd = deps.getCwd();
|
|
88
|
+
const searchRoot = params.path
|
|
89
|
+
? isAbsolute(params.path)
|
|
90
|
+
? params.path
|
|
91
|
+
: resolve(cwd, params.path)
|
|
92
|
+
: cwd;
|
|
93
|
+
const rg = await tryRipgrep(params, searchRoot, cwd);
|
|
94
|
+
if (rg !== null) {
|
|
95
|
+
return rg.length > 0 ? textResult(rg.join('\n')) : textResult('(no matches)');
|
|
96
|
+
}
|
|
97
|
+
// Pure-JS fallback.
|
|
98
|
+
try {
|
|
99
|
+
const jsMatches = await jsGrep(params, searchRoot, cwd);
|
|
100
|
+
return jsMatches.length > 0
|
|
101
|
+
? textResult(jsMatches.join('\n'))
|
|
102
|
+
: textResult('(no matches)');
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
return errorResult(err instanceof Error ? err.message : String(err));
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Attempt ripgrep. Returns the matched lines, `[]` for a clean no-match, or
|
|
112
|
+
* `null` when ripgrep is unavailable (so the caller falls back to JS).
|
|
113
|
+
*/
|
|
114
|
+
function tryRipgrep(params, searchRoot, cwd) {
|
|
115
|
+
return new Promise((resolvePromise) => {
|
|
116
|
+
const args = ['--no-heading', '--line-number', '--color', 'never', '--max-count', String(MAX_GREP_MATCHES)];
|
|
117
|
+
if (params.ignoreCase)
|
|
118
|
+
args.push('--ignore-case');
|
|
119
|
+
if (params.glob)
|
|
120
|
+
args.push('--glob', params.glob);
|
|
121
|
+
args.push('--regexp', params.pattern, searchRoot);
|
|
122
|
+
let child;
|
|
123
|
+
try {
|
|
124
|
+
child = spawn('rg', args, { cwd });
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
resolvePromise(null);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
let stdout = '';
|
|
131
|
+
let settled = false;
|
|
132
|
+
const done = (value) => {
|
|
133
|
+
if (!settled) {
|
|
134
|
+
settled = true;
|
|
135
|
+
resolvePromise(value);
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
child.on('error', () => done(null)); // ENOENT — rg not installed.
|
|
139
|
+
child.stdout?.on('data', (d) => {
|
|
140
|
+
stdout += d.toString();
|
|
141
|
+
});
|
|
142
|
+
child.on('close', (code) => {
|
|
143
|
+
// rg exits 0 with matches, 1 with no matches, 2 on error.
|
|
144
|
+
if (code === 0 || code === 1) {
|
|
145
|
+
const lines = stdout
|
|
146
|
+
.split('\n')
|
|
147
|
+
.filter((l) => l.trim().length > 0)
|
|
148
|
+
.slice(0, MAX_GREP_MATCHES)
|
|
149
|
+
.map((l) => normalizeRgLine(l, searchRoot, cwd));
|
|
150
|
+
done(lines);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
done(null);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
function normalizeRgLine(line, searchRoot, cwd) {
|
|
159
|
+
// ripgrep emits absolute or root-relative paths; normalize to cwd-relative.
|
|
160
|
+
const match = /^(.*?):(\d+):(.*)$/.exec(line);
|
|
161
|
+
if (!match)
|
|
162
|
+
return line;
|
|
163
|
+
const [, file, lineNo, text] = match;
|
|
164
|
+
const abs = isAbsolute(file) ? file : resolve(searchRoot, file);
|
|
165
|
+
const rel = relative(cwd, abs) || file;
|
|
166
|
+
return `${rel.split('\\').join('/')}:${lineNo}:${text}`;
|
|
167
|
+
}
|
|
168
|
+
async function jsGrep(params, searchRoot, cwd) {
|
|
169
|
+
let regex;
|
|
170
|
+
try {
|
|
171
|
+
regex = new RegExp(params.pattern, params.ignoreCase ? 'i' : undefined);
|
|
172
|
+
}
|
|
173
|
+
catch (err) {
|
|
174
|
+
throw new Error(`Invalid regular expression: ${err instanceof Error ? err.message : String(err)}`);
|
|
175
|
+
}
|
|
176
|
+
// Resolve the files to scan. When `path` names a single file, scan it
|
|
177
|
+
// directly — globbing with a file as `cwd` would silently match nothing.
|
|
178
|
+
let files;
|
|
179
|
+
let rootStat;
|
|
180
|
+
try {
|
|
181
|
+
rootStat = await fs.stat(searchRoot);
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
rootStat = undefined;
|
|
185
|
+
}
|
|
186
|
+
if (rootStat?.isFile()) {
|
|
187
|
+
files = [searchRoot];
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
const pattern = params.glob ?? '**/*';
|
|
191
|
+
files = await tinyGlob(pattern, {
|
|
192
|
+
cwd: searchRoot,
|
|
193
|
+
absolute: true,
|
|
194
|
+
dot: false,
|
|
195
|
+
onlyFiles: true,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
const results = [];
|
|
199
|
+
for (const file of files) {
|
|
200
|
+
if (results.length >= MAX_GREP_MATCHES)
|
|
201
|
+
break;
|
|
202
|
+
let buf;
|
|
203
|
+
try {
|
|
204
|
+
const st = await fs.stat(file);
|
|
205
|
+
if (st.size > MAX_FILE_BYTES)
|
|
206
|
+
continue;
|
|
207
|
+
buf = await fs.readFile(file);
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
if (buf.subarray(0, 8000).includes(0))
|
|
213
|
+
continue; // skip binary
|
|
214
|
+
const rel = (relative(cwd, file) || file).split('\\').join('/');
|
|
215
|
+
const lines = buf.toString('utf-8').split('\n');
|
|
216
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
217
|
+
if (regex.test(lines[i])) {
|
|
218
|
+
results.push(`${rel}:${i + 1}:${lines[i]}`);
|
|
219
|
+
if (results.length >= MAX_GREP_MATCHES)
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return results;
|
|
225
|
+
}
|
package/dist/ui/App.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* App — the root Ink component. Owns the view reducer, subscribes to the
|
|
3
|
+
* controller's event stream (with a streaming coalescer), wires global
|
|
4
|
+
* keybindings, routes slash commands, and renders the header / transcript /
|
|
5
|
+
* input / toast stack / status bar / overlays.
|
|
6
|
+
*/
|
|
7
|
+
import React from 'react';
|
|
8
|
+
import type { AgentController } from '../agent/controller.js';
|
|
9
|
+
import type { ConfirmRequest } from '../tools/index.js';
|
|
10
|
+
import { type Overlay } from '../agent/reducer.js';
|
|
11
|
+
import { type RenderMode } from './layout/frame.js';
|
|
12
|
+
export interface ConfirmBridge {
|
|
13
|
+
handler: ((req: ConfirmRequest) => Promise<boolean>) | null;
|
|
14
|
+
}
|
|
15
|
+
export interface AppProps {
|
|
16
|
+
controller: AgentController;
|
|
17
|
+
version: string;
|
|
18
|
+
/** Decided once in `cli.tsx::runInteractive()`; never switched at run time. */
|
|
19
|
+
mode: RenderMode;
|
|
20
|
+
initialOverlay?: Overlay;
|
|
21
|
+
initialPrompt?: string;
|
|
22
|
+
confirmBridge?: ConfirmBridge;
|
|
23
|
+
}
|
|
24
|
+
export declare function App({ controller, version, mode, initialOverlay, initialPrompt, confirmBridge, }: AppProps): React.ReactElement;
|