@aspct3434/distill-agent 0.2.0 → 0.2.1
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 +8 -1
- package/lib/distill-cli.js +63 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -111,7 +111,7 @@ docker compose up -d --build
|
|
|
111
111
|
|
|
112
112
|
### CLI Installation
|
|
113
113
|
|
|
114
|
-
You can also install Distill globally using `npm` to get the robust interactive CLI installer:
|
|
114
|
+
You can also install Distill globally using `npm` to get the robust interactive CLI installer and TUI:
|
|
115
115
|
|
|
116
116
|
```powershell
|
|
117
117
|
npx @aspct3434/distill-agent install
|
|
@@ -119,6 +119,13 @@ npx @aspct3434/distill-agent install
|
|
|
119
119
|
|
|
120
120
|
After installation, use the CLI to manage the agent:
|
|
121
121
|
```bash
|
|
122
|
+
npm install -g @aspct3434/distill-agent
|
|
123
|
+
distill # Open the interactive terminal UI
|
|
124
|
+
distill start # Start the backend and control panel
|
|
125
|
+
distill logs # View running logs
|
|
126
|
+
distill update # Pull the latest changes
|
|
127
|
+
|
|
128
|
+
# npx works too if you prefer not to install globally:
|
|
122
129
|
npx @aspct3434/distill-agent start # Start the backend and control panel
|
|
123
130
|
npx @aspct3434/distill-agent logs # View running logs
|
|
124
131
|
npx @aspct3434/distill-agent update # Pull the latest changes
|
package/lib/distill-cli.js
CHANGED
|
@@ -192,6 +192,7 @@ function banner() {
|
|
|
192
192
|
lines.push(c.bold(hex(colors[i], line)));
|
|
193
193
|
});
|
|
194
194
|
lines.push("");
|
|
195
|
+
lines.push(` ${c.bold(hex("#A855F7", "DISTILL"))}`);
|
|
195
196
|
lines.push(` ${hex("#6B7280", "v" + packageVersion())} ${c.dim("·")} ${hex("#A855F7", "Autonomous Agent Framework")}`);
|
|
196
197
|
lines.push(` ${hex("#6B7280", "Evidence-gated execution · Skill distillation · Hybrid memory")}`);
|
|
197
198
|
lines.push("");
|
|
@@ -223,6 +224,7 @@ function usage() {
|
|
|
223
224
|
${c.bold("Distill")} — installer and lifecycle CLI
|
|
224
225
|
|
|
225
226
|
${hex("#A855F7", "Usage:")}
|
|
227
|
+
distill Launch the interactive Terminal UI
|
|
226
228
|
distill install [options] Interactive guided setup
|
|
227
229
|
distill doctor [options] Health check
|
|
228
230
|
distill start [options] Start backend + control panel
|
|
@@ -230,6 +232,7 @@ ${hex("#A855F7", "Usage:")}
|
|
|
230
232
|
distill restart [options] Restart all services
|
|
231
233
|
distill update [options] Pull latest + restart
|
|
232
234
|
distill logs [options] View service logs
|
|
235
|
+
distill tui [options] Launch the Terminal UI
|
|
233
236
|
|
|
234
237
|
${hex("#A855F7", "Install options:")}
|
|
235
238
|
--repo-url URL Git repository URL
|
|
@@ -248,8 +251,11 @@ ${hex("#A855F7", "Lifecycle options:")}
|
|
|
248
251
|
--sandbox on|off Override sandbox mode
|
|
249
252
|
--tail NUMBER Number of log lines to show ${c.dim("(default: 200)")}
|
|
250
253
|
--follow Stream logs continuously
|
|
254
|
+
--url URL Gateway WebSocket URL for the TUI
|
|
255
|
+
--theme NAME TUI theme ${c.dim("(distill|ocean|ember|mono)")}
|
|
251
256
|
|
|
252
257
|
${hex("#A855F7", "Examples:")}
|
|
258
|
+
${c.dim("$")} distill
|
|
253
259
|
${c.dim("$")} npx @aspct3434/distill-agent install
|
|
254
260
|
${c.dim("$")} npx @aspct3434/distill-agent doctor
|
|
255
261
|
${c.dim("$")} npx @aspct3434/distill-agent logs --tail 100 --follow
|
|
@@ -257,7 +263,7 @@ ${hex("#A855F7", "Examples:")}
|
|
|
257
263
|
}
|
|
258
264
|
|
|
259
265
|
function parseArgs(argv) {
|
|
260
|
-
const result = { command: "
|
|
266
|
+
const result = { command: "tui", options: {} };
|
|
261
267
|
const args = [...argv];
|
|
262
268
|
if (args.length > 0 && !args[0].startsWith("-")) {
|
|
263
269
|
result.command = args.shift();
|
|
@@ -270,7 +276,9 @@ function parseArgs(argv) {
|
|
|
270
276
|
"sandbox",
|
|
271
277
|
"messaging",
|
|
272
278
|
"mode",
|
|
273
|
-
"tail"
|
|
279
|
+
"tail",
|
|
280
|
+
"url",
|
|
281
|
+
"theme"
|
|
274
282
|
]);
|
|
275
283
|
const booleanOptions = new Set([
|
|
276
284
|
"dry-run",
|
|
@@ -1241,9 +1249,10 @@ async function startServices(config) {
|
|
|
1241
1249
|
`${hex("#A855F7", "Control Panel:")} ${c.underline("http://localhost:5173")}`,
|
|
1242
1250
|
`${hex("#A855F7", "API Docs:")} ${c.underline("http://localhost:8000/docs")}`,
|
|
1243
1251
|
`${hex("#A855F7", "Health Check:")} ${c.underline("http://localhost:8000/health")}`,
|
|
1244
|
-
`${hex("#A855F7", "Terminal UI:")} ${c.dim("
|
|
1252
|
+
`${hex("#A855F7", "Terminal UI:")} ${c.dim("distill")}`,
|
|
1245
1253
|
"",
|
|
1246
1254
|
`${c.dim("Manage with:")}`,
|
|
1255
|
+
` ${c.dim("$")} distill`,
|
|
1247
1256
|
` ${c.dim("$")} npx @aspct3434/distill-agent stop`,
|
|
1248
1257
|
` ${c.dim("$")} npx @aspct3434/distill-agent logs --follow`,
|
|
1249
1258
|
` ${c.dim("$")} npx @aspct3434/distill-agent doctor`,
|
|
@@ -1347,6 +1356,19 @@ function spawnDetached(command, args, cwd, stdoutPath, stderrPath, dryRun) {
|
|
|
1347
1356
|
logStep(`[dry-run] ${formatCommand(command, args)} > ${stdoutPath} 2> ${stderrPath}`, cwd);
|
|
1348
1357
|
return { pid: 0 };
|
|
1349
1358
|
}
|
|
1359
|
+
if (process.platform === "win32") {
|
|
1360
|
+
const psArgs = [
|
|
1361
|
+
"-NoProfile", "-NonInteractive", "-Command",
|
|
1362
|
+
`$proc = Start-Process -FilePath "${command}" -ArgumentList @(${args.map(a => `"${a.replace(/"/g, '""')}"`).join(", ")}) -WorkingDirectory "${cwd}" -WindowStyle Hidden -PassThru -RedirectStandardOutput "${stdoutPath}" -RedirectStandardError "${stderrPath}"; Write-Output $proc.Id`
|
|
1363
|
+
];
|
|
1364
|
+
const result = spawnSync("powershell", psArgs, { windowsHide: true });
|
|
1365
|
+
const pidStr = result.stdout ? result.stdout.toString().trim() : "";
|
|
1366
|
+
const pid = parseInt(pidStr, 10);
|
|
1367
|
+
if (isNaN(pid)) {
|
|
1368
|
+
throw new Error(`Failed to start detached process on Windows. Output: ${result.stdout} ${result.stderr}`);
|
|
1369
|
+
}
|
|
1370
|
+
return { pid };
|
|
1371
|
+
}
|
|
1350
1372
|
const stdout = fs.openSync(stdoutPath, "a");
|
|
1351
1373
|
const stderr = fs.openSync(stderrPath, "a");
|
|
1352
1374
|
const child = spawn(command, args, {
|
|
@@ -1491,6 +1513,35 @@ async function doctor(options) {
|
|
|
1491
1513
|
}
|
|
1492
1514
|
}
|
|
1493
1515
|
|
|
1516
|
+
// ─── TUI ─────────────────────────────────────────────────────────────────────
|
|
1517
|
+
|
|
1518
|
+
function resolveTuiPython(config) {
|
|
1519
|
+
for (const name of [".run-venv", "venv"]) {
|
|
1520
|
+
const venvDir = path.join(config.installDir, name);
|
|
1521
|
+
const candidate = virtualEnvPython(venvDir);
|
|
1522
|
+
if (fs.existsSync(candidate)) return [candidate, []];
|
|
1523
|
+
}
|
|
1524
|
+
const systemPython = pythonCommand();
|
|
1525
|
+
if (systemPython && isAgentRepo(config.installDir)) return systemPython;
|
|
1526
|
+
throw new Error(
|
|
1527
|
+
"Python environment not found. Run 'distill install' first, or run from a Distill checkout with dependencies installed."
|
|
1528
|
+
);
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
async function startTui(config, options = {}) {
|
|
1532
|
+
if (!config.dryRun && !isAgentRepo(config.installDir)) {
|
|
1533
|
+
throw new Error(`Install directory is not a Distill checkout: ${config.installDir}`);
|
|
1534
|
+
}
|
|
1535
|
+
const [python, pythonPrefix] = config.dryRun
|
|
1536
|
+
? (pythonCommand() || ["python3", []])
|
|
1537
|
+
: resolveTuiPython(config);
|
|
1538
|
+
const args = [...pythonPrefix, "src/tui.py"];
|
|
1539
|
+
if (options.url) args.push("--url", options.url);
|
|
1540
|
+
if (options.theme) args.push("--theme", options.theme);
|
|
1541
|
+
|
|
1542
|
+
await run(python, args, { cwd: config.installDir, stdio: "inherit", dryRun: config.dryRun });
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1494
1545
|
// ─── Install ─────────────────────────────────────────────────────────────────
|
|
1495
1546
|
|
|
1496
1547
|
async function install(options) {
|
|
@@ -1558,6 +1609,7 @@ async function install(options) {
|
|
|
1558
1609
|
|
|
1559
1610
|
async function main(argv = process.argv.slice(2)) {
|
|
1560
1611
|
const { command, options } = parseArgs(argv);
|
|
1612
|
+
const implicitTui = argv.length === 0;
|
|
1561
1613
|
switch (command) {
|
|
1562
1614
|
case "help":
|
|
1563
1615
|
case undefined:
|
|
@@ -1597,6 +1649,14 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
1597
1649
|
case "logs":
|
|
1598
1650
|
await showLogs(resolveRuntimeConfig(options), options);
|
|
1599
1651
|
break;
|
|
1652
|
+
case "tui":
|
|
1653
|
+
if (implicitTui && (!process.stdin.isTTY || !process.stdout.isTTY)) {
|
|
1654
|
+
console.log(banner());
|
|
1655
|
+
console.log(usage());
|
|
1656
|
+
break;
|
|
1657
|
+
}
|
|
1658
|
+
await startTui(resolveRuntimeConfig(options), options);
|
|
1659
|
+
break;
|
|
1600
1660
|
default:
|
|
1601
1661
|
throw new Error(`Unknown command: ${command}\n${usage()}`);
|
|
1602
1662
|
}
|