@agentskit/cli 0.4.2 → 0.5.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/dist/index.cjs CHANGED
@@ -5,21 +5,65 @@ var React3 = require('react');
5
5
  var ink$1 = require('ink');
6
6
  var commander = require('commander');
7
7
  var path = require('path');
8
- var core = require('@agentskit/core');
8
+ var promises = require('fs/promises');
9
9
  var ink = require('@agentskit/ink');
10
10
  var adapters = require('@agentskit/adapters');
11
11
  var tools = require('@agentskit/tools');
12
12
  var skills = require('@agentskit/skills');
13
13
  var memory = require('@agentskit/memory');
14
14
  var jsxRuntime = require('react/jsx-runtime');
15
- var promises = require('fs/promises');
15
+ var prompts = require('@inquirer/prompts');
16
+ var kleur = require('kleur');
17
+ var fs = require('fs');
16
18
  var runtime = require('@agentskit/runtime');
19
+ var child_process = require('child_process');
20
+ var chokidar = require('chokidar');
17
21
 
18
22
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
19
23
 
20
24
  var React3__default = /*#__PURE__*/_interopDefault(React3);
21
25
  var path__default = /*#__PURE__*/_interopDefault(path);
26
+ var kleur__default = /*#__PURE__*/_interopDefault(kleur);
27
+ var chokidar__default = /*#__PURE__*/_interopDefault(chokidar);
22
28
 
