vaan-ai 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.
Files changed (106) hide show
  1. package/LICENSE +216 -0
  2. package/README.md +390 -0
  3. package/dist/src/agent.js +151 -0
  4. package/dist/src/agent.js.map +1 -0
  5. package/dist/src/cli/args.js +38 -0
  6. package/dist/src/cli/args.js.map +1 -0
  7. package/dist/src/cli/doctor.js +98 -0
  8. package/dist/src/cli/doctor.js.map +1 -0
  9. package/dist/src/cli/dotenv.js +58 -0
  10. package/dist/src/cli/dotenv.js.map +1 -0
  11. package/dist/src/cli/main.js +138 -0
  12. package/dist/src/cli/main.js.map +1 -0
  13. package/dist/src/cli/memory-cmd.js +31 -0
  14. package/dist/src/cli/memory-cmd.js.map +1 -0
  15. package/dist/src/cli/repl.js +275 -0
  16. package/dist/src/cli/repl.js.map +1 -0
  17. package/dist/src/cli/schedule.js +184 -0
  18. package/dist/src/cli/schedule.js.map +1 -0
  19. package/dist/src/cli/suggested.js +26 -0
  20. package/dist/src/cli/suggested.js.map +1 -0
  21. package/dist/src/cli/trace-cmd.js +69 -0
  22. package/dist/src/cli/trace-cmd.js.map +1 -0
  23. package/dist/src/cli/wizard.js +346 -0
  24. package/dist/src/cli/wizard.js.map +1 -0
  25. package/dist/src/config.js +130 -0
  26. package/dist/src/config.js.map +1 -0
  27. package/dist/src/eval/graders.js +145 -0
  28. package/dist/src/eval/graders.js.map +1 -0
  29. package/dist/src/eval/report.js +20 -0
  30. package/dist/src/eval/report.js.map +1 -0
  31. package/dist/src/eval/runner.js +67 -0
  32. package/dist/src/eval/runner.js.map +1 -0
  33. package/dist/src/eval/suites.js +164 -0
  34. package/dist/src/eval/suites.js.map +1 -0
  35. package/dist/src/http.js +134 -0
  36. package/dist/src/http.js.map +1 -0
  37. package/dist/src/inbox.js +51 -0
  38. package/dist/src/inbox.js.map +1 -0
  39. package/dist/src/index.js +180 -0
  40. package/dist/src/index.js.map +1 -0
  41. package/dist/src/memory/context.js +63 -0
  42. package/dist/src/memory/context.js.map +1 -0
  43. package/dist/src/memory/index.js +28 -0
  44. package/dist/src/memory/index.js.map +1 -0
  45. package/dist/src/memory/search.js +32 -0
  46. package/dist/src/memory/search.js.map +1 -0
  47. package/dist/src/memory/store.js +171 -0
  48. package/dist/src/memory/store.js.map +1 -0
  49. package/dist/src/observability/events.js +109 -0
  50. package/dist/src/observability/events.js.map +1 -0
  51. package/dist/src/observability/request.js +20 -0
  52. package/dist/src/observability/request.js.map +1 -0
  53. package/dist/src/observability/trace.js +149 -0
  54. package/dist/src/observability/trace.js.map +1 -0
  55. package/dist/src/paths.js +24 -0
  56. package/dist/src/paths.js.map +1 -0
  57. package/dist/src/permissions/approval.js +80 -0
  58. package/dist/src/permissions/approval.js.map +1 -0
  59. package/dist/src/permissions/policy.js +75 -0
  60. package/dist/src/permissions/policy.js.map +1 -0
  61. package/dist/src/permissions/rules.js +200 -0
  62. package/dist/src/permissions/rules.js.map +1 -0
  63. package/dist/src/prompt.js +114 -0
  64. package/dist/src/prompt.js.map +1 -0
  65. package/dist/src/providers/anthropic.js +233 -0
  66. package/dist/src/providers/anthropic.js.map +1 -0
  67. package/dist/src/providers/custom.js +46 -0
  68. package/dist/src/providers/custom.js.map +1 -0
  69. package/dist/src/providers/google.js +197 -0
  70. package/dist/src/providers/google.js.map +1 -0
  71. package/dist/src/providers/index.js +122 -0
  72. package/dist/src/providers/index.js.map +1 -0
  73. package/dist/src/providers/ollama.js +44 -0
  74. package/dist/src/providers/ollama.js.map +1 -0
  75. package/dist/src/providers/openai.js +193 -0
  76. package/dist/src/providers/openai.js.map +1 -0
  77. package/dist/src/providers/shared.js +32 -0
  78. package/dist/src/providers/shared.js.map +1 -0
  79. package/dist/src/sandbox/filesystem.js +193 -0
  80. package/dist/src/sandbox/filesystem.js.map +1 -0
  81. package/dist/src/sandbox/network.js +119 -0
  82. package/dist/src/sandbox/network.js.map +1 -0
  83. package/dist/src/sandbox/process.js +198 -0
  84. package/dist/src/sandbox/process.js.map +1 -0
  85. package/dist/src/skills.js +80 -0
  86. package/dist/src/skills.js.map +1 -0
  87. package/dist/src/tools/basics.js +41 -0
  88. package/dist/src/tools/basics.js.map +1 -0
  89. package/dist/src/tools/code.js +114 -0
  90. package/dist/src/tools/code.js.map +1 -0
  91. package/dist/src/tools/files.js +162 -0
  92. package/dist/src/tools/files.js.map +1 -0
  93. package/dist/src/tools/git.js +91 -0
  94. package/dist/src/tools/git.js.map +1 -0
  95. package/dist/src/tools/grep.js +92 -0
  96. package/dist/src/tools/grep.js.map +1 -0
  97. package/dist/src/tools/index.js +66 -0
  98. package/dist/src/tools/index.js.map +1 -0
  99. package/dist/src/tools/shared.js +11 -0
  100. package/dist/src/tools/shared.js.map +1 -0
  101. package/dist/src/tools/web.js +217 -0
  102. package/dist/src/tools/web.js.map +1 -0
  103. package/dist/src/types.js +14 -0
  104. package/dist/src/types.js.map +1 -0
  105. package/package.json +59 -0
  106. package/scripts/postinstall.js +47 -0
