@alisio/alisio-code 0.1.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js ADDED
@@ -0,0 +1,476 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ const VERSION = "0.1.0-alpha.1";
4
+ function parseAgents(json) {
5
+ const value = JSON.parse(json);
6
+ if (!value || typeof value !== "object" || Array.isArray(value))
7
+ throw new Error('--agents expects a JSON object: {"name":{"description":"...","prompt":"..."}}');
8
+ return value;
9
+ }
10
+ /** Built-in plugins and prompt templates, and the slash names templates may not take. */
11
+ async function cliDefaults() {
12
+ const [{ BUILTIN_PLUGINS }, { BUILTIN_PROMPTS }, { reservedCommandNames }] = await Promise.all([
13
+ import("./builtin.js"),
14
+ import("./prompts/index.js"),
15
+ import("./tui/state.js"),
16
+ ]);
17
+ return {
18
+ builtins: BUILTIN_PLUGINS,
19
+ builtinPrompts: BUILTIN_PROMPTS,
20
+ reservedPromptNames: reservedCommandNames(),
21
+ };
22
+ }
23
+ const program = new Command();
24
+ program
25
+ .name("alisio")
26
+ .description("Velocidad y eficiencia para construir — extensible coding harness")
27
+ .version("0.1.0-alpha.1")
28
+ .option("--cwd <path>", "Working directory")
29
+ .option("--config <path>", "Explicit trusted configuration file")
30
+ .option("--trust-project", "Load project config and executable plugins (full process privileges)")
31
+ .option("--plugin <path...>", "Load explicitly trusted local plugins")
32
+ .option("--model <id>", "Provider model ID")
33
+ .option("--base-url <url>", "OpenAI-compatible API base URL, including /v1 if needed")
34
+ .option("--api-mode <mode>", "chat or responses")
35
+ .option("--allow-write", "Allow file writes")
36
+ .option("--allow-process", "Allow arbitrary subprocesses; not sandboxed")
37
+ .option("--allow-external", "Allow network tools: webfetch, websearch and provider-native search")
38
+ .option("--allow-mcp", "Allow configured MCP servers and remote tool calls")
39
+ .option("--allow-agents", "Allow messaging neighboring agents through Herdr")
40
+ .option("--no-herdr", "Disable automatic Herdr lifecycle reports")
41
+ .option("--read-only", "Disable writes, arbitrary processes, network tools, executable plugins and MCP")
42
+ .option("--db <path>", "Session database")
43
+ .option("--json", "Emit versioned JSONL events")
44
+ .option("--no-tui", "Use the plain readline interactive mode instead of the TUI")
45
+ .option("--disable-plugin <ids...>", "Disable built-in plugins (for example: memory)")
46
+ .option("--no-banner", "Do not show the startup screen")
47
+ .option("--agents <json>", 'Extra subagent definitions as JSON: {"name":{"description":"...","prompt":"..."}}')
48
+ .option("--quiet", "Suppress non-essential output (startup screen, hints)");
49
+ const options = (cmd) => {
50
+ const o = cmd.optsWithGlobals();
51
+ return {
52
+ ...o,
53
+ baseURL: o.baseUrl,
54
+ noHerdr: o.herdr === false,
55
+ disablePlugins: o.disablePlugin,
56
+ ...(o.agents
57
+ ? { pluginOptions: { subagents: { agents: parseAgents(String(o.agents)) } } }
58
+ : {}),
59
+ };
60
+ };
61
+ /**
62
+ * A one-time, plain (pre-alt-screen) yes/no prompt. It must run before the TUI (and before
63
+ * `createApplication`, which is what actually reads `.alisio/config.json`) exists, since the
64
+ * decision made here controls whether that read happens at all — the TUI's own interactive
65
+ * question queue is built from an already-created Application, too late for this.
66
+ */
67
+ async function promptTrust(workspace) {
68
+ const { createInterface } = await import("node:readline/promises");
69
+ process.stderr.write(`\nThis directory has Alisio project configuration: ${workspace}\n` +
70
+ "Trusting it lets Alisio load that configuration for this and future runs — including a " +
71
+ "possibly different provider endpoint or API key — plus its plugins, agents, skills and " +
72
+ "prompt templates. Declining uses Alisio's own defaults instead; nothing here is read.\n");
73
+ const rl = createInterface({ input: process.stdin, output: process.stderr });
74
+ try {
75
+ const answer = (await rl.question("Trust this project's Alisio configuration? [y/N] "))
76
+ .trim()
77
+ .toLowerCase();
78
+ return answer === "y" || answer === "yes";
79
+ }
80
+ finally {
81
+ rl.close();
82
+ }
83
+ }
84
+ /**
85
+ * Resolves the effective `trustProject` for an interactive TUI run: an explicit
86
+ * `--trust-project`/`--config` is untouched (that is already one-run, explicit trust, never
87
+ * persisted here as though it were an interactive grant). Otherwise, a workspace with project
88
+ * resources to trust gets a one-time prompt (re-asked only when `.alisio/config.json` changes),
89
+ * persisted in the trust store; a workspace with nothing to trust is never prompted at all.
90
+ */
91
+ async function withProjectTrust(opts) {
92
+ if (opts.trustProject || opts.config)
93
+ return opts;
94
+ const { findWorkspace, resolveTrust, setTrust } = await import("@alisio/core");
95
+ const workspace = await findWorkspace(opts.cwd ?? process.cwd());
96
+ const resolution = await resolveTrust(workspace);
97
+ if (!resolution.hasProjectResources)
98
+ return opts;
99
+ if (!resolution.needsPrompt)
100
+ return { ...opts, trustProject: resolution.trusted };
101
+ const trusted = await promptTrust(workspace);
102
+ await setTrust(workspace, trusted, resolution.configHash);
103
+ return { ...opts, trustProject: trusted };
104
+ }
105
+ async function run(cmd, prompt, sessionId) {
106
+ const opts = options(cmd);
107
+ if (!prompt &&
108
+ !opts.json &&
109
+ opts.tui !== false &&
110
+ process.stdin.isTTY &&
111
+ process.stdout.isTTY) {
112
+ const { runTui } = await import("./tui/app.js");
113
+ const trusted = await withProjectTrust(opts);
114
+ return runTui({ ...trusted, ...(sessionId ? { session: sessionId } : {}) });
115
+ }
116
+ const { createApplication } = await import("@alisio/core");
117
+ const app = await createApplication({
118
+ ...(await cliDefaults()),
119
+ ...opts,
120
+ onEvent: (event) => {
121
+ if (opts.json)
122
+ process.stdout.write(`${JSON.stringify(event)}\n`);
123
+ else if (event.type === "text_delta")
124
+ process.stdout.write(String(event.data.delta));
125
+ else if (event.type === "tool_started")
126
+ process.stderr.write(`\n→ ${event.data.name}\n`);
127
+ },
128
+ });
129
+ const controller = new AbortController();
130
+ const interrupt = () => controller.abort(new Error("Interrupted"));
131
+ process.on("SIGINT", interrupt);
132
+ // `/name args` runs a prompt template (same syntax as the TUI); refuse before creating a session.
133
+ let template;
134
+ try {
135
+ template = prompt ? app.expandPrompt(prompt) : undefined;
136
+ }
137
+ catch (error) {
138
+ await app.close();
139
+ throw error;
140
+ }
141
+ let session = sessionId ?? app.store.create(app.workspace, app.provider.id, app.provider.model).id;
142
+ try {
143
+ // Sessions record their model; an explicit --model switches it for the next turns.
144
+ if (sessionId && opts.model && app.store.get(session).model !== opts.model)
145
+ app.runner.setModel(session, opts.model);
146
+ await app.herdr.report("idle", session);
147
+ if (prompt) {
148
+ const match = /^\/skill:([a-z0-9-]+)\s*([\s\S]*)$/.exec(prompt);
149
+ if (match?.[1])
150
+ prompt = `${await app.skills.load(match[1])}\n\nUser request: ${match[2] ?? ""}`;
151
+ await app.runner.run(session, template?.text ?? prompt, controller.signal, template ? { display: template.display } : {});
152
+ if (!opts.json)
153
+ process.stdout.write(`\nSession: ${session}\n`);
154
+ return;
155
+ }
156
+ if (opts.json || !process.stdin.isTTY)
157
+ throw new Error("Provide a prompt with run, or use an interactive terminal");
158
+ const { createInterface } = await import("node:readline/promises");
159
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
160
+ rl.on("SIGINT", interrupt);
161
+ controller.signal.addEventListener("abort", () => rl.close(), { once: true });
162
+ const { bannerPolicy, startupInput, terminalCapabilities } = await import("./banner.js");
163
+ if (bannerPolicy({
164
+ mode: "readline",
165
+ ...opts,
166
+ stdoutTTY: !!process.stdout.isTTY,
167
+ stderrTTY: !!process.stderr.isTTY,
168
+ env: process.env,
169
+ })) {
170
+ const { renderStartup } = await import("@alisio/core");
171
+ const terminal = terminalCapabilities({
172
+ env: process.env,
173
+ columns: process.stderr.columns ?? 80,
174
+ tty: true,
175
+ });
176
+ const banner = renderStartup(app.plugins, startupInput(app, { version: VERSION, readOnly: !!opts.readOnly, terminal }));
177
+ process.stderr.write(`${banner.lines.join("\n")}\n`);
178
+ for (const d of banner.diagnostics)
179
+ process.stderr.write(`[startup] ${JSON.stringify(d)}\n`);
180
+ }
181
+ if (!opts.quiet)
182
+ console.log("Alisio · /exit /new /skill:name /command plugin.id:name args");
183
+ process.stdout.write("\nalisio › ");
184
+ try {
185
+ for await (const rawLine of rl) {
186
+ if (controller.signal.aborted)
187
+ break;
188
+ const line = rawLine.trim();
189
+ if (!line)
190
+ continue;
191
+ if (line === "/exit")
192
+ break;
193
+ if (line === "/new") {
194
+ session = app.store.create(app.workspace, app.provider.id, app.provider.model).id;
195
+ await app.herdr.report("idle", session);
196
+ process.stdout.write("\nalisio › ");
197
+ continue;
198
+ }
199
+ if (line.startsWith("/command ")) {
200
+ const [name, ...args] = line.slice(9).split(" ");
201
+ const handler = app.plugins.commands.get(name ?? "");
202
+ if (!handler)
203
+ throw new Error("Unknown plugin command");
204
+ console.log(await handler(args.join(" ")));
205
+ continue;
206
+ }
207
+ const match = /^\/skill:([a-z0-9-]+)\s*([\s\S]*)$/.exec(line);
208
+ const input = match?.[1] ? `${await app.skills.load(match[1])}\n\n${match[2] ?? ""}` : line;
209
+ try {
210
+ const template = app.expandPrompt(input);
211
+ await app.runner.run(session, template?.text ?? input, controller.signal, template ? { display: template.display } : {});
212
+ }
213
+ catch (e) {
214
+ console.error(String(e));
215
+ }
216
+ process.stdout.write("\nalisio › ");
217
+ }
218
+ }
219
+ finally {
220
+ rl.close();
221
+ }
222
+ }
223
+ finally {
224
+ process.off("SIGINT", interrupt);
225
+ await app.close();
226
+ }
227
+ }
228
+ program
229
+ .command("run")
230
+ .description('Run one prompt headless; "/name args" runs a prompt template (e.g. "/init")')
231
+ .argument("<prompt>")
232
+ .action((prompt, _options, cmd) => run(cmd, prompt));
233
+ program
234
+ .command("resume")
235
+ .argument("<session>")
236
+ .argument("[prompt]")
237
+ .action((id, prompt, _opts, cmd) => run(cmd, prompt, id));
238
+ program.action((_opts, cmd) => run(cmd));
239
+ program
240
+ .command("setup")
241
+ .description("Write an example configuration without secrets (for AGENTS.md use /init)")
242
+ .action(async (_opts, cmd) => {
243
+ const { resolve, join } = await import("node:path");
244
+ const { mkdir, writeFile } = await import("node:fs/promises");
245
+ const { exists } = await import("@alisio/core");
246
+ const path = join(resolve(options(cmd).cwd ?? process.cwd()), ".alisio", "config.json");
247
+ if (await exists(path))
248
+ throw new Error(`Configuration exists: ${path}`);
249
+ await mkdir(join(path, ".."), { recursive: true });
250
+ await writeFile(path, `${JSON.stringify({ schemaVersion: 1, provider: { baseURL: "https://api.openai.com/v1", apiKeyEnv: "OPENAI_API_KEY", model: "YOUR_MODEL_ID", apiMode: "chat", auth: "bearer", tokenParameter: "max_tokens", streamUsage: false }, plugins: [], skills: [], mcp: { servers: {} } }, null, 2)}\n`);
251
+ console.log(`Created ${path}. Set your model, endpoint and environment key. Use --config ${path}.`);
252
+ console.log('To generate AGENTS.md for this project, run /init inside alisio (or: alisio run "/init" --allow-write).');
253
+ });
254
+ program.command("doctor").action(async (_opts, cmd) => {
255
+ const { findWorkspace, loadConfigWithProvenance, overridesSavedProviderProfile, ProviderSettingsStore, which, } = await import("@alisio/core");
256
+ const o = options(cmd);
257
+ const workspace = await findWorkspace(o.cwd ?? process.cwd());
258
+ const { config, provenance } = await loadConfigWithProvenance(workspace, {
259
+ file: o.config,
260
+ trustProject: o.trustProject,
261
+ model: o.model,
262
+ baseURL: o.baseURL,
263
+ apiMode: o.apiMode,
264
+ });
265
+ const saved = await new ProviderSettingsStore().active();
266
+ const useSaved = !!saved &&
267
+ !overridesSavedProviderProfile(provenance, !!o.baseURL || !!o.apiMode || !!process.env.OPENAI_BASE_URL || !!process.env.ALISIO_API_MODE);
268
+ const model = o.model?.trim() ||
269
+ process.env.ALISIO_MODEL?.trim() ||
270
+ (useSaved ? saved.profile.model : config.provider.model);
271
+ const status = {
272
+ version: "0.1.0-alpha.1",
273
+ runtime: process.versions.bun ? `bun ${process.versions.bun}` : `node ${process.versions.node}`,
274
+ platform: process.platform,
275
+ workspace,
276
+ git: (await which("git")) ?? null,
277
+ ripgrep: (await which("rg")) ?? null,
278
+ provider: {
279
+ id: useSaved ? saved.profile.provider : "openai-compatible",
280
+ baseURL: useSaved ? saved.profile.values.baseURL : config.provider.baseURL,
281
+ apiMode: useSaved ? saved.profile.values.apiMode : config.provider.apiMode,
282
+ model: !model
283
+ ? "not configured"
284
+ : model === "YOUR_MODEL_ID"
285
+ ? "not configured (placeholder from `alisio setup` — edit .alisio/config.json)"
286
+ : model,
287
+ auth: useSaved ? saved.profile.values.auth : config.provider.auth,
288
+ keyConfigured: useSaved
289
+ ? !!saved.credentials.apiKey || saved.profile.values.auth === "none"
290
+ : config.provider.auth === "none" || !!process.env[config.provider.apiKeyEnv],
291
+ },
292
+ };
293
+ console.log(JSON.stringify(status, null, 2));
294
+ if (!model || model === "YOUR_MODEL_ID")
295
+ console.error("\nNo model configured yet: set provider.model in your config, --model, or ALISIO_MODEL " +
296
+ "before starting a real conversation (it will otherwise fail on the first turn).");
297
+ });
298
+ const trust = program.command("trust").description("Inspect or revoke per-directory project trust");
299
+ trust.command("list").action(async () => {
300
+ const { listTrust } = await import("@alisio/core");
301
+ console.log(JSON.stringify(await listTrust(), null, 2));
302
+ });
303
+ trust
304
+ .command("revoke")
305
+ .argument("<path>")
306
+ .description("Revoke a workspace's stored trust decision (re-prompts next time)")
307
+ .action(async (path) => {
308
+ const { revokeTrust } = await import("@alisio/core");
309
+ const { resolve } = await import("node:path");
310
+ const { realpath } = await import("node:fs/promises");
311
+ const workspace = await realpath(resolve(path)).catch(() => resolve(path));
312
+ const removed = await revokeTrust(workspace);
313
+ console.log(removed ? `Revoked trust for ${workspace}` : `No stored trust decision for ${workspace}`);
314
+ });
315
+ const sessions = program.command("sessions");
316
+ async function openStore(cmd) {
317
+ const { SQLiteStore } = await import("@alisio/core");
318
+ const { stateHome } = await import("@alisio/core");
319
+ const { join } = await import("node:path");
320
+ return new SQLiteStore(options(cmd).db ?? join(stateHome(), "sessions.sqlite"));
321
+ }
322
+ sessions.command("list").action(async (_opts, cmd) => {
323
+ const store = await openStore(cmd);
324
+ try {
325
+ console.log(JSON.stringify(store.list(), null, 2));
326
+ }
327
+ finally {
328
+ store.close();
329
+ }
330
+ });
331
+ sessions
332
+ .command("recover")
333
+ .argument("<session>")
334
+ .requiredOption("--acknowledge", "Acknowledge uncertain effects after inspecting the workspace")
335
+ .action(async (id, _opts, cmd) => {
336
+ const store = await openStore(cmd);
337
+ try {
338
+ store.acquire(id);
339
+ try {
340
+ store.reconcile(id, true);
341
+ }
342
+ finally {
343
+ store.release(id);
344
+ }
345
+ console.log("Session recovered. Uncertain operations were not replayed.");
346
+ }
347
+ finally {
348
+ store.close();
349
+ }
350
+ });
351
+ program
352
+ .command("context")
353
+ .command("explain")
354
+ .argument("<path>")
355
+ .action(async (path, _opts, cmd) => {
356
+ const { ProjectContext } = await import("@alisio/core");
357
+ const { findWorkspace } = await import("@alisio/core");
358
+ const { resolve } = await import("node:path");
359
+ const cwd = resolve(options(cmd).cwd ?? process.cwd());
360
+ const root = await findWorkspace(cwd);
361
+ console.log(JSON.stringify(await new ProjectContext(root).explain(resolve(cwd, path)), null, 2));
362
+ });
363
+ const skills = program.command("skills");
364
+ for (const name of ["list", "validate"]) {
365
+ skills
366
+ .command(name)
367
+ .argument("[path]")
368
+ .action(async (path, _opts, cmd) => {
369
+ const { Skills, configHome, findWorkspace, loadConfig, skillRoots } = await import("@alisio/core");
370
+ const { resolve } = await import("node:path");
371
+ const { homedir } = await import("node:os");
372
+ const o = options(cmd), cwd = resolve(o.cwd ?? process.cwd()), root = await findWorkspace(cwd);
373
+ const config = await loadConfig(root, { file: o.config, trustProject: o.trustProject });
374
+ const roots = skillRoots({
375
+ workspace: root,
376
+ cwd,
377
+ home: homedir(),
378
+ configHome: configHome(),
379
+ trusted: !!o.trustProject || !!o.config,
380
+ configSkills: config.skills,
381
+ });
382
+ const catalog = new Skills({ overrides: path ? {} : config.skillOverrides });
383
+ await catalog.discover(path ? [resolve(cwd, path)] : roots);
384
+ console.log(JSON.stringify({ skills: [...catalog.items.values()], diagnostics: catalog.diagnostics }, null, 2));
385
+ if (name === "validate" && catalog.diagnostics.length)
386
+ process.exitCode = 1;
387
+ });
388
+ }
389
+ const plugins = program.command("plugins");
390
+ plugins.command("list").action(async (_opts, cmd) => {
391
+ const { discoverPlugins } = await import("@alisio/core");
392
+ const { configHome } = await import("@alisio/core");
393
+ const { join, resolve } = await import("node:path");
394
+ console.log(JSON.stringify({
395
+ global: await discoverPlugins(join(configHome(), "plugins")),
396
+ project: await discoverPlugins(join(resolve(options(cmd).cwd ?? process.cwd()), ".alisio", "plugins")),
397
+ explicit: options(cmd).plugin ?? [],
398
+ }, null, 2));
399
+ });
400
+ plugins.command("doctor").action(async (_opts, cmd) => {
401
+ const { createApplication } = await import("@alisio/core");
402
+ const app = await createApplication({
403
+ ...(await cliDefaults()),
404
+ ...options(cmd),
405
+ provider: {
406
+ id: "inspection",
407
+ model: "none",
408
+ stream() {
409
+ throw new Error("Inspection provider cannot run prompts");
410
+ },
411
+ },
412
+ });
413
+ try {
414
+ console.log(JSON.stringify({
415
+ tools: app.registry
416
+ .list()
417
+ .filter((t) => t.name.startsWith("p_"))
418
+ .map((t) => t.name),
419
+ extensions: {
420
+ mascot: app.plugins.extensions.resolve("mascot")?.provider.id ?? "alisio.default",
421
+ startupScreen: app.plugins.extensions.resolve("startup-screen")?.provider.id ?? "alisio.default",
422
+ conflicts: app.plugins.extensions.conflicts(),
423
+ },
424
+ commands: [...app.plugins.commandInfo.entries()]
425
+ .filter(([, info]) => !info.builtin)
426
+ .map(([name]) => name),
427
+ builtin: [...app.plugins.builtins],
428
+ }, null, 2));
429
+ }
430
+ finally {
431
+ await app.close();
432
+ }
433
+ });
434
+ const mcp = program.command("mcp");
435
+ mcp.command("list").action(async (_opts, cmd) => {
436
+ const { loadConfig } = await import("@alisio/core");
437
+ const o = options(cmd);
438
+ const config = await loadConfig(o.cwd ?? process.cwd(), {
439
+ file: o.config,
440
+ trustProject: o.trustProject,
441
+ });
442
+ console.log(JSON.stringify(Object.keys(config.mcp.servers), null, 2));
443
+ });
444
+ mcp
445
+ .command("doctor")
446
+ .argument("<server>")
447
+ .action(async (server, _opts, cmd) => {
448
+ const o = options(cmd);
449
+ if (!o.allowMcp)
450
+ throw new Error("Use --allow-mcp to start or connect to a configured server");
451
+ const { createApplication } = await import("@alisio/core");
452
+ const app = await createApplication({
453
+ ...(await cliDefaults()),
454
+ ...o,
455
+ provider: {
456
+ id: "inspection",
457
+ model: "none",
458
+ stream() {
459
+ throw new Error("Inspection only");
460
+ },
461
+ },
462
+ });
463
+ try {
464
+ console.log(JSON.stringify(await app.mcp.connect(server, AbortSignal.timeout(15000)), null, 2));
465
+ }
466
+ finally {
467
+ await app.close();
468
+ }
469
+ });
470
+ try {
471
+ await program.parseAsync();
472
+ }
473
+ catch (error) {
474
+ console.error(error instanceof Error ? error.message : String(error));
475
+ process.exitCode = 1;
476
+ }
@@ -0,0 +1,5 @@
1
+ /** Prompt templates shipped with the CLI (lowest precedence; users and projects can override). */
2
+ export declare const BUILTIN_PROMPTS: {
3
+ name: string;
4
+ text: string;
5
+ }[];
@@ -0,0 +1,3 @@
1
+ import { INIT_TEMPLATE } from "./init.js";
2
+ /** Prompt templates shipped with the CLI (lowest precedence; users and projects can override). */
3
+ export const BUILTIN_PROMPTS = [{ name: "init", text: INIT_TEMPLATE }];
@@ -0,0 +1,2 @@
1
+ /** Built-in `/init` prompt template (embedded so it ships in dist and in the binary). */
2
+ export declare const INIT_TEMPLATE = "---\ndescription: Analyze this repository and create or update the root AGENTS.md\nargument-hint: \"[focus]\"\nrequires: [write]\n---\nAnalyze this repository and create or update the root `AGENTS.md`: concise, project-specific\ninstructions for coding agents working here.\n\n## 1. Explore efficiently (read-only first)\n- `list_files` on the root and key directories (use `limit`; skip vendored or generated folders).\n- `git_status` to see the state of the tree.\n- `read_file` the manifests that exist: package.json, pnpm-workspace.yaml, pyproject.toml,\n setup.cfg, requirements*.txt, go.mod, Cargo.toml, pom.xml, build.gradle*, Gemfile, composer.json,\n Makefile, justfile, Dockerfile. Nested workspace manifests matter in monorepos.\n- Identify the package manager from lockfiles (pnpm-lock.yaml, package-lock.json, yarn.lock,\n bun.lock/bun.lockb, poetry.lock, uv.lock, Cargo.lock, go.sum).\n- Read build/test/lint/format/typecheck configuration (tsconfig*.json, biome.json, .eslintrc*,\n .prettierrc*, vitest/jest/pytest config, ruff/flake8, rustfmt, golangci) and CI workflows.\n `list_files` hides dotfiles, so probe likely paths such as `.github/workflows/ci.yml` with\n `read_file` (a missing file just returns an error). Use `search_text` only on paths that exist.\n- Read README and CONTRIBUTING, and existing agent instruction files if present: AGENTS.md\n (root and nested), CLAUDE.md, GEMINI.md, .cursorrules, .cursor/rules/*,\n .github/copilot-instructions.md. Probe them with `read_file`; a missing file is not an error.\n- Sample a few representative source and test files to learn the layout and conventions. Use\n `search_text` instead of reading many files.\n\n## 2. Write AGENTS.md (roughly 150 lines or fewer)\nCover, only where the repository gives evidence:\n- Project overview: what it is, main languages and frameworks.\n- Commands: exact setup, build, test, single-test, lint, format and typecheck commands as\n defined in manifests or CI (for example `pnpm test`, not \"run the tests\").\n- Architecture: module or package layout with the important paths.\n- Code style and conventions actually enforced by configuration (formatter, linter rules,\n compiler strictness, import style).\n- Testing approach: framework, where tests live, how fixtures work.\n- Gotchas and constraints: security rules, generated files, files or directories not to touch,\n required tool versions.\n\nRules:\n- Only facts verified from files you read. No generic advice (\"write clean code\"), no invented\n commands or paths. If something important is unknown, say so briefly instead of guessing.\n- Never include secrets, tokens or environment variable values; do not read .env files.\n- Merge useful rules from other agent instruction files and cite the source file, e.g.\n \"(from CLAUDE.md)\".\n\n## 3. Create or update safely\n- If `AGENTS.md` does not exist, create it with `write_file` (`expectedHash: null`).\n- If it exists, `read_file` it first and update it in place: preserve human-written content and\n intent, merge improvements, and keep edits minimal using `edit_file` with the sha256 from\n `read_file` as `expectedHash`. Never blindly overwrite an existing AGENTS.md.\n\n## 4. Finish\nReply with a short summary of what you wrote or changed and anything you could not verify.\n\nAdditional focus from the user (may be empty): $ARGUMENTS\n";
@@ -0,0 +1,57 @@
1
+ /** Built-in `/init` prompt template (embedded so it ships in dist and in the binary). */
2
+ export const INIT_TEMPLATE = `---
3
+ description: Analyze this repository and create or update the root AGENTS.md
4
+ argument-hint: "[focus]"
5
+ requires: [write]
6
+ ---
7
+ Analyze this repository and create or update the root \`AGENTS.md\`: concise, project-specific
8
+ instructions for coding agents working here.
9
+
10
+ ## 1. Explore efficiently (read-only first)
11
+ - \`list_files\` on the root and key directories (use \`limit\`; skip vendored or generated folders).
12
+ - \`git_status\` to see the state of the tree.
13
+ - \`read_file\` the manifests that exist: package.json, pnpm-workspace.yaml, pyproject.toml,
14
+ setup.cfg, requirements*.txt, go.mod, Cargo.toml, pom.xml, build.gradle*, Gemfile, composer.json,
15
+ Makefile, justfile, Dockerfile. Nested workspace manifests matter in monorepos.
16
+ - Identify the package manager from lockfiles (pnpm-lock.yaml, package-lock.json, yarn.lock,
17
+ bun.lock/bun.lockb, poetry.lock, uv.lock, Cargo.lock, go.sum).
18
+ - Read build/test/lint/format/typecheck configuration (tsconfig*.json, biome.json, .eslintrc*,
19
+ .prettierrc*, vitest/jest/pytest config, ruff/flake8, rustfmt, golangci) and CI workflows.
20
+ \`list_files\` hides dotfiles, so probe likely paths such as \`.github/workflows/ci.yml\` with
21
+ \`read_file\` (a missing file just returns an error). Use \`search_text\` only on paths that exist.
22
+ - Read README and CONTRIBUTING, and existing agent instruction files if present: AGENTS.md
23
+ (root and nested), CLAUDE.md, GEMINI.md, .cursorrules, .cursor/rules/*,
24
+ .github/copilot-instructions.md. Probe them with \`read_file\`; a missing file is not an error.
25
+ - Sample a few representative source and test files to learn the layout and conventions. Use
26
+ \`search_text\` instead of reading many files.
27
+
28
+ ## 2. Write AGENTS.md (roughly 150 lines or fewer)
29
+ Cover, only where the repository gives evidence:
30
+ - Project overview: what it is, main languages and frameworks.
31
+ - Commands: exact setup, build, test, single-test, lint, format and typecheck commands as
32
+ defined in manifests or CI (for example \`pnpm test\`, not "run the tests").
33
+ - Architecture: module or package layout with the important paths.
34
+ - Code style and conventions actually enforced by configuration (formatter, linter rules,
35
+ compiler strictness, import style).
36
+ - Testing approach: framework, where tests live, how fixtures work.
37
+ - Gotchas and constraints: security rules, generated files, files or directories not to touch,
38
+ required tool versions.
39
+
40
+ Rules:
41
+ - Only facts verified from files you read. No generic advice ("write clean code"), no invented
42
+ commands or paths. If something important is unknown, say so briefly instead of guessing.
43
+ - Never include secrets, tokens or environment variable values; do not read .env files.
44
+ - Merge useful rules from other agent instruction files and cite the source file, e.g.
45
+ "(from CLAUDE.md)".
46
+
47
+ ## 3. Create or update safely
48
+ - If \`AGENTS.md\` does not exist, create it with \`write_file\` (\`expectedHash: null\`).
49
+ - If it exists, \`read_file\` it first and update it in place: preserve human-written content and
50
+ intent, merge improvements, and keep edits minimal using \`edit_file\` with the sha256 from
51
+ \`read_file\` as \`expectedHash\`. Never blindly overwrite an existing AGENTS.md.
52
+
53
+ ## 4. Finish
54
+ Reply with a short summary of what you wrote or changed and anything you could not verify.
55
+
56
+ Additional focus from the user (may be empty): $ARGUMENTS
57
+ `;
@@ -0,0 +1,8 @@
1
+ import type { AppOptions } from "@alisio/core";
2
+ export interface TuiOptions extends AppOptions {
3
+ session?: string;
4
+ quiet?: boolean;
5
+ /** `false` with --no-banner. */
6
+ banner?: boolean;
7
+ }
8
+ export declare function runTui(options: TuiOptions): Promise<void>;