29
+ async function loadJsonConfig(path4) {
30
+ try {
31
+ const raw = await promises.readFile(path4, "utf8");
32
+ return JSON.parse(raw);
33
+ } catch {
34
+ return void 0;
35
+ }
36
+ }
37
+ async function loadTsConfig(path4) {
38
+ try {
39
+ const mod = await import(path4);
40
+ return mod.default ?? mod;
41
+ } catch {
42
+ return void 0;
43
+ }
44
+ }
45
+ async function loadPackageJsonConfig(dir) {
46
+ try {
47
+ const raw = await promises.readFile(path.join(dir, "package.json"), "utf8");
48
+ const pkg = JSON.parse(raw);
49
+ if (pkg.agentskit && typeof pkg.agentskit === "object") {
50
+ return pkg.agentskit;
51
+ }
52
+ return void 0;
53
+ } catch {
54
+ return void 0;
55
+ }
56
+ }
57
+ async function loadConfig(options) {
58
+ const cwd = path.resolve(options?.cwd ?? process.cwd());
59
+ const tsPath = path.join(cwd, ".agentskit.config.ts");
60
+ const tsConfig = await loadTsConfig(tsPath);
61
+ if (tsConfig) return tsConfig;
62
+ const jsonPath = path.join(cwd, ".agentskit.config.json");
63
+ const jsonConfig = await loadJsonConfig(jsonPath);
64
+ if (jsonConfig) return jsonConfig;
65
+ return await loadPackageJsonConfig(cwd);
66
+ }
23
67
  var providers = {
24
68
  openai: {
25
69
  label: "OpenAI",
@@ -79,7 +123,7 @@ function createDemoAdapter(provider, model) {
79
123
  ].join(" ");
80
124
  for (const chunk of reply.match(/.{1,18}/g) ?? []) {
81
125
  if (cancelled) return;
82
- await new Promise((resolve) => setTimeout(resolve, 35));
126
+ await new Promise((resolve2) => setTimeout(resolve2, 35));
83
127
  yield { type: "text", content: chunk };
84
128
  }
85
129
  yield { type: "done" };
@@ -186,7 +230,7 @@ function resolveMemory(backend, memoryPath) {
186
230
  return memory.sqliteChatMemory({ path: memoryPath.replace(/\.json$/, ".db") });
187
231
  case "file":
188
232
  default:
189
- return core.createFileMemory(memoryPath);
233
+ return memory.fileChatMemory(memoryPath);
190
234
  }
191
235
  }
192
236
  function ChatApp(options) {
@@ -234,92 +278,467 @@ function renderChatHeader(options) {
234
278
  if (options.memoryBackend) parts.push(`memory=${options.memoryBackend}`);
235
279
  return parts.join(" ");
236
280
  }
237
- function reactStarter() {
281
+ var PROVIDER_IMPORT = {
282
+ openai: "openai",
283
+ anthropic: "anthropic",
284
+ gemini: "gemini",
285
+ ollama: "ollama"
286
+ };
287
+ var PROVIDER_DEFAULT_MODEL = {
288
+ openai: "gpt-4o-mini",
289
+ anthropic: "claude-sonnet-4-6",
290
+ gemini: "gemini-2.5-flash",
291
+ ollama: "llama3.1",
292
+ demo: "demo"
293
+ };
294
+ var PROVIDER_ENV_KEY = {
295
+ openai: "OPENAI_API_KEY",
296
+ anthropic: "ANTHROPIC_API_KEY",
297
+ gemini: "GEMINI_API_KEY",
298
+ ollama: null,
299
+ demo: null
300
+ };
301
+ function adapterCall(provider, prefix = "process.env") {
302
+ const model = PROVIDER_DEFAULT_MODEL[provider];
303
+ if (provider === "demo") return `demoAdapter()`;
304
+ if (provider === "ollama") return `ollama({ model: '${model}' })`;
305
+ const envKey = PROVIDER_ENV_KEY[provider];
306
+ return `${PROVIDER_IMPORT[provider]}({ apiKey: ${prefix}.${envKey} ?? '', model: '${model}' })`;
307
+ }
308
+ function viteAdapterCall(provider) {
309
+ if (provider === "demo") return `demoAdapter()`;
310
+ if (provider === "ollama") return `ollama({ model: '${PROVIDER_DEFAULT_MODEL[provider]}' })`;
311
+ const envKey = PROVIDER_ENV_KEY[provider];
312
+ return `${PROVIDER_IMPORT[provider]}({ apiKey: import.meta.env.VITE_${envKey} ?? '', model: '${PROVIDER_DEFAULT_MODEL[provider]}' })`;
313
+ }
314
+ function adapterImport(provider) {
315
+ if (provider === "demo") return "";
316
+ return `import { ${PROVIDER_IMPORT[provider]} } from '@agentskit/adapters'
317
+ `;
318
+ }
319
+ function toolImports(tools) {
320
+ if (tools.length === 0) return "";
321
+ return `import { ${tools.map((t) => t === "web_search" ? "webSearch" : t).join(", ")} } from '@agentskit/tools'
322
+ `;
323
+ }
324
+ function toolList(tools) {
325
+ if (tools.length === 0) return "[]";
326
+ const calls = tools.map((t) => {
327
+ if (t === "web_search") return "webSearch()";
328
+ if (t === "filesystem") return `...filesystem({ basePath: './workspace' })`;
329
+ if (t === "shell") return `shell({ allowedCommands: ['ls', 'cat'] })`;
330
+ return "";
331
+ });
332
+ return `[${calls.join(", ")}]`;
333
+ }
334
+ function memoryImport(memory) {
335
+ if (memory === "file") return `import { fileChatMemory } from '@agentskit/memory'
336
+ `;
337
+ if (memory === "sqlite") return `import { sqliteChatMemory } from '@agentskit/memory'
338
+ `;
339
+ return "";
340
+ }
341
+ function memoryCall(memory) {
342
+ if (memory === "file") return `fileChatMemory('./.agentskit-history.json')`;
343
+ if (memory === "sqlite") return `sqliteChatMemory({ path: './.agentskit-history.db' })`;
344
+ return "undefined";
345
+ }
346
+ function demoAdapterSnippet() {
347
+ return `function demoAdapter() {
238
348
  return {
239
- "package.json": JSON.stringify({
240
- name: "agentskit-react-app",
241
- private: true,
242
- type: "module",
243
- scripts: {
244
- dev: "vite"
349
+ createSource: () => ({
350
+ stream: async function* () {
351
+ yield { type: 'text' as const, content: 'Hello from your AgentsKit starter. ' }
352
+ yield { type: 'text' as const, content: 'Configure a real adapter to talk to a model.' }
353
+ yield { type: 'done' as const }
245
354
  },
246
- dependencies: {
247
- "@agentskit/adapters": "^0.1.0",
248
- "@agentskit/react": "^0.1.0",
249
- react: "^18.3.1",
250
- "react-dom": "^18.3.1"
251
- }
252
- }, null, 2),
355
+ abort: () => {},
356
+ }),
357
+ }
358
+ }
359
+
360
+ `;
361
+ }
362
+ function reactStarter(ctx) {
363
+ const deps = {
364
+ "@agentskit/react": "^0.4.0",
365
+ react: "^19.0.0",
366
+ "react-dom": "^19.0.0"
367
+ };
368
+ if (ctx.provider !== "demo") deps["@agentskit/adapters"] = "^0.4.0";
369
+ if (ctx.tools.length > 0) deps["@agentskit/tools"] = "^0.4.0";
370
+ if (ctx.memory !== "none") deps["@agentskit/memory"] = "^0.4.0";
371
+ const includesDemo = ctx.provider === "demo";
372
+ const adapter = ctx.provider === "demo" ? viteAdapterCall(ctx.provider) : viteAdapterCall(ctx.provider);
373
+ const envKey = PROVIDER_ENV_KEY[ctx.provider];
374
+ const envContent = envKey ? `VITE_${envKey}=
375
+ ` : "# No API key required for the local provider\n";
376
+ return {
377
+ "package.json": JSON.stringify(
378
+ {
379
+ name: path__default.default.basename(ctx.template === "react" ? "agentskit-react-app" : "agentskit-app"),
380
+ private: true,
381
+ type: "module",
382
+ scripts: {
383
+ dev: "vite",
384
+ build: "vite build",
385
+ preview: "vite preview"
386
+ },
387
+ dependencies: deps,
388
+ devDependencies: {
389
+ "@vitejs/plugin-react": "^5.0.0",
390
+ typescript: "^5.5.0",
391
+ vite: "^7.0.0"
392
+ }
393
+ },
394
+ null,
395
+ 2
396
+ ) + "\n",
397
+ "index.html": `<!doctype html>
398
+ <html lang="en">
399
+ <head>
400
+ <meta charset="UTF-8" />
401
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
402
+ <title>AgentsKit React Starter</title>
403
+ </head>
404
+ <body>
405
+ <div id="root"></div>
406
+ <script type="module" src="/src/main.tsx"></script>
407
+ </body>
408
+ </html>
409
+ `,
410
+ "vite.config.ts": `import { defineConfig } from 'vite'
411
+ import react from '@vitejs/plugin-react'
412
+
413
+ export default defineConfig({ plugins: [react()] })
414
+ `,
415
+ "tsconfig.json": JSON.stringify(
416
+ {
417
+ compilerOptions: {
418
+ target: "ES2022",
419
+ lib: ["ES2022", "DOM"],
420
+ module: "ESNext",
421
+ moduleResolution: "bundler",
422
+ jsx: "react-jsx",
423
+ strict: true,
424
+ noEmit: true,
425
+ skipLibCheck: true
426
+ },
427
+ include: ["src"]
428
+ },
429
+ null,
430
+ 2
431
+ ) + "\n",
253
432
  "src/main.tsx": `import React from 'react'
254
433
  import ReactDOM from 'react-dom/client'
255
- import { ChatContainer, InputBar, Message, useChat } from '@agentskit/react'
256
- import { openai } from '@agentskit/adapters'
257
- import '@agentskit/react/theme'
434
+ import App from './App'
258
435
 
259
- function App() {
436
+ ReactDOM.createRoot(document.getElementById('root')!).render(
437
+ <React.StrictMode>
438
+ <App />
439
+ </React.StrictMode>,
440
+ )
441
+ `,
442
+ "src/App.tsx": `import { ChatContainer, InputBar, Message, useChat } from '@agentskit/react'
443
+ ${adapterImport(ctx.provider)}${toolImports(ctx.tools)}${memoryImport(ctx.memory)}import '@agentskit/react/theme'
444
+
445
+ ${includesDemo ? demoAdapterSnippet() : ""}export default function App() {
260
446
  const chat = useChat({
261
- adapter: openai({ apiKey: import.meta.env.VITE_OPENAI_API_KEY ?? '', model: 'gpt-4o-mini' }),
447
+ adapter: ${adapter},${ctx.tools.length > 0 ? `
448
+ tools: ${toolList(ctx.tools)},` : ""}${ctx.memory !== "none" ? `
449
+ memory: ${memoryCall(ctx.memory)},` : ""}
262
450
  })
263
451
 
264
452
  return (
265
453
  <ChatContainer>
266
- {chat.messages.map(message => <Message key={message.id} message={message} />)}
454
+ {chat.messages.map(message => (
455
+ <Message key={message.id} message={message} />
456
+ ))}
267
457
  <InputBar chat={chat} />
268
458
  </ChatContainer>
269
459
  )
270
460
  }
271
-
272
- ReactDOM.createRoot(document.getElementById('root')!).render(<App />)
273
461
  `,
274
- ".env.example": "VITE_OPENAI_API_KEY=\n"
462
+ ".env.example": envContent,
463
+ ".gitignore": `node_modules
464
+ dist
465
+ .env
466
+ .env.local
467
+ .agentskit-history.*
468
+ `,
469
+ "README.md": readmeFor(ctx)
275
470
  };
276
471
  }
277
- function inkStarter() {
472
+ function inkStarter(ctx) {
473
+ const deps = {
474
+ "@agentskit/ink": "^0.4.0",
475
+ ink: "^7.0.0",
476
+ react: "^19.0.0"
477
+ };
478
+ if (ctx.provider !== "demo") deps["@agentskit/adapters"] = "^0.4.0";
479
+ if (ctx.tools.length > 0) deps["@agentskit/tools"] = "^0.4.0";
480
+ if (ctx.memory !== "none") deps["@agentskit/memory"] = "^0.4.0";
278
481
  return {
279
- "package.json": JSON.stringify({
280
- name: "agentskit-ink-app",
281
- private: true,
282
- type: "module",
283
- scripts: {
284
- dev: "tsx src/index.tsx"
482
+ "package.json": JSON.stringify(
483
+ {
484
+ name: "agentskit-ink-app",
485
+ private: true,
486
+ type: "module",
487
+ scripts: {
488
+ dev: "tsx src/index.tsx",
489
+ start: "tsx src/index.tsx"
490
+ },
491
+ dependencies: deps,
492
+ devDependencies: {
493
+ "@types/react": "^19.0.0",
494
+ tsx: "^4.20.0",
495
+ typescript: "^5.5.0"
496
+ }
285
497
  },
286
- dependencies: {
287
- "@agentskit/ink": "^0.1.0",
288
- react: "^18.3.1"
289
- }
290
- }, null, 2),
498
+ null,
499
+ 2
500
+ ) + "\n",
501
+ "tsconfig.json": JSON.stringify(
502
+ {
503
+ compilerOptions: {
504
+ target: "ES2022",
505
+ module: "ESNext",
506
+ moduleResolution: "bundler",
507
+ jsx: "react-jsx",
508
+ strict: true,
509
+ noEmit: true,
510
+ skipLibCheck: true
511
+ },
512
+ include: ["src"]
513
+ },
514
+ null,
515
+ 2
516
+ ) + "\n",
291
517
  "src/index.tsx": `import React from 'react'
292
518
  import { render } from 'ink'
293
519
  import { ChatContainer, InputBar, Message, useChat } from '@agentskit/ink'
520
+ ${adapterImport(ctx.provider)}${toolImports(ctx.tools)}${memoryImport(ctx.memory)}
521
+ ${ctx.provider === "demo" ? demoAdapterSnippet() : ""}function App() {
522
+ const chat = useChat({
523
+ adapter: ${adapterCall(ctx.provider)},${ctx.tools.length > 0 ? `
524
+ tools: ${toolList(ctx.tools)},` : ""}${ctx.memory !== "none" ? `
525
+ memory: ${memoryCall(ctx.memory)},` : ""}
526
+ })
294
527
 
295
- function DemoAdapter() {
296
- return {
297
- createSource: () => ({
298
- async *stream() {
299
- yield { type: 'text', content: 'Hello from AgentsKit Ink.' }
300
- yield { type: 'done' }
301
- },
302
- abort() {},
303
- }),
304
- }
305
- }
306
-
307
- function App() {
308
- const chat = useChat({ adapter: DemoAdapter() })
309
528
  return (
310
529
  <ChatContainer>
311
- {chat.messages.map(message => <Message key={message.id} message={message} />)}
530
+ {chat.messages.map(message => (
531
+ <Message key={message.id} message={message} />
532
+ ))}
312
533
  <InputBar chat={chat} />
313
534
  </ChatContainer>
314
535
  )
315
536
  }
316
537
 
317
538
  render(<App />)
318
- `
539
+ `,
540
+ ".env.example": PROVIDER_ENV_KEY[ctx.provider] ? `${PROVIDER_ENV_KEY[ctx.provider]}=
541
+ ` : "# No API key required for the local provider\n",
542
+ ".gitignore": `node_modules
543
+ .env
544
+ .env.local
545
+ .agentskit-history.*
546
+ `,
547
+ "README.md": readmeFor(ctx)
548
+ };
549
+ }
550
+ function runtimeStarter(ctx) {
551
+ const deps = {
552
+ "@agentskit/runtime": "^0.4.0"
553
+ };
554
+ if (ctx.provider !== "demo") deps["@agentskit/adapters"] = "^0.4.0";
555
+ if (ctx.tools.length > 0) deps["@agentskit/tools"] = "^0.4.0";
556
+ if (ctx.memory !== "none") deps["@agentskit/memory"] = "^0.4.0";
557
+ return {
558
+ "package.json": JSON.stringify(
559
+ {
560
+ name: "agentskit-runtime-app",
561
+ private: true,
562
+ type: "module",
563
+ scripts: {
564
+ start: "tsx src/index.ts",
565
+ dev: "tsx src/index.ts"
566
+ },
567
+ dependencies: deps,
568
+ devDependencies: {
569
+ tsx: "^4.20.0",
570
+ typescript: "^5.5.0"
571
+ }
572
+ },
573
+ null,
574
+ 2
575
+ ) + "\n",
576
+ "tsconfig.json": JSON.stringify(
577
+ {
578
+ compilerOptions: {
579
+ target: "ES2022",
580
+ module: "ESNext",
581
+ moduleResolution: "bundler",
582
+ strict: true,
583
+ noEmit: true,
584
+ skipLibCheck: true
585
+ },
586
+ include: ["src"]
587
+ },
588
+ null,
589
+ 2
590
+ ) + "\n",
591
+ "src/index.ts": `import { createRuntime } from '@agentskit/runtime'
592
+ ${adapterImport(ctx.provider)}${toolImports(ctx.tools)}${memoryImport(ctx.memory)}
593
+ ${ctx.provider === "demo" ? demoAdapterSnippet() : ""}const runtime = createRuntime({
594
+ adapter: ${adapterCall(ctx.provider)},${ctx.tools.length > 0 ? `
595
+ tools: ${toolList(ctx.tools)},` : ""}${ctx.memory !== "none" ? `
596
+ memory: ${memoryCall(ctx.memory)},` : ""}
597
+ maxSteps: 10,
598
+ })
599
+
600
+ const task = process.argv.slice(2).join(' ') || 'Say hello and tell me one fact about TypeScript.'
601
+ const result = await runtime.run(task)
602
+
603
+ console.log(result.content)
604
+ console.log(\`\\n\u2014 \${result.steps} steps \xB7 \${result.toolCalls.length} tool calls \xB7 \${result.durationMs}ms\`)
605
+ `,
606
+ ".env.example": PROVIDER_ENV_KEY[ctx.provider] ? `${PROVIDER_ENV_KEY[ctx.provider]}=
607
+ ` : "# No API key required for the local provider\n",
608
+ ".gitignore": `node_modules
609
+ .env
610
+ .env.local
611
+ .agentskit-history.*
612
+ `,
613
+ "README.md": readmeFor(ctx)
614
+ };
615
+ }
616
+ function multiAgentStarter(ctx) {
617
+ const deps = {
618
+ "@agentskit/runtime": "^0.4.0",
619
+ "@agentskit/skills": "^0.4.0"
620
+ };
621
+ if (ctx.provider !== "demo") deps["@agentskit/adapters"] = "^0.4.0";
622
+ if (ctx.tools.length === 0) ctx.tools = ["web_search"];
623
+ deps["@agentskit/tools"] = "^0.4.0";
624
+ return {
625
+ "package.json": JSON.stringify(
626
+ {
627
+ name: "agentskit-multi-agent",
628
+ private: true,
629
+ type: "module",
630
+ scripts: {
631
+ start: "tsx src/index.ts",
632
+ dev: "tsx src/index.ts"
633
+ },
634
+ dependencies: deps,
635
+ devDependencies: {
636
+ tsx: "^4.20.0",
637
+ typescript: "^5.5.0"
638
+ }
639
+ },
640
+ null,
641
+ 2
642
+ ) + "\n",
643
+ "tsconfig.json": JSON.stringify(
644
+ {
645
+ compilerOptions: {
646
+ target: "ES2022",
647
+ module: "ESNext",
648
+ moduleResolution: "bundler",
649
+ strict: true,
650
+ noEmit: true,
651
+ skipLibCheck: true
652
+ },
653
+ include: ["src"]
654
+ },
655
+ null,
656
+ 2
657
+ ) + "\n",
658
+ "src/index.ts": `import { createRuntime } from '@agentskit/runtime'
659
+ import { planner, researcher } from '@agentskit/skills'
660
+ ${adapterImport(ctx.provider)}${toolImports(ctx.tools)}
661
+ ${ctx.provider === "demo" ? demoAdapterSnippet() : ""}const runtime = createRuntime({
662
+ adapter: ${adapterCall(ctx.provider)},
663
+ maxSteps: 10,
664
+ maxDelegationDepth: 2,
665
+ })
666
+
667
+ const task = process.argv.slice(2).join(' ') || 'Research the current state of WebGPU and summarize.'
668
+
669
+ const result = await runtime.run(task, {
670
+ skill: planner,
671
+ delegates: {
672
+ researcher: {
673
+ skill: researcher,
674
+ tools: ${toolList(ctx.tools)},
675
+ maxSteps: 5,
676
+ },
677
+ },
678
+ })
679
+
680
+ console.log(result.content)
681
+ console.log(\`\\n\u2014 \${result.steps} steps \xB7 \${result.toolCalls.length} tool calls\`)
682
+ `,
683
+ ".env.example": PROVIDER_ENV_KEY[ctx.provider] ? `${PROVIDER_ENV_KEY[ctx.provider]}=
684
+ ` : "# No API key required for the local provider\n",
685
+ ".gitignore": `node_modules
686
+ .env
687
+ .env.local
688
+ `,
689
+ "README.md": readmeFor(ctx)
319
690
  };
320
691
  }
692
+ function readmeFor(ctx) {
693
+ const installCmd = ctx.pm === "npm" ? "npm install" : `${ctx.pm} install`;
694
+ const runCmd = ctx.pm === "npm" ? "npm run dev" : `${ctx.pm} dev`;
695
+ const envKey = PROVIDER_ENV_KEY[ctx.provider];
696
+ return `# AgentsKit ${ctx.template} starter
697
+
698
+ Generated by \`agentskit init\`.
699
+
700
+ ## Stack
701
+
702
+ - **Template**: \`${ctx.template}\`
703
+ - **Provider**: \`${ctx.provider}\`${ctx.tools.length ? `
704
+ - **Tools**: ${ctx.tools.map((t) => `\`${t}\``).join(", ")}` : ""}${ctx.memory !== "none" ? `
705
+ - **Memory**: \`${ctx.memory}\`` : ""}
706
+
707
+ ## Run
708
+
709
+ \`\`\`bash
710
+ ${installCmd}
711
+ ${envKey ? `cp .env.example .env
712
+ # add ${envKey}=...` : "# No API key required"}
713
+ ${runCmd}
714
+ \`\`\`
715
+
716
+ ## Next steps
717
+
718
+ - Open the AgentsKit docs at https://agentskit.io/docs
719
+ - Add a custom skill: https://agentskit.io/docs/concepts/skill
720
+ - Wire up RAG: https://agentskit.io/docs/recipes/rag-chat
721
+
722
+ ## License
723
+
724
+ ISC
725
+ `;
726
+ }
727
+ var TEMPLATE_FN = {
728
+ react: reactStarter,
729
+ ink: inkStarter,
730
+ runtime: runtimeStarter,
731
+ "multi-agent": multiAgentStarter
732
+ };
321
733
  async function writeStarterProject(options) {
322
- const files = options.template === "ink" ? inkStarter() : reactStarter();
734
+ const ctx = {
735
+ template: options.template,
736
+ provider: options.provider ?? "demo",
737
+ tools: options.tools ?? [],
738
+ memory: options.memory ?? "none",
739
+ pm: options.packageManager ?? "pnpm"
740
+ };
741
+ const files = TEMPLATE_FN[ctx.template](ctx);
323
742
  await promises.mkdir(options.targetDir, { recursive: true });
324
743
  await Promise.all(
325
744
  Object.entries(files).map(async ([relativePath, content]) => {
@@ -329,6 +748,133 @@ async function writeStarterProject(options) {
329
748
  })
330
749
  );
331
750
  }
751
+ async function runInteractiveInit(defaults = {}) {
752
+ process.stdout.write(`
753
+ ${kleur__default.default.bold().green("\u25B2")} ${kleur__default.default.bold("agentskit init")}
754
+ `);
755
+ process.stdout.write(kleur__default.default.dim(" Generate a starter project \u2014 answer five questions.\n\n"));
756
+ try {
757
+ const targetDir = await prompts.input({
758
+ message: "Project directory:",
759
+ default: defaults.dir ?? "agentskit-app",
760
+ validate: (value) => {
761
+ if (!value.trim()) return "A directory name is required.";
762
+ const abs = path__default.default.resolve(process.cwd(), value);
763
+ if (fs.existsSync(abs)) return `${value} already exists. Pick a different name.`;
764
+ return true;
765
+ }
766
+ });
767
+ const template = await prompts.select({
768
+ message: "Template:",
769
+ default: defaults.template ?? "react",
770
+ choices: [
771
+ { name: "React chat (Vite + browser)", value: "react", description: "Streaming UI with @agentskit/react" },
772
+ { name: "Ink chat (terminal UI)", value: "ink", description: "Same chat but in your terminal" },
773
+ { name: "Runtime (headless agent, no UI)", value: "runtime", description: "Autonomous task \u2192 result" },
774
+ { name: "Multi-agent (planner + delegates)", value: "multi-agent", description: "Supervisor pattern, ready to extend" }
775
+ ]
776
+ });
777
+ const provider = await prompts.select({
778
+ message: "LLM provider:",
779
+ default: "demo",
780
+ choices: [
781
+ { name: "Demo (no API key \u2014 deterministic stub)", value: "demo" },
782
+ { name: "OpenAI", value: "openai" },
783
+ { name: "Anthropic", value: "anthropic" },
784
+ { name: "Gemini", value: "gemini" },
785
+ { name: "Ollama (local, no key)", value: "ollama" }
786
+ ]
787
+ });
788
+ let tools = [];
789
+ if (template !== "react") {
790
+ tools = await prompts.checkbox({
791
+ message: "Tools (space to toggle, enter to confirm):",
792
+ choices: [
793
+ { name: "web_search", value: "web_search" },
794
+ { name: "filesystem", value: "filesystem" },
795
+ { name: "shell", value: "shell" }
796
+ ]
797
+ });
798
+ }
799
+ const memory = await prompts.select({
800
+ message: "Memory backend:",
801
+ default: "none",
802
+ choices: [
803
+ { name: "None (stateless)", value: "none" },
804
+ { name: "File (JSON on disk)", value: "file" },
805
+ { name: "SQLite (better-sqlite3)", value: "sqlite" }
806
+ ]
807
+ });
808
+ const packageManager = await prompts.select({
809
+ message: "Package manager:",
810
+ default: "pnpm",
811
+ choices: [
812
+ { name: "pnpm", value: "pnpm" },
813
+ { name: "npm", value: "npm" },
814
+ { name: "yarn", value: "yarn" },
815
+ { name: "bun", value: "bun" }
816
+ ]
817
+ });
818
+ process.stdout.write("\n" + kleur__default.default.dim(" Summary:\n"));
819
+ process.stdout.write(kleur__default.default.dim(` dir ${targetDir}
820
+ `));
821
+ process.stdout.write(kleur__default.default.dim(` template ${template}
822
+ `));
823
+ process.stdout.write(kleur__default.default.dim(` provider ${provider}
824
+ `));
825
+ if (tools.length) process.stdout.write(kleur__default.default.dim(` tools ${tools.join(", ")}
826
+ `));
827
+ process.stdout.write(kleur__default.default.dim(` memory ${memory}
828
+ `));
829
+ process.stdout.write(kleur__default.default.dim(` pm ${packageManager}
830
+
831
+ `));
832
+ const proceed = await prompts.confirm({ message: "Generate?", default: true });
833
+ if (!proceed) {
834
+ process.stdout.write(kleur__default.default.yellow("Cancelled.\n"));
835
+ return { cancelled: true, options: { targetDir, template, provider, tools, memory, packageManager } };
836
+ }
837
+ return {
838
+ cancelled: false,
839
+ options: {
840
+ targetDir: path__default.default.resolve(process.cwd(), targetDir),
841
+ template,
842
+ provider,
843
+ tools,
844
+ memory,
845
+ packageManager
846
+ }
847
+ };
848
+ } catch (err) {
849
+ if (err.name === "ExitPromptError") {
850
+ process.stdout.write(kleur__default.default.yellow("\nCancelled.\n"));
851
+ return { cancelled: true, options: { targetDir: "", template: "react" } };
852
+ }
853
+ throw err;
854
+ }
855
+ }
856
+ function printNextSteps(options) {
857
+ const dir = path__default.default.relative(process.cwd(), options.targetDir) || ".";
858
+ const pm = options.packageManager ?? "pnpm";
859
+ const installCmd = pm === "npm" ? "npm install" : `${pm} install`;
860
+ const runCmd = pm === "npm" ? "npm run dev" : `${pm} dev`;
861
+ process.stdout.write("\n" + kleur__default.default.green("\u2713 Created starter at ") + kleur__default.default.bold(dir) + "\n\n");
862
+ process.stdout.write(kleur__default.default.bold("Next steps:\n\n"));
863
+ process.stdout.write(` ${kleur__default.default.cyan("cd")} ${dir}
864
+ `);
865
+ process.stdout.write(` ${kleur__default.default.cyan(installCmd)}
866
+ `);
867
+ if (options.provider && options.provider !== "demo" && options.provider !== "ollama") {
868
+ process.stdout.write(
869
+ ` ${kleur__default.default.cyan("cp")} .env.example .env ${kleur__default.default.dim("# add your API key")}
870
+ `
871
+ );
872
+ }
873
+ process.stdout.write(` ${kleur__default.default.cyan(runCmd)}
874
+
875
+ `);
876
+ process.stdout.write(kleur__default.default.dim(" Docs: https://agentskit.io/docs\n\n"));
877
+ }
332
878
  function formatEvent(event) {
333
879
  switch (event.type) {
334
880
  case "agent:step":
@@ -483,6 +1029,404 @@ function RunApp({ task, options }) {
483
1029
  ] })
484
1030
  ] });
485
1031
  }
1032
+ var PROVIDER_ENV_KEYS = {
1033
+ openai: "OPENAI_API_KEY",
1034
+ anthropic: "ANTHROPIC_API_KEY",
1035
+ gemini: "GEMINI_API_KEY",
1036
+ deepseek: "DEEPSEEK_API_KEY",
1037
+ grok: "XAI_API_KEY",
1038
+ kimi: "KIMI_API_KEY"
1039
+ };
1040
+ var PROVIDER_REACH_URLS = {
1041
+ openai: "https://api.openai.com/v1/models",
1042
+ anthropic: "https://api.anthropic.com",
1043
+ gemini: "https://generativelanguage.googleapis.com",
1044
+ ollama: "http://localhost:11434/api/tags"
1045
+ };
1046
+ async function checkNodeVersion() {
1047
+ const major = Number(process.versions.node.split(".")[0]);
1048
+ if (Number.isNaN(major)) {
1049
+ return { status: "fail", name: "Node version", detail: "Could not parse process.versions.node" };
1050
+ }
1051
+ if (major < 22) {
1052
+ return {
1053
+ status: "fail",
1054
+ name: "Node version",
1055
+ detail: `Node ${process.versions.node} (need 22+)`,
1056
+ fix: "Install Node 22 LTS or newer (https://nodejs.org)"
1057
+ };
1058
+ }
1059
+ if (major === 25) {
1060
+ return {
1061
+ status: "warn",
1062
+ name: "Node version",
1063
+ detail: `Node ${process.versions.node} \u2014 Docusaurus apps may break here`,
1064
+ fix: "Use Node 22 LTS for the legacy docs app, or stay on 25 for everything else"
1065
+ };
1066
+ }
1067
+ return { status: "pass", name: "Node version", detail: `Node ${process.versions.node}` };
1068
+ }
1069
+ async function checkPnpm() {
1070
+ const cwd = process.cwd();
1071
+ const hasPnpm = fs.existsSync(path.join(cwd, "pnpm-lock.yaml")) || fs.existsSync(path.join(cwd, "pnpm-workspace.yaml"));
1072
+ if (hasPnpm) {
1073
+ return { status: "pass", name: "Package manager", detail: "pnpm detected (lockfile)" };
1074
+ }
1075
+ if (fs.existsSync(path.join(cwd, "package-lock.json"))) {
1076
+ return { status: "warn", name: "Package manager", detail: "npm detected \u2014 pnpm recommended for monorepo workflows" };
1077
+ }
1078
+ if (fs.existsSync(path.join(cwd, "yarn.lock"))) {
1079
+ return { status: "pass", name: "Package manager", detail: "yarn detected" };
1080
+ }
1081
+ if (fs.existsSync(path.join(cwd, "bun.lock")) || fs.existsSync(path.join(cwd, "bun.lockb"))) {
1082
+ return { status: "pass", name: "Package manager", detail: "bun detected" };
1083
+ }
1084
+ return {
1085
+ status: "skip",
1086
+ name: "Package manager",
1087
+ detail: "No lockfile found in cwd"
1088
+ };
1089
+ }
1090
+ async function checkPackageJson() {
1091
+ const path4 = path.join(process.cwd(), "package.json");
1092
+ if (!fs.existsSync(path4)) {
1093
+ return {
1094
+ status: "warn",
1095
+ name: "package.json",
1096
+ detail: "No package.json in cwd",
1097
+ fix: "Run from a project directory (or use `agentskit init` to create one)"
1098
+ };
1099
+ }
1100
+ try {
1101
+ const pkg = JSON.parse(await promises.readFile(path4, "utf8"));
1102
+ const deps = {
1103
+ ...pkg.dependencies ?? {},
1104
+ ...pkg.devDependencies ?? {}
1105
+ };
1106
+ const akDeps = Object.entries(deps).filter(([name]) => name.startsWith("@agentskit/"));
1107
+ if (akDeps.length === 0) {
1108
+ return { status: "skip", name: "AgentsKit packages", detail: "No @agentskit/* deps found in package.json" };
1109
+ }
1110
+ return {
1111
+ status: "pass",
1112
+ name: "AgentsKit packages",
1113
+ detail: `${akDeps.length} installed: ${akDeps.map(([n]) => n.replace("@agentskit/", "")).join(", ")}`
1114
+ };
1115
+ } catch (err) {
1116
+ return {
1117
+ status: "fail",
1118
+ name: "package.json",
1119
+ detail: `Could not parse: ${err.message}`
1120
+ };
1121
+ }
1122
+ }
1123
+ async function checkProviderEnv(provider) {
1124
+ const envKey = PROVIDER_ENV_KEYS[provider];
1125
+ if (!envKey) {
1126
+ return { status: "skip", name: `${provider} API key`, detail: "No env-key requirement for this provider" };
1127
+ }
1128
+ const value = process.env[envKey];
1129
+ if (!value) {
1130
+ return {
1131
+ status: "fail",
1132
+ name: `${provider} API key`,
1133
+ detail: `${envKey} is not set`,
1134
+ fix: `export ${envKey}=...`
1135
+ };
1136
+ }
1137
+ if (value.length < 16) {
1138
+ return {
1139
+ status: "warn",
1140
+ name: `${provider} API key`,
1141
+ detail: `${envKey} looks too short (${value.length} chars)`,
1142
+ fix: "Verify the key is complete and not truncated"
1143
+ };
1144
+ }
1145
+ return { status: "pass", name: `${provider} API key`, detail: `${envKey} set (${value.length} chars)` };
1146
+ }
1147
+ async function checkProviderReachable(provider, fetchImpl = fetch, timeoutMs = 4e3) {
1148
+ const url = PROVIDER_REACH_URLS[provider];
1149
+ if (!url) {
1150
+ return { status: "skip", name: `${provider} reachable`, detail: "No reachability check for this provider" };
1151
+ }
1152
+ const controller = new AbortController();
1153
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
1154
+ try {
1155
+ const res = await fetchImpl(url, {
1156
+ method: "GET",
1157
+ signal: controller.signal
1158
+ // No auth — we just want to confirm DNS + network reach.
1159
+ });
1160
+ return {
1161
+ status: "pass",
1162
+ name: `${provider} reachable`,
1163
+ detail: `${url} \u2192 HTTP ${res.status}`
1164
+ };
1165
+ } catch (err) {
1166
+ const reason = err.name === "AbortError" ? `timeout after ${timeoutMs}ms` : err.message;
1167
+ return {
1168
+ status: "fail",
1169
+ name: `${provider} reachable`,
1170
+ detail: `${url} \u2192 ${reason}`,
1171
+ fix: provider === "ollama" ? "Start Ollama: `ollama serve` (or install from https://ollama.com)" : "Check network / firewall / VPN settings"
1172
+ };
1173
+ } finally {
1174
+ clearTimeout(timer);
1175
+ }
1176
+ }
1177
+ async function checkConfig() {
1178
+ try {
1179
+ const config = await loadConfig();
1180
+ if (!config) {
1181
+ return { status: "skip", name: "AgentsKit config", detail: "No .agentskit.config or package.json#agentskit found" };
1182
+ }
1183
+ return {
1184
+ status: "pass",
1185
+ name: "AgentsKit config",
1186
+ detail: `loaded \u2014 defaults: ${JSON.stringify(config.defaults ?? {})}`
1187
+ };
1188
+ } catch (err) {
1189
+ return {
1190
+ status: "warn",
1191
+ name: "AgentsKit config",
1192
+ detail: `Could not load: ${err.message}`
1193
+ };
1194
+ }
1195
+ }
1196
+ async function runDoctor(options = {}) {
1197
+ const providers2 = options.providers ?? ["openai", "anthropic", "gemini", "ollama"];
1198
+ const fetchImpl = options.fetchImpl ?? fetch;
1199
+ const checks = [
1200
+ checkNodeVersion(),
1201
+ checkPnpm(),
1202
+ checkPackageJson(),
1203
+ checkConfig()
1204
+ ];
1205
+ for (const provider of providers2) {
1206
+ checks.push(checkProviderEnv(provider));
1207
+ if (!options.noNetwork) {
1208
+ checks.push(checkProviderReachable(provider, fetchImpl));
1209
+ }
1210
+ }
1211
+ const results = await Promise.all(checks);
1212
+ return {
1213
+ results,
1214
+ pass: results.filter((r) => r.status === "pass").length,
1215
+ warn: results.filter((r) => r.status === "warn").length,
1216
+ fail: results.filter((r) => r.status === "fail").length,
1217
+ skip: results.filter((r) => r.status === "skip").length
1218
+ };
1219
+ }
1220
+ var ICON = {
1221
+ pass: "\u2713",
1222
+ warn: "!",
1223
+ fail: "\u2717",
1224
+ skip: "\xB7"
1225
+ };
1226
+ function renderReport(report, opts = {}) {
1227
+ const color = opts.color ?? true;
1228
+ const c = (code, text) => color ? `\x1B[${code}m${text}\x1B[0m` : text;
1229
+ const colorFor = {
1230
+ pass: (t) => c("32", t),
1231
+ warn: (t) => c("33", t),
1232
+ fail: (t) => c("31", t),
1233
+ skip: (t) => c("90", t)
1234
+ };
1235
+ const lines = [];
1236
+ lines.push("");
1237
+ lines.push(c("1", "agentskit doctor"));
1238
+ lines.push("");
1239
+ for (const r of report.results) {
1240
+ const icon = colorFor[r.status](ICON[r.status]);
1241
+ const name = r.name.padEnd(28);
1242
+ const detail = r.detail ? c("90", r.detail) : "";
1243
+ lines.push(` ${icon} ${name} ${detail}`);
1244
+ if (r.fix && (r.status === "fail" || r.status === "warn")) {
1245
+ lines.push(` ${c("90", "\u21B3 " + r.fix)}`);
1246
+ }
1247
+ }
1248
+ lines.push("");
1249
+ const summary = [
1250
+ `${report.pass} pass`,
1251
+ report.warn > 0 ? colorFor.warn(`${report.warn} warn`) : `${report.warn} warn`,
1252
+ report.fail > 0 ? colorFor.fail(`${report.fail} fail`) : `${report.fail} fail`,
1253
+ `${report.skip} skip`
1254
+ ].join(" \xB7 ");
1255
+ lines.push(` ${c("1", "Summary:")} ${summary}`);
1256
+ lines.push("");
1257
+ return lines.join("\n");
1258
+ }
1259
+ var DEFAULT_WATCH = [
1260
+ "**/*.ts",
1261
+ "**/*.tsx",
1262
+ "**/*.mjs",
1263
+ "**/*.json",
1264
+ ".agentskit.config.*"
1265
+ ];
1266
+ var DEFAULT_IGNORE = [
1267
+ "**/node_modules/**",
1268
+ "**/dist/**",
1269
+ "**/build/**",
1270
+ "**/.next/**",
1271
+ "**/.turbo/**",
1272
+ "**/.git/**",
1273
+ "**/coverage/**",
1274
+ "**/*.test.ts",
1275
+ "**/*.spec.ts"
1276
+ ];
1277
+ function startDev(options) {
1278
+ const entry = path.resolve(process.cwd(), options.entry);
1279
+ if (!fs.existsSync(entry)) {
1280
+ throw new Error(`Entry file not found: ${entry}`);
1281
+ }
1282
+ const stdout = options.stdout ?? process.stdout;
1283
+ const stderr = options.stderr ?? process.stderr;
1284
+ const debounceMs = options.debounceMs ?? 200;
1285
+ const isTs = entry.endsWith(".ts") || entry.endsWith(".tsx");
1286
+ const cmd = isTs ? "tsx" : "node";
1287
+ const baseArgs = [entry, ...options.scriptArgs ?? []];
1288
+ const spawnFn = options.spawn ?? ((c, a) => child_process.spawn(c, a, {
1289
+ stdio: ["inherit", "pipe", "pipe"],
1290
+ env: { ...process.env, FORCE_COLOR: "1" }
1291
+ }));
1292
+ const watchPaths = options.watch ?? DEFAULT_WATCH;
1293
+ const ignorePaths = [...DEFAULT_IGNORE, ...options.ignore ?? []];
1294
+ const watcherFactory = options.watcher ?? ((paths, opts) => chokidar__default.default.watch(paths, { ignored: opts.ignored, ignoreInitial: true }));
1295
+ const watcher = watcherFactory(watchPaths, { ignored: ignorePaths });
1296
+ let child;
1297
+ let restartCount = 0;
1298
+ let restartTimer;
1299
+ let stopped = false;
1300
+ let resolveDone;
1301
+ const done = new Promise((r) => {
1302
+ resolveDone = r;
1303
+ });
1304
+ const banner = (msg, color = "green") => {
1305
+ const time = (/* @__PURE__ */ new Date()).toTimeString().slice(0, 8);
1306
+ stdout.write(kleur__default.default[color](`[agentskit dev ${time}] `) + msg + "\n");
1307
+ };
1308
+ const startChild = () => {
1309
+ restartCount++;
1310
+ banner(`\u25B8 starting ${kleur__default.default.bold(path.basename(entry))} (restart #${restartCount - 1})`, "cyan");
1311
+ const c = spawnFn(cmd, baseArgs);
1312
+ child = c;
1313
+ c.stdout?.on("data", (d) => stdout.write(d));
1314
+ c.stderr?.on("data", (d) => stderr.write(d));
1315
+ c.on("exit", (code, signal) => {
1316
+ if (stopped) return;
1317
+ if (signal === "SIGTERM" || signal === "SIGINT") return;
1318
+ if (code === 0) {
1319
+ banner(`\u2713 exited cleanly \u2014 waiting for changes`, "green");
1320
+ } else {
1321
+ banner(`\u2717 exited with code ${code} \u2014 waiting for changes`, "red");
1322
+ }
1323
+ });
1324
+ };
1325
+ const restart = (path4) => {
1326
+ if (restartTimer) clearTimeout(restartTimer);
1327
+ restartTimer = setTimeout(() => {
1328
+ restartTimer = void 0;
1329
+ banner(`\u21BB change detected \u2014 ${path4}`, "yellow");
1330
+ if (child && !child.killed && child.exitCode === null) {
1331
+ child.kill("SIGTERM");
1332
+ }
1333
+ setTimeout(startChild, 80);
1334
+ }, debounceMs);
1335
+ };
1336
+ watcher.on("change", restart);
1337
+ watcher.on("add", restart);
1338
+ watcher.on("unlink", restart);
1339
+ startChild();
1340
+ const stop = async () => {
1341
+ if (stopped) return;
1342
+ stopped = true;
1343
+ if (restartTimer) clearTimeout(restartTimer);
1344
+ if (child && !child.killed && child.exitCode === null) {
1345
+ child.kill("SIGTERM");
1346
+ }
1347
+ await watcher.close();
1348
+ banner(`stopped`, "cyan");
1349
+ resolveDone();
1350
+ };
1351
+ if (process.stdin.isTTY && process.stdin.setRawMode) {
1352
+ process.stdin.setRawMode(true);
1353
+ process.stdin.resume();
1354
+ process.stdin.on("data", (data) => {
1355
+ const key = data.toString();
1356
+ if (key === "r") restart("manual");
1357
+ if (key === "q" || key === "") void stop();
1358
+ });
1359
+ }
1360
+ return {
1361
+ done,
1362
+ stop,
1363
+ restarts: () => restartCount
1364
+ };
1365
+ }
1366
+ async function startTunnel(options) {
1367
+ const stdout = options.stdout ?? process.stdout;
1368
+ const open = options.open ?? (async (opts) => {
1369
+ const lt = (await import('localtunnel')).default;
1370
+ return await lt(opts);
1371
+ });
1372
+ const banner = (msg, color = "green") => {
1373
+ const time = (/* @__PURE__ */ new Date()).toTimeString().slice(0, 8);
1374
+ stdout.write(kleur__default.default[color](`[agentskit tunnel ${time}] `) + msg + "\n");
1375
+ };
1376
+ banner(`opening tunnel to ${options.host ?? "localhost"}:${options.port}...`, "cyan");
1377
+ const tunnel = await open({
1378
+ port: options.port,
1379
+ subdomain: options.subdomain,
1380
+ local_host: options.host
1381
+ });
1382
+ let requests = 0;
1383
+ let stopped = false;
1384
+ let resolveDone;
1385
+ const done = new Promise((r) => {
1386
+ resolveDone = r;
1387
+ });
1388
+ tunnel.on("request", () => {
1389
+ requests++;
1390
+ });
1391
+ tunnel.on("close", () => {
1392
+ if (stopped) return;
1393
+ banner(`tunnel closed by remote`, "yellow");
1394
+ resolveDone();
1395
+ });
1396
+ tunnel.on("error", (...args) => {
1397
+ const err = args[0];
1398
+ banner(`error: ${err?.message ?? "unknown"}`, "red");
1399
+ });
1400
+ banner(`\u2713 ready`, "green");
1401
+ stdout.write("\n");
1402
+ stdout.write(` ${kleur__default.default.bold("Public URL:")} ${kleur__default.default.cyan(tunnel.url)}
1403
+ `);
1404
+ stdout.write(` ${kleur__default.default.bold("Local:")} http://${options.host ?? "localhost"}:${options.port}
1405
+ `);
1406
+ stdout.write("\n");
1407
+ stdout.write(kleur__default.default.dim(` Forward webhooks here, then ${kleur__default.default.bold("Ctrl+C")} to stop.
1408
+
1409
+ `));
1410
+ options.onReady?.(tunnel.url);
1411
+ const stop = async () => {
1412
+ if (stopped) return;
1413
+ stopped = true;
1414
+ tunnel.close();
1415
+ banner(`stopped \u2014 proxied ${requests} request${requests === 1 ? "" : "s"}`, "cyan");
1416
+ resolveDone();
1417
+ };
1418
+ if (process.stdin.isTTY) {
1419
+ process.on("SIGINT", () => {
1420
+ void stop();
1421
+ });
1422
+ }
1423
+ return {
1424
+ url: tunnel.url,
1425
+ done,
1426
+ stop,
1427
+ requests: () => requests
1428
+ };
1429
+ }
486
1430
 
487
1431
  // src/commands.ts
488
1432
  function mergeWithConfig(options, config) {
@@ -498,7 +1442,7 @@ function createCli() {
498
1442
  const program = new commander.Command();
499
1443
  program.name("agentskit").description("AgentsKit CLI for chat demos and project bootstrapping.");
500
1444
  program.command("chat").description("Start a terminal chat session.").option("--provider <provider>", "Provider to use", "demo").option("--model <model>", "Model name").option("--api-key <key>", "API key for the selected provider").option("--base-url <url>", "Override provider base URL").option("--system <prompt>", "System prompt").option("--memory <path>", "Path for file-based memory", ".agentskit-history.json").option("--tools <tools>", "Comma-separated tools: web_search,filesystem,shell").option("--skill <skills>", "Comma-separated skills: researcher,coder,planner,critic,summarizer").option("--memory-backend <backend>", "Memory backend: file (default), sqlite").option("--no-config", "Skip loading .agentskit.config.json").action(async (options) => {
501
- const config = options.config !== false ? await core.loadConfig() : void 0;
1445
+ const config = options.config !== false ? await loadConfig() : void 0;
502
1446
  const merged = mergeWithConfig(options, config);
503
1447
  const chatOptions = {
504
1448
  apiKey: merged.apiKey ?? options.apiKey,
@@ -522,7 +1466,7 @@ function createCli() {
522
1466
  process.stderr.write("Error: task is required. Pass as argument or use --task.\n");
523
1467
  process.exit(1);
524
1468
  }
525
- const config = options.config !== false ? await core.loadConfig() : void 0;
1469
+ const config = options.config !== false ? await loadConfig() : void 0;
526
1470
  const merged = mergeWithConfig(options, config);
527
1471
  if (options.pretty) {
528
1472
  ink$1.render(React3__default.default.createElement(RunApp, { task, options }));
@@ -536,22 +1480,106 @@ function createCli() {
536
1480
  }
537
1481
  }
538
1482
  });
539
- program.command("init").description("Generate a starter project.").option("--template <template>", "Starter template (react|ink)", "react").option("--dir <directory>", "Target directory", "agentskit-starter").action(async (options) => {
540
- await writeStarterProject({
541
- template: options.template === "ink" ? "ink" : "react",
542
- targetDir: path__default.default.resolve(process.cwd(), options.dir)
1483
+ program.command("init").description("Generate a starter project. Run with no flags for interactive mode.").option("--template <template>", "Starter template (react|ink|runtime|multi-agent)").option("--dir <directory>", "Target directory", "agentskit-app").option("--provider <provider>", "LLM provider (openai|anthropic|gemini|ollama|demo)").option("--tools <tools>", "Comma-separated tools (web_search,filesystem,shell)").option("--memory <backend>", "Memory backend (none|file|sqlite)").option("--pm <packageManager>", "Package manager (pnpm|npm|yarn|bun)").option("-y, --yes", "Skip interactive prompts; use flag values + defaults").action(async (rawOptions) => {
1484
+ const isCi = !process.stdout.isTTY || rawOptions.yes || rawOptions.template;
1485
+ let resolved;
1486
+ if (isCi) {
1487
+ const template = rawOptions.template ?? "react";
1488
+ resolved = {
1489
+ targetDir: path__default.default.resolve(process.cwd(), rawOptions.dir),
1490
+ template,
1491
+ provider: rawOptions.provider ?? "demo",
1492
+ tools: rawOptions.tools ? rawOptions.tools.split(",").map((t) => t.trim()) : [],
1493
+ memory: rawOptions.memory ?? "none",
1494
+ packageManager: rawOptions.pm ?? "pnpm"
1495
+ };
1496
+ } else {
1497
+ const result = await runInteractiveInit({
1498
+ dir: rawOptions.dir,
1499
+ template: rawOptions.template
1500
+ });
1501
+ if (result.cancelled) {
1502
+ process.exit(0);
1503
+ }
1504
+ resolved = result.options;
1505
+ }
1506
+ await writeStarterProject(resolved);
1507
+ if (isCi) {
1508
+ process.stdout.write(
1509
+ `Created ${resolved.template} starter in ${path__default.default.relative(process.cwd(), resolved.targetDir) || "."}
1510
+ `
1511
+ );
1512
+ } else {
1513
+ printNextSteps(resolved);
1514
+ }
1515
+ });
1516
+ program.command("doctor").description("Diagnose your AgentsKit environment.").option("--no-network", "Skip provider reachability checks").option(
1517
+ "--providers <providers>",
1518
+ "Comma-separated providers to check (default: openai,anthropic,gemini,ollama)"
1519
+ ).option("--json", "Emit JSON instead of formatted output").action(async (options) => {
1520
+ const providers2 = options.providers ? options.providers.split(",").map((p) => p.trim()).filter(Boolean) : void 0;
1521
+ const report = await runDoctor({
1522
+ providers: providers2,
1523
+ noNetwork: options.network === false
543
1524
  });
544
- process.stdout.write(`Created ${options.template} starter in ${options.dir}
1525
+ if (options.json) {
1526
+ process.stdout.write(JSON.stringify(report, null, 2) + "\n");
1527
+ } else {
1528
+ process.stdout.write(renderReport(report, { color: process.stdout.isTTY }));
1529
+ }
1530
+ if (report.fail > 0) process.exit(1);
1531
+ });
1532
+ program.command("dev [entry]").description("Run an entry file with hot-reload on file changes.").option("--watch <globs>", "Comma-separated glob patterns to watch").option("--ignore <globs>", "Comma-separated glob patterns to ignore").option("--debounce <ms>", "Debounce window before restart", "200").action(async (positional, options) => {
1533
+ const entry = positional ?? "src/index.ts";
1534
+ const watch = options.watch ? options.watch.split(",").map((s) => s.trim()).filter(Boolean) : void 0;
1535
+ const ignore = options.ignore ? options.ignore.split(",").map((s) => s.trim()).filter(Boolean) : void 0;
1536
+ try {
1537
+ const controller = startDev({
1538
+ entry,
1539
+ watch,
1540
+ ignore,
1541
+ debounceMs: Number(options.debounce) || 200
1542
+ });
1543
+ await controller.done;
1544
+ } catch (err) {
1545
+ process.stderr.write(`Error: ${err.message}
545
1546
  `);
1547
+ process.exit(1);
1548
+ }
1549
+ });
1550
+ program.command("tunnel <port>").description("Open a public URL pointing to a local port (great for webhooks).").option("--subdomain <name>", "Hint for a stable subdomain (provider may decline)").option("--host <host>", "Local hostname", "localhost").action(async (port, options) => {
1551
+ const portNum = Number(port);
1552
+ if (Number.isNaN(portNum) || portNum < 1 || portNum > 65535) {
1553
+ process.stderr.write(`Error: invalid port: ${port}
1554
+ `);
1555
+ process.exit(2);
1556
+ }
1557
+ try {
1558
+ const controller = await startTunnel({
1559
+ port: portNum,
1560
+ subdomain: options.subdomain,
1561
+ host: options.host
1562
+ });
1563
+ await controller.done;
1564
+ } catch (err) {
1565
+ process.stderr.write(`Error: ${err.message}
1566
+ `);
1567
+ process.exit(1);
1568
+ }
546
1569
  });
547
1570
  return program;
548
1571
  }
549
1572
 
550
1573
  exports.ChatApp = ChatApp;
551
1574
  exports.createCli = createCli;
1575
+ exports.loadConfig = loadConfig;
552
1576
  exports.renderChatHeader = renderChatHeader;
1577
+ exports.renderReport = renderReport;
553
1578
  exports.resolveChatProvider = resolveChatProvider;
554
1579
  exports.runAgent = runAgent;
1580
+ exports.runDoctor = runDoctor;
1581
+ exports.startDev = startDev;
1582
+ exports.startTunnel = startTunnel;
555
1583
  exports.writeStarterProject = writeStarterProject;
556
1584
  //# sourceMappingURL=index.cjs.map
557
1585
  //# sourceMappingURL=index.cjs.map