@9thprotocol/cli 0.1.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/LICENSE +16 -0
- package/README.md +43 -0
- package/dist/init.d.ts +2 -0
- package/dist/init.js +61 -0
- package/dist/login.d.ts +4 -0
- package/dist/login.js +161 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +53 -0
- package/dist/map.d.ts +2 -0
- package/dist/map.js +57 -0
- package/dist/repl.d.ts +1 -0
- package/dist/repl.js +266 -0
- package/dist/scripts/tui-smoke.d.ts +1 -0
- package/dist/scripts/tui-smoke.js +64 -0
- package/dist/serve.d.ts +8 -0
- package/dist/serve.js +225 -0
- package/dist/shared.d.ts +60 -0
- package/dist/shared.js +192 -0
- package/dist/tui/app.d.ts +28 -0
- package/dist/tui/app.js +191 -0
- package/dist/tui/index.d.ts +2 -0
- package/dist/tui/index.js +35 -0
- package/dist/webui.d.ts +13 -0
- package/dist/webui.js +1056 -0
- package/package.json +41 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
9th Protocol — Proprietary License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 9th Protocol. All rights reserved.
|
|
4
|
+
|
|
5
|
+
This software and its source code are the property of 9th Protocol.
|
|
6
|
+
It is licensed, not sold. You may install and use the unmodified
|
|
7
|
+
package for its intended purpose. You may not copy, modify, merge,
|
|
8
|
+
publish, distribute, sublicense, decompile, or reverse engineer it,
|
|
9
|
+
or use it to build a competing agent product, without a separate
|
|
10
|
+
written license from 9th Protocol.
|
|
11
|
+
|
|
12
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
13
|
+
EXPRESS OR IMPLIED. IN NO EVENT SHALL 9TH PROTOCOL BE LIABLE FOR
|
|
14
|
+
ANY CLAIM, DAMAGES OR OTHER LIABILITY ARISING FROM THE SOFTWARE.
|
|
15
|
+
|
|
16
|
+
Contact: licensing@9thprotocol.com
|
package/README.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# 9p — the 9th Protocol terminal coding agent
|
|
2
|
+
|
|
3
|
+
An agentic coder for your terminal, powered by OpenRouter so you can use the
|
|
4
|
+
model of your choice: the agent loop, tools, permissions, sub-agents, memory
|
|
5
|
+
and model routing all live in `9p`. Subscriptions and credit budgets are
|
|
6
|
+
managed on the [9th Protocol dashboard](https://9thprotocol.com).
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
npm install -g @9thprotocol/cli
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Requires Node 22 or newer (macOS and Linux; Windows best-effort).
|
|
15
|
+
|
|
16
|
+
## Quick start
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
9p login # opens a browser to sign in / create your account
|
|
20
|
+
9p # start an interactive session in your project directory
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Other modes:
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
9p --plain # non-TUI REPL for scripting and CI
|
|
27
|
+
9p serve 4310 # local web session UI on port 4310
|
|
28
|
+
9p init # set up a project config / vault
|
|
29
|
+
9p map # generate a codebase wiki
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Credentials are stored in `~/.9p/auth.json`. To use your own OpenRouter key
|
|
33
|
+
instead of the platform, set `OPENROUTER_API_KEY`.
|
|
34
|
+
|
|
35
|
+
## Links
|
|
36
|
+
|
|
37
|
+
- Dashboard: https://9thprotocol.com
|
|
38
|
+
- Docs: https://docs.9thprotocol.com
|
|
39
|
+
|
|
40
|
+
## License
|
|
41
|
+
|
|
42
|
+
Proprietary — see [LICENSE](./LICENSE). The engine it runs on is
|
|
43
|
+
[`@9thprotocol/agent-core`](https://www.npmjs.com/package/@9thprotocol/agent-core).
|
package/dist/init.d.ts
ADDED
package/dist/init.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import readline from "node:readline/promises";
|
|
2
|
+
import { stdin, stdout } from "node:process";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { saveProjectConfig, scaffoldVault, loadProjectConfig } from "@9thprotocol/agent-core";
|
|
6
|
+
import { cyan, dim, yellow } from "./shared.js";
|
|
7
|
+
const STARTER_9P_MD = `# Project memory
|
|
8
|
+
|
|
9
|
+
Standing instructions for the 9p agent in this project. Keep this file short -
|
|
10
|
+
it loads into every session.
|
|
11
|
+
|
|
12
|
+
## Conventions
|
|
13
|
+
- (add your project's conventions here)
|
|
14
|
+
`;
|
|
15
|
+
/** `9p init`: set up project memory: plain 9P.md, or an Obsidian-style vault. */
|
|
16
|
+
export async function runInit(cwd) {
|
|
17
|
+
const rl = readline.createInterface({ input: stdin, output: stdout });
|
|
18
|
+
// piped/scripted stdin can hit EOF mid-question. Treat it as "accept defaults"
|
|
19
|
+
let closed = false;
|
|
20
|
+
const onClose = new Promise((resolve) => rl.once("close", () => {
|
|
21
|
+
closed = true;
|
|
22
|
+
resolve("");
|
|
23
|
+
}));
|
|
24
|
+
const ask = (q) => (closed ? Promise.resolve("") : Promise.race([rl.question(q), onClose]));
|
|
25
|
+
console.log(cyan("9p init, project memory setup"));
|
|
26
|
+
const existing = loadProjectConfig(cwd);
|
|
27
|
+
if (existing.vault) {
|
|
28
|
+
console.log(dim(`vault already configured: ${existing.vault}`));
|
|
29
|
+
}
|
|
30
|
+
const choice = (await ask(`How should this project remember things?\n` +
|
|
31
|
+
` 1. simple, a 9P.md file with standing instructions\n` +
|
|
32
|
+
` 2. vault, an Obsidian-style folder: index, jobs, daily logs, decisions, codebase maps\n` +
|
|
33
|
+
`choose [1/2]: `)).trim();
|
|
34
|
+
if (choice === "2") {
|
|
35
|
+
const answer = (await ask(`vault location (default: ./vault): `)).trim();
|
|
36
|
+
const vaultRel = answer || "vault";
|
|
37
|
+
const vaultAbs = path.resolve(cwd, vaultRel);
|
|
38
|
+
const created = scaffoldVault(vaultAbs);
|
|
39
|
+
saveProjectConfig(cwd, { ...existing, vault: vaultRel });
|
|
40
|
+
console.log(created.length ? dim(`created:\n ${created.join("\n ")}`) : dim("vault already scaffolded"));
|
|
41
|
+
console.log(`${cyan("vault linked.")} The agent now reads ${vaultRel}/INDEX.md first, appends instead of
|
|
42
|
+
creating notes, and logs work to daily notes. Run ${cyan("9p map")} to generate codebase maps.`);
|
|
43
|
+
console.log(dim("Tip: open the vault folder in Obsidian (obsidian.md) to see the knowledge graph.\n" +
|
|
44
|
+
"Your memory store stays on this device; prompts that reference it go to the models you use."));
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
const file = path.join(cwd, "9P.md");
|
|
48
|
+
if (fs.existsSync(file)) {
|
|
49
|
+
console.log(dim(`9P.md already exists at ${file}, left untouched`));
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
fs.writeFileSync(file, STARTER_9P_MD);
|
|
53
|
+
console.log(`${cyan("created")} ${file}. It loads into every session in this project.`);
|
|
54
|
+
}
|
|
55
|
+
if (choice !== "1" && choice !== "")
|
|
56
|
+
console.log(yellow("(unrecognized choice, defaulted to simple)"));
|
|
57
|
+
}
|
|
58
|
+
if (!closed)
|
|
59
|
+
rl.close();
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=init.js.map
|
package/dist/login.d.ts
ADDED
package/dist/login.js
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `9p login` / `9p logout`: device authorization grant (RFC 8628).
|
|
3
|
+
*
|
|
4
|
+
* Replaces hand-editing ~/.9p/auth.json. The CLI never sees the password: it
|
|
5
|
+
* gets a short code, the user approves it in the browser, and the CLI polls
|
|
6
|
+
* until tokens come back.
|
|
7
|
+
*/
|
|
8
|
+
import fs from "node:fs";
|
|
9
|
+
import os from "node:os";
|
|
10
|
+
import path from "node:path";
|
|
11
|
+
import { spawn } from "node:child_process";
|
|
12
|
+
import readline from "node:readline/promises";
|
|
13
|
+
import { stdin, stdout } from "node:process";
|
|
14
|
+
import { cyan, dim, red, yellow } from "./shared.js";
|
|
15
|
+
const DEFAULT_API_URL = "https://9th-prot-api.bundleboss.net/v1";
|
|
16
|
+
const authFile = path.join(os.homedir(), ".9p", "auth.json");
|
|
17
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
18
|
+
/** Best-effort browser open; the code is always printed so this failing is harmless. */
|
|
19
|
+
function openBrowser(url) {
|
|
20
|
+
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
21
|
+
try {
|
|
22
|
+
spawn(cmd, [url], { stdio: "ignore", detached: true, shell: process.platform === "win32" })
|
|
23
|
+
.on("error", () => { })
|
|
24
|
+
.unref();
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
// no browser available. The printed URL is the fallback
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function readAuthFile() {
|
|
31
|
+
try {
|
|
32
|
+
return JSON.parse(fs.readFileSync(authFile, "utf8"));
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return {};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function writeAuthFile(data) {
|
|
39
|
+
fs.mkdirSync(path.dirname(authFile), { recursive: true });
|
|
40
|
+
// 0600: this file holds a refresh token good for 30 days.
|
|
41
|
+
fs.writeFileSync(authFile, JSON.stringify(data, null, 2) + "\n", { mode: 0o600 });
|
|
42
|
+
fs.chmodSync(authFile, 0o600);
|
|
43
|
+
}
|
|
44
|
+
export async function runLogin() {
|
|
45
|
+
const apiUrl = (process.env.NINEP_API_URL ?? DEFAULT_API_URL).replace(/\/$/, "");
|
|
46
|
+
let start;
|
|
47
|
+
try {
|
|
48
|
+
const res = await fetch(`${apiUrl}/auth/device/code`, {
|
|
49
|
+
method: "POST",
|
|
50
|
+
headers: { "Content-Type": "application/json" },
|
|
51
|
+
body: JSON.stringify({ clientLabel: `9p CLI on ${os.hostname()} (${process.platform})` }),
|
|
52
|
+
});
|
|
53
|
+
if (!res.ok)
|
|
54
|
+
throw new Error(`${res.status}: ${await res.text()}`);
|
|
55
|
+
start = (await res.json());
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
console.error(red("Could not reach the 9th Protocol API.") + ` ${String(err)}`);
|
|
59
|
+
console.error(dim(`API URL: ${apiUrl}, override with NINEP_API_URL`));
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
console.log(`\n${cyan("Sign in to 9th Protocol")}`);
|
|
63
|
+
console.log(`\n code: ${cyan(start.userCode)}`);
|
|
64
|
+
console.log(` open: ${start.verificationUri}\n`);
|
|
65
|
+
console.log(dim("Approve the code in your browser. Waiting…"));
|
|
66
|
+
openBrowser(start.verificationUriComplete);
|
|
67
|
+
const deadline = Date.now() + start.expiresIn * 1000;
|
|
68
|
+
let interval = Math.max(1, start.interval) * 1000;
|
|
69
|
+
while (Date.now() < deadline) {
|
|
70
|
+
await sleep(interval);
|
|
71
|
+
let payload;
|
|
72
|
+
let ok;
|
|
73
|
+
try {
|
|
74
|
+
const res = await fetch(`${apiUrl}/auth/device/token`, {
|
|
75
|
+
method: "POST",
|
|
76
|
+
headers: { "Content-Type": "application/json" },
|
|
77
|
+
body: JSON.stringify({ deviceCode: start.deviceCode }),
|
|
78
|
+
});
|
|
79
|
+
ok = res.ok;
|
|
80
|
+
payload = (await res.json());
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
continue; // transient network blip. Keep polling until the deadline
|
|
84
|
+
}
|
|
85
|
+
if (ok) {
|
|
86
|
+
const tokens = payload;
|
|
87
|
+
writeAuthFile({
|
|
88
|
+
...readAuthFile(),
|
|
89
|
+
apiUrl,
|
|
90
|
+
token: tokens.accessToken,
|
|
91
|
+
refreshToken: tokens.refreshToken,
|
|
92
|
+
email: tokens.user.email,
|
|
93
|
+
});
|
|
94
|
+
console.log(`\n${cyan("✓ signed in")} as ${tokens.user.email} ${dim(`(plan: ${tokens.user.plan})`)}`);
|
|
95
|
+
console.log(dim(`credentials saved to ${authFile}`));
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
switch (payload.error) {
|
|
99
|
+
case "authorization_pending":
|
|
100
|
+
break; // expected while the user is still approving
|
|
101
|
+
case "slow_down":
|
|
102
|
+
interval += 2000; // the server says we're too eager
|
|
103
|
+
break;
|
|
104
|
+
case "access_denied":
|
|
105
|
+
console.error(`\n${red("Request denied.")} Nothing was saved.`);
|
|
106
|
+
process.exit(1);
|
|
107
|
+
// eslint-disable-next-line no-fallthrough
|
|
108
|
+
case "expired_token":
|
|
109
|
+
console.error(`\n${red("Code expired.")} Run ${cyan("9p login")} again.`);
|
|
110
|
+
process.exit(1);
|
|
111
|
+
// eslint-disable-next-line no-fallthrough
|
|
112
|
+
default:
|
|
113
|
+
console.error(`\n${red("Login failed:")} ${String(payload.message ?? payload.error)}`);
|
|
114
|
+
process.exit(1);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
console.error(`\n${red("Timed out")} waiting for approval. Run ${cyan("9p login")} again.`);
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
export async function runLogout() {
|
|
121
|
+
const file = readAuthFile();
|
|
122
|
+
if (!file.token && !file.refreshToken) {
|
|
123
|
+
console.log(dim("Not signed in."));
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const apiUrl = String(file.apiUrl ?? process.env.NINEP_API_URL ?? DEFAULT_API_URL).replace(/\/$/, "");
|
|
127
|
+
if (typeof file.refreshToken === "string") {
|
|
128
|
+
// Revoke server-side so a leaked file can't be replayed.
|
|
129
|
+
try {
|
|
130
|
+
await fetch(`${apiUrl}/auth/logout`, {
|
|
131
|
+
method: "POST",
|
|
132
|
+
headers: { "Content-Type": "application/json" },
|
|
133
|
+
body: JSON.stringify({ refreshToken: file.refreshToken }),
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
console.log(yellow("Could not reach the API to revoke the token; clearing locally."));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Keep any BYOK key, logging out of the platform shouldn't wipe that.
|
|
141
|
+
const { token: _t, refreshToken: _r, apiUrl: _u, email: _e, ...rest } = file;
|
|
142
|
+
if (Object.keys(rest).length)
|
|
143
|
+
writeAuthFile(rest);
|
|
144
|
+
else
|
|
145
|
+
fs.rmSync(authFile, { force: true });
|
|
146
|
+
console.log(cyan("✓ signed out"));
|
|
147
|
+
}
|
|
148
|
+
/** Prompt-based fallback for `9p login --paste` (headless boxes with no browser). */
|
|
149
|
+
export async function runLoginPaste() {
|
|
150
|
+
const rl = readline.createInterface({ input: stdin, output: stdout });
|
|
151
|
+
const apiUrl = ((await rl.question(`API URL [${DEFAULT_API_URL}]: `)).trim() || DEFAULT_API_URL).replace(/\/$/, "");
|
|
152
|
+
const token = (await rl.question("access token: ")).trim();
|
|
153
|
+
rl.close();
|
|
154
|
+
if (!token) {
|
|
155
|
+
console.error(red("No token given."));
|
|
156
|
+
process.exit(1);
|
|
157
|
+
}
|
|
158
|
+
writeAuthFile({ ...readAuthFile(), apiUrl, token });
|
|
159
|
+
console.log(cyan("✓ saved") + dim(` → ${authFile}`));
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=login.js.map
|
package/dist/main.d.ts
ADDED
package/dist/main.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* 9p, the 9th Protocol coding agent.
|
|
4
|
+
* 9p interactive session (Ink TUI in a TTY; --plain for the bare REPL)
|
|
5
|
+
* 9p login sign in via the browser (device grant); --paste for headless
|
|
6
|
+
* 9p logout revoke and clear saved credentials
|
|
7
|
+
* 9p init project memory setup: 9P.md or an Obsidian-style vault
|
|
8
|
+
* 9p map generate/refresh codebase wiki notes in the vault
|
|
9
|
+
* 9p serve [port] local web session (used standalone and by the VS Code extension)
|
|
10
|
+
*/
|
|
11
|
+
import { runRepl } from "./repl.js";
|
|
12
|
+
import { runInit } from "./init.js";
|
|
13
|
+
import { runMap } from "./map.js";
|
|
14
|
+
import { runServe } from "./serve.js";
|
|
15
|
+
import { runLogin, runLoginPaste, runLogout } from "./login.js";
|
|
16
|
+
const cwd = process.cwd();
|
|
17
|
+
const args = process.argv.slice(2);
|
|
18
|
+
const cmd = args[0];
|
|
19
|
+
switch (cmd) {
|
|
20
|
+
case "login":
|
|
21
|
+
await (args.includes("--paste") ? runLoginPaste() : runLogin());
|
|
22
|
+
break;
|
|
23
|
+
case "logout":
|
|
24
|
+
await runLogout();
|
|
25
|
+
break;
|
|
26
|
+
case "init":
|
|
27
|
+
await runInit(cwd);
|
|
28
|
+
break;
|
|
29
|
+
case "map":
|
|
30
|
+
await runMap(cwd);
|
|
31
|
+
break;
|
|
32
|
+
case "serve": {
|
|
33
|
+
const port = Number(args[1] ?? process.env.NINEP_PORT ?? 4310);
|
|
34
|
+
await runServe(cwd, port);
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
case "--plain":
|
|
38
|
+
await runRepl(cwd);
|
|
39
|
+
break;
|
|
40
|
+
case undefined:
|
|
41
|
+
if (process.stdout.isTTY && process.stdin.isTTY) {
|
|
42
|
+
const { runTui } = await import("./tui/index.js");
|
|
43
|
+
await runTui(cwd);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
await runRepl(cwd);
|
|
47
|
+
}
|
|
48
|
+
break;
|
|
49
|
+
default:
|
|
50
|
+
console.error(`unknown command: ${cmd}\nusage: 9p [login|logout|init|map|serve [port]|--plain]`);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=main.js.map
|
package/dist/map.d.ts
ADDED
package/dist/map.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { AgentSession, resolveVault } from "@9thprotocol/agent-core";
|
|
2
|
+
import { cyan, dim, red, requireAuth, usageLine, DEFAULT_MODEL, fetchCatalog } from "./shared.js";
|
|
3
|
+
function mapPrompt(vault) {
|
|
4
|
+
return `Map this codebase into the vault's graph section so future sessions can navigate the map instead of re-reading raw files.
|
|
5
|
+
|
|
6
|
+
1. Explore the project with glob/grep/read: layout, packages/modules, entry points, configs.
|
|
7
|
+
2. Write concise wiki notes (each under 60 lines) into ${vault}/graph/:
|
|
8
|
+
- index.md, the entry point: one line per note with a [[wiki link]] and what it covers
|
|
9
|
+
- one note per major module/package/area: purpose, key files with paths, how it connects to the rest, [[wiki links]] to related notes
|
|
10
|
+
3. If a note already exists, update it in place rather than duplicating.
|
|
11
|
+
4. Update ${vault}/INDEX.md so it links to graph/index (only if not already linked).
|
|
12
|
+
|
|
13
|
+
Return a one-paragraph summary of what you mapped.`;
|
|
14
|
+
}
|
|
15
|
+
/** `9p map`: generate/refresh graphify-style codebase wiki notes in the vault. */
|
|
16
|
+
export async function runMap(cwd) {
|
|
17
|
+
const vault = resolveVault(cwd);
|
|
18
|
+
if (!vault) {
|
|
19
|
+
console.error(red("No vault configured.") + ` Run ${cyan("9p init")} and choose the vault option first.`);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
const auth = await requireAuth();
|
|
23
|
+
const catalog = await fetchCatalog(auth);
|
|
24
|
+
const session = new AgentSession({
|
|
25
|
+
apiKey: auth.apiKey,
|
|
26
|
+
...(auth.platform ? { platform: auth.platform } : {}),
|
|
27
|
+
model: process.env.NINEP_MODEL ?? DEFAULT_MODEL,
|
|
28
|
+
// Mapping is bulk read-and-summarise across a whole repo, economy by design.
|
|
29
|
+
autoRouter: { bias: "economy", ...(catalog ? { catalog } : {}) },
|
|
30
|
+
cwd,
|
|
31
|
+
// writes auto-allowed (the prompt constrains them to the vault); bash denied, mapping is read+write only
|
|
32
|
+
mode: "accept-edits",
|
|
33
|
+
decide: async () => false,
|
|
34
|
+
});
|
|
35
|
+
console.log(cyan("9p map") + dim(`, mapping ${cwd} → ${vault}/graph (model: ${session.model})`));
|
|
36
|
+
for await (const ev of session.send(mapPrompt(vault))) {
|
|
37
|
+
switch (ev.type) {
|
|
38
|
+
case "text_delta":
|
|
39
|
+
process.stdout.write(ev.text);
|
|
40
|
+
break;
|
|
41
|
+
case "tool_start":
|
|
42
|
+
console.log(dim(`⚙ ${ev.summary}`));
|
|
43
|
+
break;
|
|
44
|
+
case "tool_end":
|
|
45
|
+
if (ev.isError)
|
|
46
|
+
console.log(dim(` ✗ ${ev.output.split("\n")[0] ?? ""}`));
|
|
47
|
+
break;
|
|
48
|
+
case "turn_end":
|
|
49
|
+
console.log(`\n${dim("⏺ " + usageLine(ev.usage))}`);
|
|
50
|
+
break;
|
|
51
|
+
case "error":
|
|
52
|
+
console.error(red(`\nerror: ${ev.message}`));
|
|
53
|
+
process.exitCode = 1;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=map.js.map
|
package/dist/repl.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runRepl(cwd: string): Promise<void>;
|