@@ -0,0 +1,275 @@
1
+ // The REPL. There is no single-shot mode: a positional-argument branch would
2
+ // duplicate this whole path to save one keystroke, and piping into Vaan is a
3
+ // different program. If stdin isn't a terminal we say so and leave, rather than
4
+ // blocking forever on a prompt nobody can answer.
5
+ //
6
+ // The approval prompt lives here, and that placement is the security design.
7
+ // `approve` below is closed over this readline handle, attached to the real
8
+ // terminal. It is handed to createSession and never leaves that closure — no
9
+ // tool receives it, nothing the model emits can reach it. When the gate needs a
10
+ // yes, it comes from a person or it doesn't come.
11
+ import { createInterface } from "node:readline/promises";
12
+ import { describeConfig } from "../config.js";
13
+ import { clearInbox, readInbox } from "../inbox.js";
14
+ import { createSession } from "../index.js";
15
+ import { shortId } from "../observability/request.js";
16
+ import { statuses } from "../providers/index.js";
17
+ import { activeGroups, GROUPS } from "../tools/index.js";
18
+ import { printMemory } from "./memory-cmd.js";
19
+ import { configFile } from "../paths.js";
20
+ import { render } from "./trace-cmd.js";
21
+ const DIM = "";
22
+ const RESET = "";
23
+ export async function runRepl(opts) {
24
+ const out = process.stdout;
25
+ const rl = createInterface({ input: process.stdin, output: out });
26
+ const dim = (text) => (out.isTTY ? `${DIM}${text}${RESET}` : text);
27
+ let session;
28
+ try {
29
+ session = open(opts, rl);
30
+ }
31
+ catch (err) {
32
+ out.write(`\n ${message(err)}\n\n`);
33
+ rl.close();
34
+ return 1;
35
+ }
36
+ banner(out, opts, session);
37
+ let lastRequestId = "";
38
+ for (;;) {
39
+ const line = (await rl.question("> ")).trim();
40
+ if (!line)
41
+ continue;
42
+ if (line.startsWith("/")) {
43
+ const [command = "", ...rest] = line.slice(1).split(/\s+/);
44
+ if (command === "exit" || command === "quit")
45
+ break;
46
+ try {
47
+ session = await handle(command, rest, session, opts, rl, out, lastRequestId);
48
+ }
49
+ catch (err) {
50
+ out.write(` ${message(err)}\n\n`);
51
+ }
52
+ continue;
53
+ }
54
+ const controller = new AbortController();
55
+ const interrupt = () => controller.abort();
56
+ rl.once("SIGINT", interrupt);
57
+ let streamed = false;
58
+ try {
59
+ const result = await session.ask(line, {
60
+ signal: controller.signal,
61
+ onRequest: (request) => {
62
+ lastRequestId = request.id;
63
+ out.write(dim(` · ${shortId(request.id)}\n`));
64
+ },
65
+ onRecall: (used) => out.write(dim(used ? " · checking memory\n" : " · no memory needed\n")),
66
+ onEvent: (event) => {
67
+ if (event.type === "delta") {
68
+ streamed = true;
69
+ out.write(event.text);
70
+ }
71
+ if (event.type === "tool_call")
72
+ out.write(dim(`${streamed ? "\n" : ""} · ${event.name}\n`));
73
+ if (event.type === "tool_result" && event.isError) {
74
+ out.write(dim(` ${event.output.split("\n")[0]}\n`));
75
+ }
76
+ },
77
+ });
78
+ // With streaming on, the text has already been printed as it arrived;
79
+ // printing `result.text` again would double every answer.
80
+ out.write(streamed ? "\n\n" : `${result.text}\n\n`);
81
+ }
82
+ catch (err) {
83
+ out.write(controller.signal.aborted ? " interrupted\n\n" : ` ${message(err)}\n\n`);
84
+ }
85
+ finally {
86
+ rl.off("SIGINT", interrupt);
87
+ }
88
+ }
89
+ session.close();
90
+ rl.close();
91
+ return 0;
92
+ }
93
+ function banner(out, opts, session) {
94
+ out.write(`\n ✓ ${opts.model}\n`);
95
+ out.write(opts.memory
96
+ ? " ✓ memory on — .vaan/memory/state.db, local only\n"
97
+ : " ✓ memory off for this session\n");
98
+ out.write(` ✓ sandbox ${opts.config.sandbox.name} — commands run inside ${opts.workspace}\n`);
99
+ out.write(opts.trace
100
+ ? " ✓ tracing on — .vaan/traces, one file per request\n"
101
+ : " ✓ tracing off for this session\n");
102
+ out.write(` ✓ tools — ${activeGroups(session.tools).join(", ")}\n`);
103
+ out.write(" ✓ skills — drop a SKILL.md in .vaan/skills/\n");
104
+ if (opts.yes)
105
+ out.write(" ! --yes: every permission is granted without asking\n");
106
+ for (const warning of session.warnings)
107
+ out.write(` ! ${warning}\n`);
108
+ const pending = readInbox(opts.workspace).length;
109
+ if (pending > 0)
110
+ out.write(` ! ${pending} item${pending === 1 ? "" : "s"} in /inbox\n`);
111
+ out.write("\n");
112
+ }
113
+ function open(opts, rl) {
114
+ return createSession({
115
+ workspace: opts.workspace,
116
+ model: opts.model,
117
+ config: opts.config,
118
+ memory: opts.memory,
119
+ yes: opts.yes,
120
+ trace: opts.trace,
121
+ stream: true,
122
+ env: opts.env,
123
+ // Whether. The gate calls this, and only a person can answer it.
124
+ approve: async (request, reason) => {
125
+ process.stdout.write(`\n Vaan wants to ${verb(request)}:\n\n ${request.target}\n\n`);
126
+ process.stdout.write(` Permission:\n ${request.capability.toUpperCase()}`);
127
+ process.stdout.write(request.detail ? ` — ${request.detail}\n\n` : `\n\n`);
128
+ process.stdout.write(` ${reason}\n\n`);
129
+ const answer = (await rl.question(" Allow? [y/N] ")).trim().toLowerCase();
130
+ process.stdout.write("\n");
131
+ return answer === "y" || answer === "yes";
132
+ },
133
+ // What. Every write stops here too: the path, the diff, and one keystroke.
134
+ confirm: async (details) => {
135
+ process.stdout.write(`\n${details}\n\n`);
136
+ const answer = (await rl.question(" Write it? [y/N] ")).trim().toLowerCase();
137
+ return answer === "y" || answer === "yes";
138
+ },
139
+ });
140
+ }
141
+ const verb = (request) => {
142
+ switch (request.capability) {
143
+ case "write":
144
+ return "modify";
145
+ case "execute":
146
+ case "destructive":
147
+ return "run";
148
+ case "network":
149
+ return "reach";
150
+ case "outside":
151
+ return "touch a path outside the workspace";
152
+ default:
153
+ return "access";
154
+ }
155
+ };
156
+ const HELP = `
157
+ /model [spec] show providers, or switch model
158
+ /new start a new conversation, keeping stored memory
159
+ /memory what's remembered
160
+ /forget [id] remove a fact
161
+ /inbox results from scheduled runs
162
+ /status workspace, permissions, tools, tokens
163
+ /trace [id] the last request in full, or one by id
164
+ /settings where to change things
165
+ /help this
166
+ /exit leave
167
+ `;
168
+ async function handle(command, args, session, opts, rl, out, lastRequestId) {
169
+ switch (command) {
170
+ case "model": {
171
+ if (args.length === 0) {
172
+ out.write(`\n using ${opts.model}\n\n`);
173
+ for (const spec of statuses(opts.env)) {
174
+ const key = spec.envKey
175
+ ? `${spec.envKey} ${spec.ready ? "set" : "missing"}`
176
+ : "no key needed";
177
+ out.write(` ${spec.name.padEnd(12)} ${spec.ready ? "✓" : " "} ${key}\n`);
178
+ }
179
+ out.write("\n /model <provider>/<name> to switch.\n\n");
180
+ return session;
181
+ }
182
+ const next = args[0];
183
+ const replacement = open({ ...opts, model: next }, rl);
184
+ session.close();
185
+ opts.model = next;
186
+ out.write(`\n ✓ ${next}\n\n`);
187
+ return replacement;
188
+ }
189
+ case "new":
190
+ session.reset();
191
+ out.write("\n New conversation. Facts and past turns are still remembered.\n\n");
192
+ return session;
193
+ case "memory":
194
+ printMemory(out, await session.memory.recall(opts.workspace, ""));
195
+ return session;
196
+ case "forget": {
197
+ const { facts } = await session.memory.recall(opts.workspace, "");
198
+ if (facts.length === 0) {
199
+ out.write("\n Nothing remembered yet.\n\n");
200
+ return session;
201
+ }
202
+ let id = Number(args[0]);
203
+ if (!Number.isInteger(id)) {
204
+ out.write("\n");
205
+ for (const fact of facts)
206
+ out.write(` ${String(fact.id).padStart(3)} ${fact.text}\n`);
207
+ id = Number((await rl.question("\n Forget which? ")).trim());
208
+ }
209
+ const removed = Number.isInteger(id) ? await session.memory.forget(opts.workspace, id) : 0;
210
+ out.write(removed > 0 ? ` forgot #${id}\n\n` : " no such fact\n\n");
211
+ return session;
212
+ }
213
+ case "inbox": {
214
+ const items = readInbox(opts.workspace);
215
+ if (items.length === 0) {
216
+ out.write("\n Nothing pending.\n\n");
217
+ return session;
218
+ }
219
+ out.write("\n inbox\n\n");
220
+ for (const item of items) {
221
+ out.write(` ${item.at.slice(0, 16).replace("T", " ")} ${item.kind}\n`);
222
+ out.write(` ${item.title}\n`);
223
+ out.write(` ${item.detail.split("\n")[0] ?? ""}\n`);
224
+ if (item.requestId)
225
+ out.write(` /trace ${shortId(item.requestId)}\n`);
226
+ out.write("\n");
227
+ }
228
+ if (args[0] === "clear")
229
+ out.write(` cleared ${clearInbox(opts.workspace)}\n\n`);
230
+ else
231
+ out.write(" /inbox clear to empty it.\n\n");
232
+ return session;
233
+ }
234
+ case "status": {
235
+ out.write("\n status\n\n");
236
+ for (const entry of describeConfig({ ...session.config, model: opts.model })) {
237
+ out.write(` ${entry}\n`);
238
+ }
239
+ out.write(` tokens ${session.usage.input} in / ${session.usage.output} out\n`);
240
+ out.write("\n tool groups\n\n");
241
+ const on = new Set(activeGroups(session.tools));
242
+ for (const group of GROUPS) {
243
+ const state = !group.available ? "not configured" : on.has(group.group) ? "on" : "off";
244
+ out.write(` ${group.label.padEnd(22)} ${state}\n`);
245
+ }
246
+ out.write("\n");
247
+ return session;
248
+ }
249
+ case "trace": {
250
+ const id = args[0] ?? lastRequestId;
251
+ if (!id) {
252
+ out.write("\n Nothing to show yet — ask something first.\n\n");
253
+ return session;
254
+ }
255
+ const { readTrace } = await import("../observability/trace.js");
256
+ const { home } = await import("../paths.js");
257
+ const trace = readTrace(home(opts.workspace), id);
258
+ out.write(trace ? render(trace) : `\n No trace matching "${id}".\n\n`);
259
+ return session;
260
+ }
261
+ case "settings":
262
+ out.write(`\n Settings live in files you can edit:\n\n`);
263
+ out.write(` ${configFile(opts.workspace)}\n model, tools, sandbox, approvals\n\n`);
264
+ out.write(` SOUL.md\n who the agent is\n\n`);
265
+ out.write(` GUARDRAILS.md\n what it should and shouldn't do\n\n`);
266
+ out.write(" Changes to SOUL.md and GUARDRAILS.md apply on the next message.\n");
267
+ out.write(" Config changes need a restart. `vaan init` walks through it again.\n\n");
268
+ return session;
269
+ default:
270
+ out.write(HELP);
271
+ return session;
272
+ }
273
+ }
274
+ const message = (err) => (err instanceof Error ? err.message : String(err));
275
+ //# sourceMappingURL=repl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repl.js","sourceRoot":"","sources":["../../../src/cli/repl.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,184 @@
1
+ // `vaan schedule` — recurring work, without a daemon.
2
+ //
3
+ // Two decisions worth stating, because both are deliberate.
4
+ //
5
+ // First, there is no Vaan service. A background process that holds your API key
6
+ // and can write to your project is a thing you have to trust around the clock;
7
+ // the operating system already has a scheduler you trust, so Vaan stores the
8
+ // task and hands you the one line that installs it. It runs when cron runs it,
9
+ // as you, and not otherwise.
10
+ //
11
+ // Second, Vaan does not install that line itself. Editing a crontab is a system
12
+ // change, and system changes are denied by fixed policy in
13
+ // src/permissions/rules.ts — including to the CLI. An agent that exempts itself
14
+ // from its own floor doesn't have a floor. So the command is printed and you
15
+ // run it.
16
+ //
17
+ // A scheduled run has nobody to ask for permission, so nothing that needs
18
+ // approval happens: it lands in the inbox instead, and `/inbox` shows it the
19
+ // next time you're at the keyboard.
20
+ import { randomUUID } from "node:crypto";
21
+ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
22
+ import { join } from "node:path";
23
+ import { createInterface } from "node:readline/promises";
24
+ import { loadConfig } from "../config.js";
25
+ import { addItem } from "../inbox.js";
26
+ import { createSession } from "../index.js";
27
+ import { shortId } from "../observability/request.js";
28
+ import { stateDir } from "../paths.js";
29
+ const file = (workspace) => join(stateDir(workspace), "schedules.json");
30
+ export function readSchedules(workspace) {
31
+ try {
32
+ const parsed = JSON.parse(readFileSync(file(workspace), "utf8"));
33
+ return Array.isArray(parsed) ? parsed.filter(isSchedule) : [];
34
+ }
35
+ catch {
36
+ return [];
37
+ }
38
+ }
39
+ export function writeSchedules(workspace, schedules) {
40
+ mkdirSync(stateDir(workspace), { recursive: true });
41
+ writeFileSync(file(workspace), `${JSON.stringify(schedules, null, 2)}\n`, "utf8");
42
+ }
43
+ const isSchedule = (value) => typeof value === "object" &&
44
+ value !== null &&
45
+ typeof value.id === "string" &&
46
+ typeof value.prompt === "string";
47
+ /** The line the user runs to hand this to their own scheduler. */
48
+ export function installCommand(workspace, schedule) {
49
+ if (process.platform === "win32") {
50
+ const [minute = "0", hour = "9"] = schedule.cron.split(" ");
51
+ return (`schtasks /create /tn "vaan-${schedule.name}" /tr ` +
52
+ `"cmd /c cd /d ${workspace} && vaan schedule run ${shortId(schedule.id)}" ` +
53
+ `/sc daily /st ${hour.padStart(2, "0")}:${minute.padStart(2, "0")}`);
54
+ }
55
+ return `${schedule.cron} cd ${workspace} && vaan schedule run ${shortId(schedule.id)}`;
56
+ }
57
+ export function printSchedules(out, workspace) {
58
+ const schedules = readSchedules(workspace);
59
+ if (schedules.length === 0) {
60
+ out.write("\n Nothing scheduled.\n\n vaan schedule add to create one.\n\n");
61
+ return 0;
62
+ }
63
+ out.write("\n scheduled\n\n");
64
+ for (const schedule of schedules) {
65
+ out.write(` ${shortId(schedule.id)} ${schedule.cron.padEnd(16)} ${schedule.name}\n`);
66
+ out.write(` ${clip(schedule.prompt, 68)}\n`);
67
+ out.write(` last run ${schedule.lastRunAt ? schedule.lastRunAt.slice(0, 16).replace("T", " ") : "never"}\n\n`);
68
+ }
69
+ out.write(" vaan schedule run <id> run one now\n");
70
+ out.write(" vaan schedule remove <id> forget it\n\n");
71
+ return 0;
72
+ }
73
+ export async function addSchedule(out, workspace) {
74
+ if (!process.stdin.isTTY) {
75
+ out.write("\n Adding a schedule needs a terminal.\n\n");
76
+ return 1;
77
+ }
78
+ const rl = createInterface({ input: process.stdin, output: out });
79
+ try {
80
+ const name = (await rl.question("\n A short name ? ")).trim().replace(/\s+/g, "-");
81
+ if (!name)
82
+ return leave(out, "No name, no schedule.");
83
+ const prompt = (await rl.question("\n What should Vaan do?\n\n ? ")).trim();
84
+ if (!prompt)
85
+ return leave(out, "No task, no schedule.");
86
+ out.write("\n When? cron, five fields\n\n");
87
+ out.write(" 0 9 * * 1-5 weekdays at 09:00\n");
88
+ out.write(" 0 * * * * hourly\n");
89
+ out.write(" 30 18 * * 5 Fridays at 18:30\n\n");
90
+ const cron = (await rl.question(" ? ")).trim() || "0 9 * * 1-5";
91
+ if (cron.split(/\s+/).length !== 5)
92
+ return leave(out, "That isn't five cron fields.");
93
+ const schedule = {
94
+ id: randomUUID(),
95
+ name,
96
+ prompt,
97
+ cron,
98
+ createdAt: new Date().toISOString(),
99
+ };
100
+ writeSchedules(workspace, [...readSchedules(workspace), schedule]);
101
+ out.write(`\n Saved as ${shortId(schedule.id)}.\n\n`);
102
+ out.write(" Vaan doesn't install this itself — editing a scheduler is a system change,\n");
103
+ out.write(" and those are denied by fixed policy. Add it yourself:\n\n");
104
+ out.write(process.platform === "win32"
105
+ ? ` ${installCommand(workspace, schedule)}\n\n`
106
+ : ` crontab -e\n\n ${installCommand(workspace, schedule)}\n\n`);
107
+ return 0;
108
+ }
109
+ finally {
110
+ rl.close();
111
+ }
112
+ }
113
+ export function removeSchedule(out, workspace, query) {
114
+ const schedules = readSchedules(workspace);
115
+ const remaining = schedules.filter((entry) => !entry.id.startsWith(query.toLowerCase()));
116
+ if (remaining.length === schedules.length) {
117
+ out.write(`\n No schedule matching "${query}".\n\n`);
118
+ return 1;
119
+ }
120
+ writeSchedules(workspace, remaining);
121
+ out.write(`\n Removed ${schedules.length - remaining.length}.\n\n`);
122
+ return 0;
123
+ }
124
+ /** Run one schedule now. Nothing interactive: the result goes to the inbox. */
125
+ export async function runSchedule(out, query, opts) {
126
+ const schedules = readSchedules(opts.workspace);
127
+ const schedule = schedules.find((entry) => entry.id.startsWith(query.toLowerCase()));
128
+ if (!schedule) {
129
+ out.write(`\n No schedule matching "${query}".\n\n`);
130
+ return 1;
131
+ }
132
+ const config = loadConfig(opts.workspace);
133
+ const session = createSession({
134
+ workspace: opts.workspace,
135
+ model: opts.model,
136
+ ...(config ? { config } : {}),
137
+ env: opts.env,
138
+ yes: opts.yes,
139
+ });
140
+ // Without `--yes` there is nobody to approve anything, so the gate refuses
141
+ // and the model is told so. That is the safe default for unattended work.
142
+ let blocked = false;
143
+ try {
144
+ const result = await session.ask(schedule.prompt, {
145
+ onEvent: (event) => {
146
+ if (event.type === "tool_result" && event.isError && /Not permitted/.test(event.output)) {
147
+ blocked = true;
148
+ }
149
+ },
150
+ });
151
+ schedule.lastRunAt = new Date().toISOString();
152
+ writeSchedules(opts.workspace, schedules);
153
+ addItem(opts.workspace, {
154
+ kind: blocked ? "needs-approval" : "scheduled",
155
+ title: `${schedule.name} ran`,
156
+ detail: result.text,
157
+ requestId: result.requestId,
158
+ });
159
+ out.write(`\n ${schedule.name}: ${result.requestId}\n\n${result.text}\n\n`);
160
+ return 0;
161
+ }
162
+ catch (err) {
163
+ const detail = err instanceof Error ? err.message : String(err);
164
+ addItem(opts.workspace, {
165
+ kind: "failed",
166
+ title: `${schedule.name} failed`,
167
+ detail,
168
+ });
169
+ out.write(`\n ${schedule.name} failed: ${detail}\n\n`);
170
+ return 1;
171
+ }
172
+ finally {
173
+ session.close();
174
+ }
175
+ }
176
+ function leave(out, message) {
177
+ out.write(`\n ${message}\n\n`);
178
+ return 1;
179
+ }
180
+ const clip = (text, max) => {
181
+ const line = text.replace(/\s+/g, " ").trim();
182
+ return line.length <= max ? line : `${line.slice(0, max)}…`;
183
+ };
184
+ //# sourceMappingURL=schedule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schedule.js","sourceRoot":"","sources":["../../../src/cli/schedule.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ // The only file in Vaan that knows any model names.
2
+ //
3
+ // These are shortcuts for the onboarding, not an allowlist — it accepts any
4
+ // string you type and passes it straight through. That means a stale entry here
5
+ // is cosmetic: when a new model ships, typing its name works on day one whether
6
+ // or not this list has caught up.
7
+ export const SUGGESTED = [
8
+ { spec: "anthropic/claude-opus-5", note: "most capable" },
9
+ { spec: "anthropic/claude-sonnet-5", note: "faster, cheaper" },
10
+ { spec: "anthropic/claude-haiku-4-5", note: "cheapest" },
11
+ { spec: "openai/gpt-5", note: "" },
12
+ { spec: "openai/gpt-5-mini", note: "faster, cheaper" },
13
+ { spec: "google/gemini-2.5-pro", note: "" },
14
+ { spec: "ollama/qwen3:8b", note: "local, no key" },
15
+ ];
16
+ /** What `--yes` picks when a provider's key is present but no model was named. */
17
+ export const DEFAULT_MODEL = {
18
+ anthropic: "anthropic/claude-opus-5",
19
+ openai: "openai/gpt-5",
20
+ google: "google/gemini-2.5-pro",
21
+ ollama: "ollama/qwen3:8b",
22
+ groq: "groq/llama-3.3-70b-versatile",
23
+ };
24
+ /** The last option in the model list, which asks for a shape and a URL instead. */
25
+ export const CUSTOM_NOTE = "your own endpoint";
26
+ //# sourceMappingURL=suggested.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suggested.js","sourceRoot":"","sources":["../../../src/cli/suggested.ts"],"names":[],"mappings":"AAAA,oDAAoD;AACpD,EAAE;AACF,4EAA4E;AAC5E,gFAAgF;AAChF,gFAAgF;AAChF,kCAAkC;AAQlC,MAAM,CAAC,MAAM,SAAS,GAAsB;IAC1C,EAAE,IAAI,EAAE,yBAAyB,EAAE,IAAI,EAAE,cAAc,EAAE;IACzD,EAAE,IAAI,EAAE,2BAA2B,EAAE,IAAI,EAAE,iBAAiB,EAAE;IAC9D,EAAE,IAAI,EAAE,4BAA4B,EAAE,IAAI,EAAE,UAAU,EAAE;IACxD,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,EAAE,EAAE;IAClC,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,iBAAiB,EAAE;IACtD,EAAE,IAAI,EAAE,uBAAuB,EAAE,IAAI,EAAE,EAAE,EAAE;IAC3C,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,eAAe,EAAE;CACnD,CAAC;AAEF,kFAAkF;AAClF,MAAM,CAAC,MAAM,aAAa,GAA2B;IACnD,SAAS,EAAE,yBAAyB;IACpC,MAAM,EAAE,cAAc;IACtB,MAAM,EAAE,uBAAuB;IAC/B,MAAM,EAAE,iBAAiB;IACzB,IAAI,EAAE,8BAA8B;CACrC,CAAC;AAEF,mFAAmF;AACnF,MAAM,CAAC,MAAM,WAAW,GAAG,mBAAmB,CAAC"}
@@ -0,0 +1,69 @@
1
+ // `vaan trace` — the listing, and one request in full.
2
+ //
3
+ // The claim in the README is that every request is understandable after the
4
+ // fact: what it received, what it decided, which tools it used, what was
5
+ // allowed, what ran in the sandbox, what happened. This is where that claim is
6
+ // either true or it isn't, so the printer shows every event rather than a
7
+ // curated summary.
8
+ import { describeEvent, listTraces, readTrace } from "../observability/trace.js";
9
+ import { shortId } from "../observability/request.js";
10
+ import { home } from "../paths.js";
11
+ export function printTraceList(out, workspace, limit = 20) {
12
+ const traces = listTraces(home(workspace), limit);
13
+ if (traces.length === 0) {
14
+ out.write("\n No traces yet. They're written to .vaan/traces after each request.\n\n");
15
+ return 0;
16
+ }
17
+ out.write("\n recent requests\n\n");
18
+ for (const trace of traces) {
19
+ out.write(` ${shortId(trace.id)} ${trace.at.slice(0, 16).replace("T", " ")} ` +
20
+ `${trace.ok ? "ok " : "FAIL"} ${(trace.durationMs / 1000).toFixed(1)}s ` +
21
+ `${clip(trace.input, 48)}\n`);
22
+ }
23
+ out.write("\n vaan trace <id> for one in full.\n\n");
24
+ return 0;
25
+ }
26
+ export function printTrace(out, workspace, query) {
27
+ const trace = readTrace(home(workspace), query);
28
+ if (!trace) {
29
+ out.write(`\n No trace matching "${query}".\n\n`);
30
+ return 1;
31
+ }
32
+ out.write(render(trace));
33
+ return 0;
34
+ }
35
+ export function render(trace) {
36
+ const lines = [
37
+ "",
38
+ ` Request ID: ${trace.id}`,
39
+ ` When: ${trace.at}`,
40
+ ` Model: ${trace.model}`,
41
+ ` Workspace: ${trace.workspace}`,
42
+ "",
43
+ ` Request: ${clip(trace.input, 200)}`,
44
+ "",
45
+ " Steps",
46
+ "",
47
+ ];
48
+ for (const event of trace.events) {
49
+ lines.push(` ${pad(event.ms)} ${describeEvent(event)}`);
50
+ }
51
+ const permissions = trace.events.filter((event) => event.kind === "permission");
52
+ if (permissions.length > 0) {
53
+ lines.push("", " Permissions", "");
54
+ for (const event of permissions) {
55
+ if (event.kind !== "permission")
56
+ continue;
57
+ lines.push(` ${event.decision === "allow" ? "✓" : "✗"} ${event.capability.padEnd(12)}` +
58
+ `${clip(event.target, 44)}\n ${event.reason}`);
59
+ }
60
+ }
61
+ lines.push("", " Timing", "", ` Total: ${(trace.durationMs / 1000).toFixed(2)}s`, "", ` Result: ${trace.ok ? "ok" : "failed"}`, ` ${clip(trace.summary, 200)}`, "");
62
+ return lines.join("\n");
63
+ }
64
+ const pad = (ms) => `${(ms / 1000).toFixed(2)}s`.padStart(7);
65
+ const clip = (text, max) => {
66
+ const line = text.replace(/\s+/g, " ").trim();
67
+ return line.length <= max ? line : `${line.slice(0, max)}…`;
68
+ };
69
+ //# sourceMappingURL=trace-cmd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-cmd.js","sourceRoot":"","sources":["../../../src/cli/trace-cmd.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,EAAE;AACF,4EAA4E;AAC5E,yEAAyE;AACzE,+EAA+E;AAC/E,0EAA0E;AAC1E,mBAAmB;AAEnB,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAoB,MAAM,2BAA2B,CAAC;AACnG,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AACtD,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEnC,MAAM,UAAU,cAAc,CAAC,GAAuB,EAAE,SAAiB,EAAE,KAAK,GAAG,EAAE;IACnF,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,CAAC,CAAC;IAClD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,GAAG,CAAC,KAAK,CAAC,4EAA4E,CAAC,CAAC;QACxF,OAAO,CAAC,CAAC;IACX,CAAC;IAED,GAAG,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;IACrC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,GAAG,CAAC,KAAK,CACP,OAAO,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI;YACtE,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK;YAC3E,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAC/B,CAAC;IACJ,CAAC;IACD,GAAG,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;IACtD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,GAAuB,EAAE,SAAiB,EAAE,KAAa;IAClF,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,CAAC,CAAC;IAChD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,GAAG,CAAC,KAAK,CAAC,0BAA0B,KAAK,QAAQ,CAAC,CAAC;QACnD,OAAO,CAAC,CAAC;IACX,CAAC;IACD,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACzB,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,KAAkB;IACvC,MAAM,KAAK,GAAa;QACtB,EAAE;QACF,kBAAkB,KAAK,CAAC,EAAE,EAAE;QAC5B,kBAAkB,KAAK,CAAC,EAAE,EAAE;QAC5B,kBAAkB,KAAK,CAAC,KAAK,EAAE;QAC/B,kBAAkB,KAAK,CAAC,SAAS,EAAE;QACnC,EAAE;QACF,kBAAkB,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE;QAC1C,EAAE;QACF,SAAS;QACT,EAAE;KACH,CAAC;IAEF,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC;IAChF,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3B,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,eAAe,EAAE,EAAE,CAAC,CAAC;QACpC,KAAK,MAAM,KAAK,IAAI,WAAW,EAAE,CAAC;YAChC,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY;gBAAE,SAAS;YAC1C,KAAK,CAAC,IAAI,CACR,OAAO,KAAK,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE;gBAC5E,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,WAAW,KAAK,CAAC,MAAM,EAAE,CACrD,CAAC;QACJ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAI,CACR,EAAE,EACF,UAAU,EACV,EAAE,EACF,cAAc,CAAC,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EACrD,EAAE,EACF,aAAa,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,EACzC,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,EACjC,EAAE,CACH,CAAC;IACF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,GAAG,GAAG,CAAC,EAAU,EAAU,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAE7E,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,GAAW,EAAU,EAAE;IACjD,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9C,OAAO,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC;AAC9D,CAAC,CAAC"}