@ghostmind-dev/agent 0.1.0 → 0.2.0
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/README.md +23 -2
- package/dist/cli/files.d.ts +5 -0
- package/dist/cli/files.d.ts.map +1 -0
- package/dist/cli/files.js +167 -0
- package/dist/cli/files.js.map +1 -0
- package/dist/cli/main.d.ts +3 -0
- package/dist/cli/main.d.ts.map +1 -0
- package/dist/cli/main.js +275 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/mcp.d.ts +28 -0
- package/dist/cli/mcp.d.ts.map +1 -0
- package/dist/cli/mcp.js +86 -0
- package/dist/cli/mcp.js.map +1 -0
- package/dist/cli/session.d.ts +34 -0
- package/dist/cli/session.d.ts.map +1 -0
- package/dist/cli/session.js +109 -0
- package/dist/cli/session.js.map +1 -0
- package/dist/cli/shell.d.ts +8 -0
- package/dist/cli/shell.d.ts.map +1 -0
- package/dist/cli/shell.js +52 -0
- package/dist/cli/shell.js.map +1 -0
- package/dist/cli/ui.d.ts +29 -0
- package/dist/cli/ui.d.ts.map +1 -0
- package/dist/cli/ui.js +83 -0
- package/dist/cli/ui.js.map +1 -0
- package/package.json +17 -5
package/README.md
CHANGED
|
@@ -12,10 +12,12 @@ It is a **library**: import it, give it tools, run it. No server, no service, no
|
|
|
12
12
|
|
|
13
13
|
```
|
|
14
14
|
@ghostmind-dev/agent (engine: loop, model + Jev, guide, budget, hooks, events)
|
|
15
|
-
/
|
|
16
|
-
|
|
15
|
+
/ | \
|
|
16
|
+
a node in ensemble the `agent` command imported by an app (Potion, later)
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
+
**One core, three ways in.** The same engine runs inside an ensemble `work` node, behind a terminal REPL, or imported into an app. Each keeps its own tools, prompts and approvals.
|
|
20
|
+
|
|
19
21
|
**Share the engine, not the agent.** What makes an agent *yours* is its tools, prompts, memory and approvals, and each app keeps those. What every app needs, and what is hard to get right, is the loop: the guards that stop a model looping, stalling, inventing tool calls or overspending. That lives here once.
|
|
20
22
|
|
|
21
23
|
## Quick start
|
|
@@ -131,6 +133,25 @@ The same `go | pause | stop` vocabulary as ensemble's `guard(step)`, so one supe
|
|
|
131
133
|
|
|
132
134
|
`src/` never names an app: no app database, no app link format, no app wording in prompts. If a line of the engine would only make sense for one app, it belongs behind a seam. `test/boundary.test.mts` enforces it, along with zero runtime dependencies and no hardcoded model ids. Jev's `jev-latest` alias is the one default.
|
|
133
135
|
|
|
136
|
+
## The `agent` command
|
|
137
|
+
|
|
138
|
+
The package ships a terminal chat on the core, in the spirit of opencode. Use it to try the engine, or as a small agent in any folder:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
export OPENROUTER_API_KEY=sk-or-...
|
|
142
|
+
npx @ghostmind-dev/agent --models glm # tool-capable models, cheapest first
|
|
143
|
+
npx @ghostmind-dev/agent -m <model-id> # chat in the current folder
|
|
144
|
+
npx @ghostmind-dev/agent -m <model-id> -p "what does this repo do?" # one turn, then exit
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**What the agent can do:**
|
|
148
|
+
- **Files:** read, list and search freely. Writing or editing a file asks first. It can't reach outside the folder it started in.
|
|
149
|
+
- **Shell:** every command asks first.
|
|
150
|
+
- **MCP servers:** from `.mcp.json` (Claude Code's format). This needs `@ghostmind-dev/ensemble` installed alongside, an *optional* peer dependency, so the package keeps zero runtime dependencies.
|
|
151
|
+
- **Skills:** from `.claude/skills`. Jev picks which one a task needs.
|
|
152
|
+
|
|
153
|
+
It shows every tool call, Jev checkpoint and cost, and logs each session to `~/.agent-cli/sessions/`. There's no default model on purpose: pass `-m` or set `AGENT_MODEL`. `agent --help` lists the options. In this repo, `cli/scripts/agent.sh` runs it from source with the key from Vault (see [`cli/Readme.md`](cli/Readme.md)).
|
|
154
|
+
|
|
134
155
|
## Development
|
|
135
156
|
|
|
136
157
|
```
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Toolset } from '../index.ts';
|
|
2
|
+
/** A path inside the root, or an error that says why not. */
|
|
3
|
+
export declare function inside(root: string, path: unknown): string;
|
|
4
|
+
export declare function fileToolset(root: string): Toolset;
|
|
5
|
+
//# sourceMappingURL=files.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/cli/files.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAa,OAAO,EAAE,MAAM,aAAa,CAAC;AAKtD,6DAA6D;AAC7D,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAK1D;AAmDD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAoFjD"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Files — read, list, search, write and edit, confined to one root (the directory the CLI runs in).
|
|
3
|
+
*
|
|
4
|
+
* Reads run freely; writes and edits are CHANGES, so the core asks for approval with a one-line
|
|
5
|
+
* account before they run. Every path is resolved against the root and refused if it escapes it,
|
|
6
|
+
* so a model cannot read `~/.ssh` by asking for `../../.ssh`.
|
|
7
|
+
*/
|
|
8
|
+
import { spawn } from 'node:child_process';
|
|
9
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
10
|
+
import { dirname, join, relative, resolve, sep } from 'node:path';
|
|
11
|
+
const READ_CAP = 2000; // lines
|
|
12
|
+
const SKIP = new Set(['node_modules', '.git', 'dist', '.next', '.venv', '__pycache__']);
|
|
13
|
+
/** A path inside the root, or an error that says why not. */
|
|
14
|
+
export function inside(root, path) {
|
|
15
|
+
const p = String(path ?? '.').trim() || '.';
|
|
16
|
+
const full = resolve(root, p);
|
|
17
|
+
if (full !== root && !full.startsWith(root + sep))
|
|
18
|
+
throw new Error(`"${p}" is outside the working directory (${root}).`);
|
|
19
|
+
return full;
|
|
20
|
+
}
|
|
21
|
+
const rel = (root, full) => relative(root, full) || '.';
|
|
22
|
+
function listDir(root, dir, depth) {
|
|
23
|
+
const out = [];
|
|
24
|
+
const walk = (d, level) => {
|
|
25
|
+
let entries;
|
|
26
|
+
try {
|
|
27
|
+
entries = readdirSync(d).sort();
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
for (const name of entries) {
|
|
33
|
+
if (out.length >= 500)
|
|
34
|
+
return;
|
|
35
|
+
const full = join(d, name);
|
|
36
|
+
let st;
|
|
37
|
+
try {
|
|
38
|
+
st = statSync(full);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
const indent = ' '.repeat(level);
|
|
44
|
+
if (st.isDirectory()) {
|
|
45
|
+
out.push(`${indent}${name}/${SKIP.has(name) ? ' (skipped)' : ''}`);
|
|
46
|
+
if (level + 1 < depth && !SKIP.has(name))
|
|
47
|
+
walk(full, level + 1);
|
|
48
|
+
}
|
|
49
|
+
else
|
|
50
|
+
out.push(`${indent}${name} ${st.size}b`);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
walk(dir, 0);
|
|
54
|
+
if (out.length >= 500)
|
|
55
|
+
out.push('…(truncated at 500 entries)');
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
function ripgrep(root, pattern, path, glob, signal) {
|
|
59
|
+
return new Promise((ok, fail) => {
|
|
60
|
+
const args = ['--line-number', '--no-heading', '--color=never', '--max-count=20', '--max-columns=300', ...(glob ? ['--glob', glob] : []), '--', pattern, path];
|
|
61
|
+
const child = spawn('rg', args, { cwd: root, signal });
|
|
62
|
+
let out = '';
|
|
63
|
+
let err = '';
|
|
64
|
+
child.stdout.on('data', d => (out += d));
|
|
65
|
+
child.stderr.on('data', d => (err += d));
|
|
66
|
+
child.on('error', fail);
|
|
67
|
+
child.on('close', code => {
|
|
68
|
+
if (code === 0)
|
|
69
|
+
ok(out);
|
|
70
|
+
else if (code === 1)
|
|
71
|
+
ok('');
|
|
72
|
+
else
|
|
73
|
+
fail(new Error(err.trim() || `rg exited with ${code}`));
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
export function fileToolset(root) {
|
|
78
|
+
const tools = [
|
|
79
|
+
{
|
|
80
|
+
name: 'list_dir',
|
|
81
|
+
description: 'List a directory in the working directory as a tree (depth 1–4, default 2). Skips node_modules, .git, dist.',
|
|
82
|
+
parameters: { type: 'object', properties: { path: { type: 'string' }, depth: { type: 'number' } } },
|
|
83
|
+
run: async (a) => {
|
|
84
|
+
const dir = inside(root, a.path);
|
|
85
|
+
if (!statSync(dir).isDirectory())
|
|
86
|
+
throw new Error(`${rel(root, dir)} is not a directory.`);
|
|
87
|
+
const depth = Math.min(4, Math.max(1, Number(a.depth) || 2));
|
|
88
|
+
return `${rel(root, dir)}/\n${listDir(root, dir, depth).join('\n')}`;
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
name: 'read_file',
|
|
93
|
+
description: `Read a text file, with line numbers. \`offset\` (1-based line) and \`limit\` (lines, default ${READ_CAP}) read part of a long file.`,
|
|
94
|
+
parameters: { type: 'object', properties: { path: { type: 'string' }, offset: { type: 'number' }, limit: { type: 'number' } }, required: ['path'] },
|
|
95
|
+
run: async (a) => {
|
|
96
|
+
const file = inside(root, a.path);
|
|
97
|
+
const lines = readFileSync(file, 'utf8').split('\n');
|
|
98
|
+
const from = Math.max(1, Number(a.offset) || 1);
|
|
99
|
+
const count = Math.max(1, Number(a.limit) || READ_CAP);
|
|
100
|
+
const slice = lines.slice(from - 1, from - 1 + count).map((l, i) => `${String(from + i).padStart(5)} ${l}`);
|
|
101
|
+
const more = from - 1 + count < lines.length ? `\n…(${lines.length - (from - 1 + count)} more lines; read on with offset ${from + count})` : '';
|
|
102
|
+
return `${rel(root, file)} (${lines.length} lines)\n${slice.join('\n')}${more}`;
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: 'search',
|
|
107
|
+
description: 'Search file contents with a regular expression (ripgrep). Optional `path` to narrow, `glob` to filter files (e.g. "*.ts"). Returns file:line:text, at most 20 matches per file.',
|
|
108
|
+
parameters: { type: 'object', properties: { pattern: { type: 'string' }, path: { type: 'string' }, glob: { type: 'string' } }, required: ['pattern'] },
|
|
109
|
+
run: async (a, ctx) => {
|
|
110
|
+
const where = inside(root, a.path);
|
|
111
|
+
const out = await ripgrep(root, String(a.pattern ?? ''), rel(root, where), a.glob ? String(a.glob) : undefined, ctx.signal);
|
|
112
|
+
if (!out.trim())
|
|
113
|
+
return 'No matches.';
|
|
114
|
+
const lines = out.trim().split('\n');
|
|
115
|
+
return lines.length > 300 ? `${lines.slice(0, 300).join('\n')}\n…(${lines.length - 300} more matches; narrow the search)` : lines.join('\n');
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
name: 'write_file',
|
|
120
|
+
description: 'Create or overwrite a file with `content`. Asks the person first.',
|
|
121
|
+
parameters: { type: 'object', properties: { path: { type: 'string' }, content: { type: 'string' } }, required: ['path', 'content'] },
|
|
122
|
+
write: {
|
|
123
|
+
describe: a => {
|
|
124
|
+
const file = inside(root, a.path);
|
|
125
|
+
const n = String(a.content ?? '').split('\n').length;
|
|
126
|
+
return `${existsSync(file) ? 'Overwrite' : 'Create'} ${rel(root, file)} (${n} lines)`;
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
run: async (a) => {
|
|
130
|
+
const file = inside(root, a.path);
|
|
131
|
+
mkdirSync(dirname(file), { recursive: true });
|
|
132
|
+
writeFileSync(file, String(a.content ?? ''));
|
|
133
|
+
return `Wrote ${rel(root, file)}.`;
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: 'edit_file',
|
|
138
|
+
description: 'Replace exact text in a file: `old` must appear exactly once (or pass `all: true`). Copy `old` from read_file output without the line numbers. Asks the person first.',
|
|
139
|
+
parameters: { type: 'object', properties: { path: { type: 'string' }, old: { type: 'string' }, new: { type: 'string' }, all: { type: 'boolean' } }, required: ['path', 'old', 'new'] },
|
|
140
|
+
write: {
|
|
141
|
+
describe: a => {
|
|
142
|
+
const file = inside(root, a.path);
|
|
143
|
+
const oldText = String(a.old ?? '');
|
|
144
|
+
const count = existsSync(file) ? readFileSync(file, 'utf8').split(oldText).length - 1 : 0;
|
|
145
|
+
const first = (s) => JSON.stringify(s.split('\n')[0].slice(0, 60));
|
|
146
|
+
return `Edit ${rel(root, file)}: replace ${a.all ? `${count} occurrence(s) of` : ''} ${first(oldText)} → ${first(String(a.new ?? ''))}`;
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
run: async (a) => {
|
|
150
|
+
const file = inside(root, a.path);
|
|
151
|
+
const text = readFileSync(file, 'utf8');
|
|
152
|
+
const oldText = String(a.old ?? '');
|
|
153
|
+
if (!oldText)
|
|
154
|
+
throw new Error('`old` is empty.');
|
|
155
|
+
const count = text.split(oldText).length - 1;
|
|
156
|
+
if (count === 0)
|
|
157
|
+
throw new Error('`old` was not found. Read the file again and copy the text exactly (without line numbers).');
|
|
158
|
+
if (count > 1 && !a.all)
|
|
159
|
+
throw new Error(`\`old\` appears ${count} times. Add surrounding lines to make it unique, or pass all: true.`);
|
|
160
|
+
writeFileSync(file, a.all ? text.split(oldText).join(String(a.new ?? '')) : text.replace(oldText, () => String(a.new ?? '')));
|
|
161
|
+
return `Edited ${rel(root, file)} (${a.all ? count : 1} replacement${(a.all ? count : 1) > 1 ? 's' : ''}).`;
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
];
|
|
165
|
+
return { name: 'files', description: `Files in the working directory (${root}).`, tools };
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/cli/files.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":""}
|
package/dist/cli/main.js
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* `agent` — a terminal REPL to test the agent core, in the spirit of opencode.
|
|
4
|
+
*
|
|
5
|
+
* agent chat in the current directory
|
|
6
|
+
* agent -p "what does this repo do?" one turn, then exit (exit code 1 unless done)
|
|
7
|
+
* agent --model <id> --guidance close --max-usd 0.2 --yes --verbose
|
|
8
|
+
*
|
|
9
|
+
* The agent gets: files (read/list/search, and write/edit with approval), the shell (each command
|
|
10
|
+
* approved), MCP servers from `.mcp.json`, and skills from `.claude/skills`. Every tool call, Jev
|
|
11
|
+
* checkpoint, level change and cost is printed, and every event is logged to
|
|
12
|
+
* ~/.agent-cli/sessions/<time>.jsonl.
|
|
13
|
+
*
|
|
14
|
+
* Config is plain environment: OPENROUTER_API_KEY (required), AGENT_MODEL and AGENT_MAX_USD
|
|
15
|
+
* (defaults for --model and --max-usd). In the agent repo, cli/scripts/agent.sh supplies them through
|
|
16
|
+
* varlock. There is no default model on purpose: pick one with --model (see `agent --models`).
|
|
17
|
+
*/
|
|
18
|
+
import { homedir } from 'node:os';
|
|
19
|
+
import { join, resolve } from 'node:path';
|
|
20
|
+
import { parseArgs } from 'node:util';
|
|
21
|
+
import { createInterface } from 'node:readline/promises';
|
|
22
|
+
import { dirSkills, modelCatalog, openrouter } from "../index.js";
|
|
23
|
+
import { connectAll } from "./mcp.js";
|
|
24
|
+
import { createSession } from "./session.js";
|
|
25
|
+
import { fileToolset } from "./files.js";
|
|
26
|
+
import { shellToolset } from "./shell.js";
|
|
27
|
+
import { c, printer, summary } from "./ui.js";
|
|
28
|
+
const { values: flags, positionals } = parseArgs({
|
|
29
|
+
options: {
|
|
30
|
+
prompt: { type: 'string', short: 'p' },
|
|
31
|
+
model: { type: 'string', short: 'm' },
|
|
32
|
+
guidance: { type: 'string', short: 'g' },
|
|
33
|
+
'max-usd': { type: 'string' },
|
|
34
|
+
cwd: { type: 'string' },
|
|
35
|
+
yes: { type: 'boolean', short: 'y' },
|
|
36
|
+
verbose: { type: 'boolean', short: 'v' },
|
|
37
|
+
'no-mcp': { type: 'boolean' },
|
|
38
|
+
'no-skills': { type: 'boolean' },
|
|
39
|
+
'no-shell': { type: 'boolean' },
|
|
40
|
+
models: { type: 'boolean' },
|
|
41
|
+
help: { type: 'boolean', short: 'h' },
|
|
42
|
+
},
|
|
43
|
+
allowPositionals: true,
|
|
44
|
+
});
|
|
45
|
+
const HELP = `agent — test the agent core from a terminal
|
|
46
|
+
|
|
47
|
+
agent [options] chat in the current directory
|
|
48
|
+
agent -p "…" [options] one turn, then exit
|
|
49
|
+
|
|
50
|
+
agent --models [filter] tool-capable OpenRouter models, cheapest first
|
|
51
|
+
|
|
52
|
+
-m, --model <id> OpenRouter model (default: $AGENT_MODEL; required)
|
|
53
|
+
-g, --guidance <level> auto | off | light | normal | close | N (default: auto)
|
|
54
|
+
--max-usd <n> USD cap per turn (default: $AGENT_MAX_USD)
|
|
55
|
+
--cwd <dir> working directory (default: here)
|
|
56
|
+
-y, --yes approve every change and command without asking
|
|
57
|
+
-v, --verbose longer tool results, and the transient lines said to the model
|
|
58
|
+
--no-mcp --no-skills --no-shell
|
|
59
|
+
|
|
60
|
+
In the chat: /help /model [id] /models [filter] /guidance [level] /budget [usd]
|
|
61
|
+
/cost /tools /mcp /skills /auto /log /clear /exit Ctrl+C stops a turn`;
|
|
62
|
+
if (flags.help) {
|
|
63
|
+
console.log(HELP);
|
|
64
|
+
process.exit(0);
|
|
65
|
+
}
|
|
66
|
+
async function listModels(filter, write) {
|
|
67
|
+
const cards = (await modelCatalog()).filter(m => m.tools && (!filter || m.id.includes(filter) || m.name.toLowerCase().includes(filter.toLowerCase())));
|
|
68
|
+
cards.sort((a, b) => a.completion - b.completion);
|
|
69
|
+
for (const m of cards.slice(0, 20))
|
|
70
|
+
write(`${m.id.padEnd(48)} ${c.dim(`$${(m.completion * 1e6).toFixed(2)}/M out · ${Math.round(m.context / 1000)}k ctx`)}\n`);
|
|
71
|
+
write(c.dim(`${cards.length} tool-capable models${filter ? ` matching "${filter}"` : ''}, cheapest first\n`));
|
|
72
|
+
}
|
|
73
|
+
if (flags.models) {
|
|
74
|
+
await listModels(positionals[0], s => process.stdout.write(s));
|
|
75
|
+
process.exit(0);
|
|
76
|
+
}
|
|
77
|
+
const parseGuidance = (s) => {
|
|
78
|
+
if (!s)
|
|
79
|
+
return 'auto';
|
|
80
|
+
if (['auto', 'off', 'light', 'normal', 'close'].includes(s))
|
|
81
|
+
return s;
|
|
82
|
+
const n = Number(s);
|
|
83
|
+
return Number.isFinite(n) && n >= 1 ? n : null;
|
|
84
|
+
};
|
|
85
|
+
const root = resolve(flags.cwd ?? process.cwd());
|
|
86
|
+
const model = flags.model ?? process.env.AGENT_MODEL;
|
|
87
|
+
const guidance = parseGuidance(flags.guidance);
|
|
88
|
+
if (guidance === null) {
|
|
89
|
+
console.error(`--guidance must be auto, off, light, normal, close or a number`);
|
|
90
|
+
process.exit(2);
|
|
91
|
+
}
|
|
92
|
+
if (!process.env.OPENROUTER_API_KEY) {
|
|
93
|
+
console.error('OPENROUTER_API_KEY is not set. Export it, or in the agent repo run cli/scripts/agent.sh (varlock).');
|
|
94
|
+
process.exit(2);
|
|
95
|
+
}
|
|
96
|
+
if (!model) {
|
|
97
|
+
console.error('No model: pass --model <id> or set AGENT_MODEL. See `agent --models` for tool-capable models, cheapest first.');
|
|
98
|
+
process.exit(2);
|
|
99
|
+
}
|
|
100
|
+
const oneShot = flags.prompt !== undefined;
|
|
101
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout, terminal: process.stdin.isTTY });
|
|
102
|
+
const out = (s) => process.stdout.write(s);
|
|
103
|
+
const print = printer(out, { stream: true, verbose: !!flags.verbose });
|
|
104
|
+
// ── tools ──
|
|
105
|
+
const toolsets = [fileToolset(root), ...(flags['no-shell'] ? [] : [shellToolset(root)])];
|
|
106
|
+
let mcp = [];
|
|
107
|
+
if (!flags['no-mcp']) {
|
|
108
|
+
mcp = await connectAll(root, text => out(c.yellow(`${text}\n`)));
|
|
109
|
+
for (const m of mcp)
|
|
110
|
+
if (m.toolset)
|
|
111
|
+
toolsets.push(m.toolset);
|
|
112
|
+
}
|
|
113
|
+
const skills = flags['no-skills'] ? undefined : dirSkills(join(root, '.claude', 'skills'), join(homedir(), '.claude', 'skills'));
|
|
114
|
+
// ── approvals ──
|
|
115
|
+
const ask = async (req) => {
|
|
116
|
+
if (!process.stdin.isTTY)
|
|
117
|
+
return 'no';
|
|
118
|
+
if (print.midLine())
|
|
119
|
+
out('\n');
|
|
120
|
+
const a = (await rl.question(`${c.yellow('?')} ${c.bold(req.summary)}\n ${c.dim('allow? [y]es / [n]o / [a]lways for')} ${req.tool} ${c.dim('›')} `)).trim().toLowerCase();
|
|
121
|
+
return a.startsWith('a') ? 'always' : a.startsWith('y') ? 'yes' : 'no';
|
|
122
|
+
};
|
|
123
|
+
const stamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
124
|
+
const session = createSession({
|
|
125
|
+
provider: openrouter({ model, headers: { 'X-Title': 'agent-cli' } }),
|
|
126
|
+
model,
|
|
127
|
+
root,
|
|
128
|
+
toolsets,
|
|
129
|
+
skills,
|
|
130
|
+
guidance,
|
|
131
|
+
maxUsd: Number(flags['max-usd'] ?? process.env.AGENT_MAX_USD ?? 0.5),
|
|
132
|
+
ask,
|
|
133
|
+
onEvent: print,
|
|
134
|
+
logPath: join(homedir(), '.agent-cli', 'sessions', `${stamp}.jsonl`),
|
|
135
|
+
profilesPath: join(homedir(), '.agent-cli', 'profiles.json'),
|
|
136
|
+
autoApprove: !!flags.yes,
|
|
137
|
+
});
|
|
138
|
+
// ── one turn ──
|
|
139
|
+
let running = null;
|
|
140
|
+
async function turn(text) {
|
|
141
|
+
running = new AbortController();
|
|
142
|
+
try {
|
|
143
|
+
const r = await session.send(text, running.signal);
|
|
144
|
+
if (print.midLine())
|
|
145
|
+
out('\n');
|
|
146
|
+
out(`${summary(r, session.total)}\n`);
|
|
147
|
+
return r;
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
if (print.midLine())
|
|
151
|
+
out('\n');
|
|
152
|
+
out(`${c.red('error')} ${error instanceof Error ? error.message : String(error)}\n`);
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
finally {
|
|
156
|
+
running = null;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
rl.on('SIGINT', () => {
|
|
160
|
+
if (running) {
|
|
161
|
+
running.abort();
|
|
162
|
+
out(c.yellow('\n(stopping…)\n'));
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
out('\n');
|
|
166
|
+
rl.close();
|
|
167
|
+
process.exit(0);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
if (oneShot) {
|
|
171
|
+
const r = await turn(flags.prompt);
|
|
172
|
+
rl.close();
|
|
173
|
+
for (const m of mcp)
|
|
174
|
+
m.session?.close();
|
|
175
|
+
process.exit(r && ['done', 'greeted', 'chatted'].includes(r.status) ? 0 : 1);
|
|
176
|
+
}
|
|
177
|
+
// ── the REPL ──
|
|
178
|
+
out(`${c.bold('agent')} ${c.dim(`· ${model ?? '(no model)'} · guidance ${String(guidance)} · $${session.maxUsd}/turn · ${root}`)}\n`);
|
|
179
|
+
const tools = toolsets.flatMap(s => s.tools.map(t => t.name));
|
|
180
|
+
out(c.dim(`tools: ${tools.length} (${toolsets.map(s => `${s.name} ${s.tools.length}`).join(', ')}) · /help for commands\n`));
|
|
181
|
+
for (const m of mcp)
|
|
182
|
+
if (!m.ok)
|
|
183
|
+
out(c.yellow(`mcp ${m.name}: ${m.error}\n`));
|
|
184
|
+
async function command(line) {
|
|
185
|
+
const [cmd, ...rest] = line.slice(1).split(/\s+/);
|
|
186
|
+
const arg = rest.join(' ').trim();
|
|
187
|
+
switch (cmd) {
|
|
188
|
+
case 'help':
|
|
189
|
+
out(`${HELP}\n`);
|
|
190
|
+
break;
|
|
191
|
+
case 'exit':
|
|
192
|
+
case 'quit':
|
|
193
|
+
return false;
|
|
194
|
+
case 'model':
|
|
195
|
+
if (arg)
|
|
196
|
+
session.model = arg;
|
|
197
|
+
out(`model: ${session.model}\n`);
|
|
198
|
+
break;
|
|
199
|
+
case 'models':
|
|
200
|
+
await listModels(arg || undefined, out);
|
|
201
|
+
break;
|
|
202
|
+
case 'guidance': {
|
|
203
|
+
const g = parseGuidance(arg || undefined);
|
|
204
|
+
if (arg && g === null)
|
|
205
|
+
out('auto | off | light | normal | close | N\n');
|
|
206
|
+
else if (arg)
|
|
207
|
+
session.guidance = g;
|
|
208
|
+
out(`guidance: ${String(session.guidance)}\n`);
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
case 'budget':
|
|
212
|
+
if (arg && Number(arg) > 0)
|
|
213
|
+
session.maxUsd = Number(arg);
|
|
214
|
+
out(`budget: $${session.maxUsd} per turn\n`);
|
|
215
|
+
break;
|
|
216
|
+
case 'cost':
|
|
217
|
+
out(`session: $${session.total.toFixed(5)} over ${session.turns} turn(s)\n`);
|
|
218
|
+
break;
|
|
219
|
+
case 'tools':
|
|
220
|
+
for (const s of toolsets)
|
|
221
|
+
out(`${c.bold(s.name)}: ${s.tools.map(t => (t.write ? `${t.name}*` : t.name)).join(', ')}\n`);
|
|
222
|
+
out(c.dim('* asks approval\n'));
|
|
223
|
+
break;
|
|
224
|
+
case 'mcp':
|
|
225
|
+
if (!mcp.length)
|
|
226
|
+
out('no MCP servers (add them to .mcp.json or ~/.agent-cli/mcp.json)\n');
|
|
227
|
+
for (const m of mcp)
|
|
228
|
+
out(`${m.name}: ${m.ok ? c.green(`${m.tools} tools`) : c.red(m.error ?? 'failed')}\n`);
|
|
229
|
+
break;
|
|
230
|
+
case 'skills': {
|
|
231
|
+
const list = skills ? await skills.list() : [];
|
|
232
|
+
if (!list.length)
|
|
233
|
+
out('no skills (.claude/skills here or in ~)\n');
|
|
234
|
+
for (const s of list)
|
|
235
|
+
out(`${c.bold(s.name)} ${c.dim(s.description.slice(0, 100))}\n`);
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
238
|
+
case 'auto':
|
|
239
|
+
session.autoApprove = !session.autoApprove;
|
|
240
|
+
out(`auto-approve: ${session.autoApprove ? c.yellow('on — every change and command runs without asking') : 'off'}\n`);
|
|
241
|
+
break;
|
|
242
|
+
case 'log':
|
|
243
|
+
out(`${session.logPath}\n`);
|
|
244
|
+
break;
|
|
245
|
+
case 'clear':
|
|
246
|
+
session.clear();
|
|
247
|
+
out('new conversation\n');
|
|
248
|
+
break;
|
|
249
|
+
default:
|
|
250
|
+
out(`unknown command /${cmd} — /help\n`);
|
|
251
|
+
}
|
|
252
|
+
return true;
|
|
253
|
+
}
|
|
254
|
+
for (;;) {
|
|
255
|
+
let line;
|
|
256
|
+
try {
|
|
257
|
+
line = (await rl.question(c.cyan('› '))).trim();
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
break;
|
|
261
|
+
}
|
|
262
|
+
if (!line)
|
|
263
|
+
continue;
|
|
264
|
+
if (line.startsWith('/')) {
|
|
265
|
+
if (!(await command(line)))
|
|
266
|
+
break;
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
await turn(line);
|
|
270
|
+
}
|
|
271
|
+
rl.close();
|
|
272
|
+
for (const m of mcp)
|
|
273
|
+
m.session?.close();
|
|
274
|
+
process.exit(0);
|
|
275
|
+
//# sourceMappingURL=main.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type McpLike, type Toolset } from '../index.ts';
|
|
2
|
+
/** The parts of ensemble's McpServerSpec this reads and writes (kept local: ensemble is optional). */
|
|
3
|
+
export type McpServerSpec = {
|
|
4
|
+
command: string;
|
|
5
|
+
args?: string[];
|
|
6
|
+
env?: Record<string, string>;
|
|
7
|
+
} | {
|
|
8
|
+
url: string;
|
|
9
|
+
transport?: 'auto' | 'streamable-http' | 'sse' | 'websocket';
|
|
10
|
+
headers?: Record<string, string>;
|
|
11
|
+
};
|
|
12
|
+
type McpSession = McpLike & {
|
|
13
|
+
close(): void;
|
|
14
|
+
};
|
|
15
|
+
export declare const ENSEMBLE = "@ghostmind-dev/ensemble";
|
|
16
|
+
export declare const WRITE_VERBS: RegExp;
|
|
17
|
+
export declare function mcpConfig(cwd: string): Record<string, McpServerSpec>;
|
|
18
|
+
export interface McpConnection {
|
|
19
|
+
name: string;
|
|
20
|
+
ok: boolean;
|
|
21
|
+
tools: number;
|
|
22
|
+
error?: string;
|
|
23
|
+
session?: McpSession;
|
|
24
|
+
toolset?: Toolset;
|
|
25
|
+
}
|
|
26
|
+
export declare function connectAll(cwd: string, onLogin: (text: string) => void): Promise<McpConnection[]>;
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=mcp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/cli/mcp.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAc,KAAK,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,aAAa,CAAC;AAErE,sGAAsG;AACtG,MAAM,MAAM,aAAa,GACrB;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAClE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,GAAG,iBAAiB,GAAG,KAAK,GAAG,WAAW,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAAC;AAEpH,KAAK,UAAU,GAAG,OAAO,GAAG;IAAE,KAAK,IAAI,IAAI,CAAA;CAAE,CAAC;AAG9C,eAAO,MAAM,QAAQ,4BAA4B,CAAC;AAqBlD,eAAO,MAAM,WAAW,QAAyM,CAAC;AAElO,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAiBpE;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,UAAU,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAmBvG"}
|
package/dist/cli/mcp.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
return path;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* MCP servers, from the same `.mcp.json` Claude Code reads.
|
|
11
|
+
*
|
|
12
|
+
* The connection is ensemble's `connect()` (stdio, Streamable HTTP, SSE, WebSocket, and every auth
|
|
13
|
+
* mode including OAuth logins), used here as a third-party library: the agent core speaks no MCP wire
|
|
14
|
+
* protocol, it only takes a session shaped `{ name, listTools, call }`.
|
|
15
|
+
*
|
|
16
|
+
* Ensemble is an OPTIONAL peer dependency, loaded only when a server is configured: the package keeps
|
|
17
|
+
* zero runtime dependencies, and files, shell and skills work without it. Without it, each server is
|
|
18
|
+
* reported with the install command.
|
|
19
|
+
*
|
|
20
|
+
* Config is read from `<cwd>/.mcp.json`, then `~/.agent-cli/mcp.json` (the first definition of a name
|
|
21
|
+
* wins). A server that fails to connect is reported and skipped; it never stops the CLI.
|
|
22
|
+
*
|
|
23
|
+
* Which MCP calls are CHANGES is not something servers say reliably, so the CLI guesses from the
|
|
24
|
+
* tool's name (create_, update_, delete_…) and asks approval for those. `/auto` skips all approvals.
|
|
25
|
+
*/
|
|
26
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
27
|
+
import { homedir } from 'node:os';
|
|
28
|
+
import { join } from 'node:path';
|
|
29
|
+
import { mcpToolset } from "../index.js";
|
|
30
|
+
export const ENSEMBLE = '@ghostmind-dev/ensemble';
|
|
31
|
+
/** ensemble's connect(), or null when it is not installed. */
|
|
32
|
+
async function loadConnect() {
|
|
33
|
+
try {
|
|
34
|
+
const mod = (await import(__rewriteRelativeImportExtension(ENSEMBLE)));
|
|
35
|
+
return mod.connect ?? null;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export const WRITE_VERBS = /^(create|update|delete|remove|write|set|add|edit|append|trash|apply|send|put|patch|move|rename|upload|restore|link|unlink|pin|unpin|publish|deploy|run|execute|insert|drop|merge|close|archive)[_-]/i;
|
|
42
|
+
export function mcpConfig(cwd) {
|
|
43
|
+
const out = {};
|
|
44
|
+
for (const file of [join(cwd, '.mcp.json'), join(homedir(), '.agent-cli', 'mcp.json')]) {
|
|
45
|
+
if (!existsSync(file))
|
|
46
|
+
continue;
|
|
47
|
+
let servers = {};
|
|
48
|
+
try {
|
|
49
|
+
servers = JSON.parse(readFileSync(file, 'utf8')).mcpServers ?? {};
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
for (const [name, s] of Object.entries(servers)) {
|
|
55
|
+
if (name in out)
|
|
56
|
+
continue;
|
|
57
|
+
if (s.url)
|
|
58
|
+
out[name] = { url: s.url, transport: s.type === 'sse' ? 'sse' : s.type === 'ws' ? 'websocket' : 'auto', ...(s.headers ? { headers: s.headers } : {}) };
|
|
59
|
+
else if (s.command)
|
|
60
|
+
out[name] = { command: s.command, ...(s.args ? { args: s.args } : {}), ...(s.env ? { env: s.env } : {}) };
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return out;
|
|
64
|
+
}
|
|
65
|
+
export async function connectAll(cwd, onLogin) {
|
|
66
|
+
const specs = mcpConfig(cwd);
|
|
67
|
+
if (!Object.keys(specs).length)
|
|
68
|
+
return [];
|
|
69
|
+
const connect = await loadConnect();
|
|
70
|
+
if (!connect)
|
|
71
|
+
return Object.keys(specs).map(name => ({ name, ok: false, tools: 0, error: `MCP needs ${ENSEMBLE}: npm install -g ${ENSEMBLE} (or add it next to this package)` }));
|
|
72
|
+
return Promise.all(Object.entries(specs).map(async ([name, spec]) => {
|
|
73
|
+
try {
|
|
74
|
+
// Interactive: an OAuth server (Potion) may open a browser to log in the first time.
|
|
75
|
+
const session = await connect(name, spec, { interactive: true, prompt: onLogin });
|
|
76
|
+
const toolset = await mcpToolset(session, {
|
|
77
|
+
writes: (tool, args) => (WRITE_VERBS.test(tool) ? `${name}.${tool}(${JSON.stringify(args).slice(0, 160)})` : null),
|
|
78
|
+
});
|
|
79
|
+
return { name, ok: true, tools: toolset.tools.length, session, toolset };
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
return { name, ok: false, tools: 0, error: error instanceof Error ? error.message : String(error) };
|
|
83
|
+
}
|
|
84
|
+
}));
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=mcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/cli/mcp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type AgentEvent, type AgentResult, type ApprovalRequest, type Guidance, type ModelProvider, type SkillSource, type Toolset } from '../index.ts';
|
|
2
|
+
export type Answer = 'yes' | 'no' | 'always';
|
|
3
|
+
export interface SessionOptions {
|
|
4
|
+
provider: ModelProvider;
|
|
5
|
+
model?: string;
|
|
6
|
+
root: string;
|
|
7
|
+
toolsets: Toolset[];
|
|
8
|
+
skills?: SkillSource;
|
|
9
|
+
guidance: Guidance;
|
|
10
|
+
maxUsd: number;
|
|
11
|
+
/** Ask the person about one change. */
|
|
12
|
+
ask: (request: ApprovalRequest) => Promise<Answer>;
|
|
13
|
+
onEvent: (event: AgentEvent) => void;
|
|
14
|
+
/** Every event of every turn, one JSON line each. */
|
|
15
|
+
logPath?: string;
|
|
16
|
+
/** Per-model guide profiles, so the guide learns across sessions. */
|
|
17
|
+
profilesPath?: string;
|
|
18
|
+
autoApprove?: boolean;
|
|
19
|
+
}
|
|
20
|
+
export declare function createSession(o: SessionOptions): {
|
|
21
|
+
send: (text: string, signal?: AbortSignal) => Promise<AgentResult>;
|
|
22
|
+
readonly total: number;
|
|
23
|
+
readonly turns: number;
|
|
24
|
+
model: string | undefined;
|
|
25
|
+
guidance: Guidance;
|
|
26
|
+
maxUsd: number;
|
|
27
|
+
autoApprove: boolean;
|
|
28
|
+
readonly always: string[];
|
|
29
|
+
readonly logPath: string | undefined;
|
|
30
|
+
events: () => readonly import("../events.ts").LoggedEvent[];
|
|
31
|
+
clear(): void;
|
|
32
|
+
};
|
|
33
|
+
export type Session = ReturnType<typeof createSession>;
|
|
34
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/cli/session.ts"],"names":[],"mappings":"AASA,OAAO,EAKL,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,eAAe,EAEpB,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,OAAO,EACb,MAAM,aAAa,CAAC;AAErB,MAAM,MAAM,MAAM,GAAG,KAAK,GAAG,IAAI,GAAG,QAAQ,CAAC;AAE7C,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,aAAa,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,GAAG,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACnD,OAAO,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IACrC,qDAAqD;IACrD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AASD,wBAAgB,aAAa,CAAC,CAAC,EAAE,cAAc;iBAcnB,MAAM,WAAW,WAAW,KAAG,OAAO,CAAC,WAAW,CAAC;;;WA6C7D,MAAM,GAAG,SAAS;cAMhB,QAAQ;YAMV,MAAM;iBAMD,OAAO;;;;;EAc7B;AAED,MAAM,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A conversation with the agent core: history across turns, approvals, the event log, costs.
|
|
3
|
+
*
|
|
4
|
+
* Kept apart from the terminal (main.ts) so it can be driven by a test with a scripted model. The
|
|
5
|
+
* agent here is a generic command-line agent: its words are the core's defaults plus a few lines
|
|
6
|
+
* about working in a directory on the person's machine, and its tools are what the CLI was given.
|
|
7
|
+
*/
|
|
8
|
+
import { appendFileSync, mkdirSync } from 'node:fs';
|
|
9
|
+
import { dirname } from 'node:path';
|
|
10
|
+
import { defaultPrompts, eventLog, fileProfiles, runAgent, } from "../index.js";
|
|
11
|
+
const SYSTEM_EXTRA = (root) => [
|
|
12
|
+
`You are a command-line agent on the person's machine, working in ${root}. Paths are relative to it.`,
|
|
13
|
+
'Look before you answer: list, search and read files instead of guessing what they contain. Quote paths and line numbers you actually read.',
|
|
14
|
+
'To change a file, read it first, then use edit_file with an exact passage (or write_file for a new file). Every change and every shell command waits for the person\'s approval.',
|
|
15
|
+
'Keep answers short and concrete. Say what you changed, and what you could not do.',
|
|
16
|
+
];
|
|
17
|
+
export function createSession(o) {
|
|
18
|
+
let history = [];
|
|
19
|
+
let total = 0;
|
|
20
|
+
let model = o.model;
|
|
21
|
+
let guidance = o.guidance;
|
|
22
|
+
let maxUsd = o.maxUsd;
|
|
23
|
+
let autoApprove = o.autoApprove ?? false;
|
|
24
|
+
const always = new Set();
|
|
25
|
+
const turns = [];
|
|
26
|
+
if (o.logPath)
|
|
27
|
+
mkdirSync(dirname(o.logPath), { recursive: true });
|
|
28
|
+
const log = eventLog({ onAppend: e => void (o.logPath && appendFileSync(o.logPath, `${JSON.stringify(e)}\n`)) });
|
|
29
|
+
const profiles = o.profilesPath ? fileProfiles(o.profilesPath) : undefined;
|
|
30
|
+
async function send(text, signal) {
|
|
31
|
+
const result = await runAgent({
|
|
32
|
+
provider: o.provider,
|
|
33
|
+
model,
|
|
34
|
+
task: {
|
|
35
|
+
goal: text,
|
|
36
|
+
context: { cwd: o.root, platform: process.platform, today: new Date().toISOString().slice(0, 10) },
|
|
37
|
+
expectation: 'A direct, short answer to the request, grounded in what the tools returned. When something was changed, say exactly what.',
|
|
38
|
+
welcome: 'Hi. Ask me about this directory, or to change something in it.',
|
|
39
|
+
},
|
|
40
|
+
toolsets: o.toolsets,
|
|
41
|
+
skills: o.skills,
|
|
42
|
+
prompts: { system: [...defaultPrompts.system, ...SYSTEM_EXTRA(o.root)] },
|
|
43
|
+
history,
|
|
44
|
+
guidance,
|
|
45
|
+
guide: profiles ? { profiles } : undefined,
|
|
46
|
+
budget: { maxUsd, maxSteps: 16, maxToolCalls: 30 },
|
|
47
|
+
approve: async (request) => {
|
|
48
|
+
if (autoApprove || always.has(request.tool))
|
|
49
|
+
return true;
|
|
50
|
+
const a = await o.ask(request);
|
|
51
|
+
if (a === 'always')
|
|
52
|
+
always.add(request.tool);
|
|
53
|
+
return a !== 'no';
|
|
54
|
+
},
|
|
55
|
+
stream: true,
|
|
56
|
+
signal,
|
|
57
|
+
log,
|
|
58
|
+
onEvent: o.onEvent,
|
|
59
|
+
});
|
|
60
|
+
history = result.messages.filter(m => m.role !== 'system');
|
|
61
|
+
total += result.cost;
|
|
62
|
+
turns.push(result);
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
send,
|
|
67
|
+
get total() {
|
|
68
|
+
return total;
|
|
69
|
+
},
|
|
70
|
+
get turns() {
|
|
71
|
+
return turns.length;
|
|
72
|
+
},
|
|
73
|
+
get model() {
|
|
74
|
+
return model;
|
|
75
|
+
},
|
|
76
|
+
set model(id) {
|
|
77
|
+
model = id;
|
|
78
|
+
},
|
|
79
|
+
get guidance() {
|
|
80
|
+
return guidance;
|
|
81
|
+
},
|
|
82
|
+
set guidance(g) {
|
|
83
|
+
guidance = g;
|
|
84
|
+
},
|
|
85
|
+
get maxUsd() {
|
|
86
|
+
return maxUsd;
|
|
87
|
+
},
|
|
88
|
+
set maxUsd(v) {
|
|
89
|
+
maxUsd = v;
|
|
90
|
+
},
|
|
91
|
+
get autoApprove() {
|
|
92
|
+
return autoApprove;
|
|
93
|
+
},
|
|
94
|
+
set autoApprove(v) {
|
|
95
|
+
autoApprove = v;
|
|
96
|
+
},
|
|
97
|
+
get always() {
|
|
98
|
+
return [...always];
|
|
99
|
+
},
|
|
100
|
+
get logPath() {
|
|
101
|
+
return o.logPath;
|
|
102
|
+
},
|
|
103
|
+
events: () => log.entries(),
|
|
104
|
+
clear() {
|
|
105
|
+
history = [];
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/cli/session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Toolset } from '../index.ts';
|
|
2
|
+
export declare function runCommand(command: string, cwd: string, timeoutS: number, signal: AbortSignal): Promise<{
|
|
3
|
+
code: number | null;
|
|
4
|
+
output: string;
|
|
5
|
+
timedOut: boolean;
|
|
6
|
+
}>;
|
|
7
|
+
export declare function shellToolset(root: string): Toolset;
|
|
8
|
+
//# sourceMappingURL=shell.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell.d.ts","sourceRoot":"","sources":["../../src/cli/shell.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAI3C,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC,CAqBnK;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAkBlD"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shell — one command at a time, in the working directory, each approved by the person first.
|
|
3
|
+
*
|
|
4
|
+
* Every command is a change as far as the loop is concerned (it can do anything), so the core asks
|
|
5
|
+
* `approve` with the command itself as the sentence. Output is capped, and a command that outlives
|
|
6
|
+
* its timeout — or the turn's Stop — is killed.
|
|
7
|
+
*/
|
|
8
|
+
import { spawn } from 'node:child_process';
|
|
9
|
+
const OUT_CAP = 12_000;
|
|
10
|
+
export function runCommand(command, cwd, timeoutS, signal) {
|
|
11
|
+
return new Promise(ok => {
|
|
12
|
+
const child = spawn('bash', ['-lc', command], { cwd, env: process.env, signal });
|
|
13
|
+
let output = '';
|
|
14
|
+
let timedOut = false;
|
|
15
|
+
const add = (d) => {
|
|
16
|
+
if (output.length < OUT_CAP * 2)
|
|
17
|
+
output += d.toString();
|
|
18
|
+
};
|
|
19
|
+
child.stdout.on('data', add);
|
|
20
|
+
child.stderr.on('data', add);
|
|
21
|
+
const timer = setTimeout(() => {
|
|
22
|
+
timedOut = true;
|
|
23
|
+
child.kill('SIGKILL');
|
|
24
|
+
}, timeoutS * 1000);
|
|
25
|
+
const done = (code) => {
|
|
26
|
+
clearTimeout(timer);
|
|
27
|
+
ok({ code, output: output.length > OUT_CAP ? `${output.slice(0, OUT_CAP / 2)}\n…(cut)…\n${output.slice(-OUT_CAP / 2)}` : output, timedOut });
|
|
28
|
+
};
|
|
29
|
+
child.on('close', done);
|
|
30
|
+
child.on('error', () => done(null));
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
export function shellToolset(root) {
|
|
34
|
+
return {
|
|
35
|
+
name: 'shell',
|
|
36
|
+
description: `Shell commands in ${root}.`,
|
|
37
|
+
tools: [
|
|
38
|
+
{
|
|
39
|
+
name: 'run_command',
|
|
40
|
+
description: 'Run one bash command in the working directory and get its output and exit code. Default timeout 60 s (max 600). Asks the person first.',
|
|
41
|
+
parameters: { type: 'object', properties: { command: { type: 'string' }, timeout_s: { type: 'number' } }, required: ['command'] },
|
|
42
|
+
write: { describe: a => `Run: ${String(a.command ?? '')}` },
|
|
43
|
+
run: async (a, ctx) => {
|
|
44
|
+
const t = Math.min(600, Math.max(1, Number(a.timeout_s) || 60));
|
|
45
|
+
const r = await runCommand(String(a.command ?? ''), root, t, ctx.signal);
|
|
46
|
+
return `${r.timedOut ? `(killed after ${t}s)\n` : ''}exit ${r.code ?? 'none'}\n${r.output || '(no output)'}`;
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=shell.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell.js","sourceRoot":"","sources":["../../src/cli/shell.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/ui.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the person sees: the agent's events as terminal lines, with plain ANSI (no dependency).
|
|
3
|
+
*
|
|
4
|
+
* The CLI is a test bench, so it shows the engine's inner life that an app would hide: every tool
|
|
5
|
+
* call and result, every Jev checkpoint with its probability and what the loop did, level changes,
|
|
6
|
+
* nudges, and each turn's status, steps and cost.
|
|
7
|
+
*/
|
|
8
|
+
import type { AgentEvent, AgentResult } from '../index.ts';
|
|
9
|
+
export declare const c: {
|
|
10
|
+
dim: (s: string) => string;
|
|
11
|
+
bold: (s: string) => string;
|
|
12
|
+
red: (s: string) => string;
|
|
13
|
+
green: (s: string) => string;
|
|
14
|
+
yellow: (s: string) => string;
|
|
15
|
+
blue: (s: string) => string;
|
|
16
|
+
magenta: (s: string) => string;
|
|
17
|
+
cyan: (s: string) => string;
|
|
18
|
+
};
|
|
19
|
+
export interface Printer {
|
|
20
|
+
(event: AgentEvent): void;
|
|
21
|
+
/** Whether text has been streamed since the last newline. */
|
|
22
|
+
midLine(): boolean;
|
|
23
|
+
}
|
|
24
|
+
export declare function printer(write: (s: string) => void, options: {
|
|
25
|
+
stream: boolean;
|
|
26
|
+
verbose: boolean;
|
|
27
|
+
}): Printer;
|
|
28
|
+
export declare function summary(r: AgentResult, total: number): string;
|
|
29
|
+
//# sourceMappingURL=ui.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../src/cli/ui.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI3D,eAAO,MAAM,CAAC;aADsB,MAAM;cAAN,MAAM;aAAN,MAAM;eAAN,MAAM;gBAAN,MAAM;cAAN,MAAM;iBAAN,MAAM;cAAN,MAAM;CAUzC,CAAC;AAOF,MAAM,WAAW,OAAO;IACtB,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IAC1B,6DAA6D;IAC7D,OAAO,IAAI,OAAO,CAAC;CACpB;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,EAAE,OAAO,EAAE;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAuD3G;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAG7D"}
|
package/dist/cli/ui.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
const tty = process.stdout.isTTY && !process.env.NO_COLOR;
|
|
2
|
+
const paint = (code) => (s) => (tty ? `\x1b[${code}m${s}\x1b[0m` : s);
|
|
3
|
+
export const c = {
|
|
4
|
+
dim: paint('2'),
|
|
5
|
+
bold: paint('1'),
|
|
6
|
+
red: paint('31'),
|
|
7
|
+
green: paint('32'),
|
|
8
|
+
yellow: paint('33'),
|
|
9
|
+
blue: paint('34'),
|
|
10
|
+
magenta: paint('35'),
|
|
11
|
+
cyan: paint('36'),
|
|
12
|
+
};
|
|
13
|
+
const short = (s, n) => {
|
|
14
|
+
const one = s.replace(/\s+/g, ' ').trim();
|
|
15
|
+
return one.length > n ? `${one.slice(0, n)}…` : one;
|
|
16
|
+
};
|
|
17
|
+
export function printer(write, options) {
|
|
18
|
+
let mid = false;
|
|
19
|
+
const line = (s) => {
|
|
20
|
+
if (mid)
|
|
21
|
+
write('\n');
|
|
22
|
+
mid = false;
|
|
23
|
+
write(`${s}\n`);
|
|
24
|
+
};
|
|
25
|
+
const print = ((e) => {
|
|
26
|
+
switch (e.type) {
|
|
27
|
+
case 'delta':
|
|
28
|
+
if (options.stream) {
|
|
29
|
+
write(e.text);
|
|
30
|
+
mid = !e.text.endsWith('\n');
|
|
31
|
+
}
|
|
32
|
+
return;
|
|
33
|
+
case 'message':
|
|
34
|
+
if (!options.stream)
|
|
35
|
+
line(e.text);
|
|
36
|
+
return;
|
|
37
|
+
case 'skills':
|
|
38
|
+
if (e.names.length)
|
|
39
|
+
line(c.cyan(`· skills picked by Jev: ${e.names.join(', ')}`));
|
|
40
|
+
return;
|
|
41
|
+
case 'opening':
|
|
42
|
+
if (e.path !== 'task')
|
|
43
|
+
line(c.cyan(`· Jev: ${e.path} (${e.confidence.toFixed(2)})`));
|
|
44
|
+
return;
|
|
45
|
+
case 'tool_call':
|
|
46
|
+
line(c.blue(`→ ${e.name}`) + c.dim(` ${short(JSON.stringify(e.args), 140)}`));
|
|
47
|
+
return;
|
|
48
|
+
case 'tool_result':
|
|
49
|
+
line(` ${e.ok ? c.green('✓') : c.red('✗')} ${c.dim(short(e.result, options.verbose ? 600 : 120))}`);
|
|
50
|
+
return;
|
|
51
|
+
case 'checkpoint': {
|
|
52
|
+
const p = e.p === null ? '—' : e.p.toFixed(2);
|
|
53
|
+
const what = e.choice ? `${e.choice} ` : '';
|
|
54
|
+
const col = e.action === 'pass' || e.action === 'none' ? c.dim : c.magenta;
|
|
55
|
+
line(col(`· Jev ${e.at} ${what}p=${p} → ${e.action} [${e.level}]`));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
case 'guidance':
|
|
59
|
+
line(c.magenta(`· guidance ${e.from ?? 'start'} → ${e.level} (${e.reason})`));
|
|
60
|
+
return;
|
|
61
|
+
case 'nudge':
|
|
62
|
+
line(c.yellow(`↺ ${short(e.reason, 160)}`));
|
|
63
|
+
return;
|
|
64
|
+
case 'hook':
|
|
65
|
+
if (e.verdict !== 'go')
|
|
66
|
+
line(c.yellow(`· ${e.hook}: ${e.verdict}${e.reason ? ` (${e.reason})` : ''}`));
|
|
67
|
+
return;
|
|
68
|
+
case 'context':
|
|
69
|
+
if (options.verbose && e.transient)
|
|
70
|
+
line(c.dim(` [said to the model] ${short(String(e.message.content ?? ''), 200)}`));
|
|
71
|
+
return;
|
|
72
|
+
default:
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
print.midLine = () => mid;
|
|
77
|
+
return print;
|
|
78
|
+
}
|
|
79
|
+
export function summary(r, total) {
|
|
80
|
+
const tone = r.status === 'done' || r.status === 'greeted' || r.status === 'chatted' ? c.green : r.status === 'needs_person' || r.status === 'paused' ? c.yellow : c.red;
|
|
81
|
+
return c.dim(`${tone(r.status)} · ${r.steps} steps · ${r.toolCalls} tool calls · $${r.cost.toFixed(5)} (session $${total.toFixed(5)})${r.reason ? ` · ${r.reason}` : ''}`);
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=ui.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../../src/cli/ui.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ghostmind-dev/agent",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "The agent engine every app builds its own agent from: the tool loop and its guards, a model seam (OpenRouter + Jev), budgets with a USD cap, go/pause/stop hooks, and an append-only event log. A library,
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "The agent engine every app builds its own agent from: the tool loop and its guards, a model seam (OpenRouter + Jev), the Jev guide, budgets with a USD cap, go/pause/stop hooks, and an append-only event log. A library, plus an `agent` command line to try it.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
|
+
"bin": {
|
|
8
|
+
"agent": "dist/cli/main.js"
|
|
9
|
+
},
|
|
7
10
|
"exports": {
|
|
8
11
|
".": {
|
|
9
12
|
"types": "./dist/index.d.ts",
|
|
@@ -26,7 +29,8 @@
|
|
|
26
29
|
"mcp",
|
|
27
30
|
"agent-skills",
|
|
28
31
|
"hooks",
|
|
29
|
-
"budget"
|
|
32
|
+
"budget",
|
|
33
|
+
"cli"
|
|
30
34
|
],
|
|
31
35
|
"scripts": {
|
|
32
36
|
"build": "rm -rf dist && tsc -p tsconfig.build.json",
|
|
@@ -37,8 +41,8 @@
|
|
|
37
41
|
"bench": "node bench/guidance.mts",
|
|
38
42
|
"prepublishOnly": "npm run typecheck && npm test"
|
|
39
43
|
},
|
|
40
|
-
"dependencies": {},
|
|
41
44
|
"devDependencies": {
|
|
45
|
+
"@ghostmind-dev/ensemble": "^0.31.0",
|
|
42
46
|
"@types/node": "^22.10.0",
|
|
43
47
|
"typescript": "^5.7.0"
|
|
44
48
|
},
|
|
@@ -46,5 +50,13 @@
|
|
|
46
50
|
"node": ">=22.18.0"
|
|
47
51
|
},
|
|
48
52
|
"main": "./dist/index.js",
|
|
49
|
-
"types": "./dist/index.d.ts"
|
|
53
|
+
"types": "./dist/index.d.ts",
|
|
54
|
+
"peerDependencies": {
|
|
55
|
+
"@ghostmind-dev/ensemble": ">=0.31.0"
|
|
56
|
+
},
|
|
57
|
+
"peerDependenciesMeta": {
|
|
58
|
+
"@ghostmind-dev/ensemble": {
|
|
59
|
+
"optional": true
|
|
60
|
+
}
|
|
61
|
+
}
|
|
50
62
|
}
|