@alejandroroman/agent-kit 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 (169) hide show
  1. package/dist/_memory/config.d.ts +14 -0
  2. package/dist/_memory/config.js +16 -0
  3. package/dist/_memory/db/client.d.ts +2 -0
  4. package/dist/_memory/db/client.js +15 -0
  5. package/dist/_memory/db/schema.d.ts +14 -0
  6. package/dist/_memory/db/schema.js +51 -0
  7. package/dist/_memory/embeddings/ollama.d.ts +12 -0
  8. package/dist/_memory/embeddings/ollama.js +22 -0
  9. package/dist/_memory/embeddings/provider.d.ts +4 -0
  10. package/dist/_memory/embeddings/provider.js +1 -0
  11. package/dist/_memory/index.d.ts +10 -0
  12. package/dist/_memory/index.js +6 -0
  13. package/dist/_memory/search.d.ts +30 -0
  14. package/dist/_memory/search.js +121 -0
  15. package/dist/_memory/server.d.ts +8 -0
  16. package/dist/_memory/server.js +126 -0
  17. package/dist/_memory/store.d.ts +51 -0
  18. package/dist/_memory/store.js +115 -0
  19. package/dist/agent/loop.d.ts +3 -0
  20. package/dist/agent/loop.js +195 -0
  21. package/dist/agent/setup.d.ts +6 -0
  22. package/dist/agent/setup.js +11 -0
  23. package/dist/agent/soul.d.ts +1 -0
  24. package/dist/agent/soul.js +8 -0
  25. package/dist/agent/types.d.ts +23 -0
  26. package/dist/agent/types.js +1 -0
  27. package/dist/api/agents.d.ts +2 -0
  28. package/dist/api/agents.js +43 -0
  29. package/dist/api/config.d.ts +2 -0
  30. package/dist/api/config.js +20 -0
  31. package/dist/api/cron.d.ts +2 -0
  32. package/dist/api/cron.js +15 -0
  33. package/dist/api/health.d.ts +2 -0
  34. package/dist/api/health.js +8 -0
  35. package/dist/api/logs.d.ts +5 -0
  36. package/dist/api/logs.js +28 -0
  37. package/dist/api/router.d.ts +6 -0
  38. package/dist/api/router.js +80 -0
  39. package/dist/api/sessions.d.ts +2 -0
  40. package/dist/api/sessions.js +67 -0
  41. package/dist/api/types.d.ts +12 -0
  42. package/dist/api/types.js +13 -0
  43. package/dist/api/usage.d.ts +3 -0
  44. package/dist/api/usage.js +50 -0
  45. package/dist/bootstrap.d.ts +51 -0
  46. package/dist/bootstrap.js +110 -0
  47. package/dist/cli/chat.d.ts +1 -0
  48. package/dist/cli/chat.js +102 -0
  49. package/dist/cli/config-writer.d.ts +40 -0
  50. package/dist/cli/config-writer.js +108 -0
  51. package/dist/cli/create.d.ts +1 -0
  52. package/dist/cli/create.js +37 -0
  53. package/dist/cli/init.d.ts +1 -0
  54. package/dist/cli/init.js +85 -0
  55. package/dist/cli/list.d.ts +1 -0
  56. package/dist/cli/list.js +36 -0
  57. package/dist/cli/ollama.d.ts +6 -0
  58. package/dist/cli/ollama.js +44 -0
  59. package/dist/cli/setup-agent/index.d.ts +9 -0
  60. package/dist/cli/setup-agent/index.js +100 -0
  61. package/dist/cli/setup-agent/soul.d.ts +2 -0
  62. package/dist/cli/setup-agent/soul.js +79 -0
  63. package/dist/cli/setup-agent/tools.d.ts +9 -0
  64. package/dist/cli/setup-agent/tools.js +362 -0
  65. package/dist/cli/start.d.ts +1 -0
  66. package/dist/cli/start.js +235 -0
  67. package/dist/cli/ui.d.ts +17 -0
  68. package/dist/cli/ui.js +79 -0
  69. package/dist/cli/validate.d.ts +1 -0
  70. package/dist/cli/validate.js +47 -0
  71. package/dist/cli.d.ts +4 -0
  72. package/dist/cli.js +59 -0
  73. package/dist/config/index.d.ts +4 -0
  74. package/dist/config/index.js +3 -0
  75. package/dist/config/loader.d.ts +2 -0
  76. package/dist/config/loader.js +10 -0
  77. package/dist/config/resolve.d.ts +22 -0
  78. package/dist/config/resolve.js +45 -0
  79. package/dist/config/schema.d.ts +217 -0
  80. package/dist/config/schema.js +159 -0
  81. package/dist/cron/scheduler.d.ts +22 -0
  82. package/dist/cron/scheduler.js +115 -0
  83. package/dist/gateways/slack/client.d.ts +13 -0
  84. package/dist/gateways/slack/client.js +44 -0
  85. package/dist/gateways/slack/format.d.ts +30 -0
  86. package/dist/gateways/slack/format.js +170 -0
  87. package/dist/gateways/slack/handler.d.ts +9 -0
  88. package/dist/gateways/slack/handler.js +95 -0
  89. package/dist/gateways/slack/index.d.ts +16 -0
  90. package/dist/gateways/slack/index.js +102 -0
  91. package/dist/gateways/slack/listener.d.ts +10 -0
  92. package/dist/gateways/slack/listener.js +35 -0
  93. package/dist/gateways/slack/sessions.d.ts +11 -0
  94. package/dist/gateways/slack/sessions.js +32 -0
  95. package/dist/gateways/slack/types.d.ts +13 -0
  96. package/dist/gateways/slack/types.js +7 -0
  97. package/dist/heartbeat/index.d.ts +2 -0
  98. package/dist/heartbeat/index.js +1 -0
  99. package/dist/heartbeat/runner.d.ts +31 -0
  100. package/dist/heartbeat/runner.js +215 -0
  101. package/dist/index.d.ts +1 -0
  102. package/dist/index.js +207 -0
  103. package/dist/llm/anthropic.d.ts +12 -0
  104. package/dist/llm/anthropic.js +89 -0
  105. package/dist/llm/fallback.d.ts +6 -0
  106. package/dist/llm/fallback.js +30 -0
  107. package/dist/llm/index.d.ts +9 -0
  108. package/dist/llm/index.js +40 -0
  109. package/dist/llm/openai.d.ts +12 -0
  110. package/dist/llm/openai.js +85 -0
  111. package/dist/llm/provider.d.ts +12 -0
  112. package/dist/llm/provider.js +9 -0
  113. package/dist/llm/types.d.ts +73 -0
  114. package/dist/llm/types.js +6 -0
  115. package/dist/logger.d.ts +2 -0
  116. package/dist/logger.js +15 -0
  117. package/dist/multi/registry.d.ts +15 -0
  118. package/dist/multi/registry.js +28 -0
  119. package/dist/multi/spawn.d.ts +14 -0
  120. package/dist/multi/spawn.js +14 -0
  121. package/dist/scripts/validate-agent-cli.d.ts +1 -0
  122. package/dist/scripts/validate-agent-cli.js +47 -0
  123. package/dist/scripts/validate-agent.d.ts +17 -0
  124. package/dist/scripts/validate-agent.js +242 -0
  125. package/dist/session/compaction.d.ts +4 -0
  126. package/dist/session/compaction.js +30 -0
  127. package/dist/session/manager.d.ts +9 -0
  128. package/dist/session/manager.js +41 -0
  129. package/dist/skills/activate.d.ts +11 -0
  130. package/dist/skills/activate.js +62 -0
  131. package/dist/skills/index.d.ts +3 -0
  132. package/dist/skills/index.js +3 -0
  133. package/dist/skills/loader.d.ts +3 -0
  134. package/dist/skills/loader.js +20 -0
  135. package/dist/skills/schema.d.ts +8 -0
  136. package/dist/skills/schema.js +7 -0
  137. package/dist/text.d.ts +8 -0
  138. package/dist/text.js +24 -0
  139. package/dist/tools/builtin/index.d.ts +21 -0
  140. package/dist/tools/builtin/index.js +21 -0
  141. package/dist/tools/builtin/memory.d.ts +8 -0
  142. package/dist/tools/builtin/memory.js +164 -0
  143. package/dist/tools/builtin/read-file.d.ts +3 -0
  144. package/dist/tools/builtin/read-file.js +30 -0
  145. package/dist/tools/builtin/run-command.d.ts +3 -0
  146. package/dist/tools/builtin/run-command.js +37 -0
  147. package/dist/tools/builtin/spawn.d.ts +15 -0
  148. package/dist/tools/builtin/spawn.js +59 -0
  149. package/dist/tools/builtin/web-search.d.ts +8 -0
  150. package/dist/tools/builtin/web-search.js +99 -0
  151. package/dist/tools/builtin/write-file.d.ts +3 -0
  152. package/dist/tools/builtin/write-file.js +34 -0
  153. package/dist/tools/registry.d.ts +10 -0
  154. package/dist/tools/registry.js +26 -0
  155. package/dist/tools/sandbox.d.ts +9 -0
  156. package/dist/tools/sandbox.js +74 -0
  157. package/dist/tools/types.d.ts +8 -0
  158. package/dist/tools/types.js +7 -0
  159. package/dist/usage/index.d.ts +4 -0
  160. package/dist/usage/index.js +3 -0
  161. package/dist/usage/pricing.d.ts +10 -0
  162. package/dist/usage/pricing.js +35 -0
  163. package/dist/usage/schema.d.ts +1 -0
  164. package/dist/usage/schema.js +45 -0
  165. package/dist/usage/store.d.ts +10 -0
  166. package/dist/usage/store.js +227 -0
  167. package/dist/usage/types.d.ts +61 -0
  168. package/dist/usage/types.js +1 -0
  169. package/package.json +53 -0
@@ -0,0 +1,51 @@
1
+ import { AgentRegistry } from "./multi/registry.js";
2
+ import { type UsageStore } from "./usage/index.js";
3
+ import type { Config } from "./config/schema.js";
4
+ import type { ToolRegistry } from "./tools/registry.js";
5
+ import type { Message } from "./llm/types.js";
6
+ import type { AgentResult } from "./agent/types.js";
7
+ import type { ResolvedAgent } from "./config/resolve.js";
8
+ import type { SessionManager } from "./session/manager.js";
9
+ export interface AgentRuntime {
10
+ resolved: ResolvedAgent;
11
+ toolRegistry: ToolRegistry;
12
+ agentRegistry: AgentRegistry;
13
+ promptFragments: string[];
14
+ skillsIndex: string;
15
+ soul: string | undefined;
16
+ session: SessionManager;
17
+ }
18
+ export interface AgentExecutorFn {
19
+ (agentName: string, messages: Message[]): Promise<AgentResult>;
20
+ }
21
+ /**
22
+ * Build a fully-initialized agent runtime: tool registry, skills, spawn wrappers, session.
23
+ */
24
+ export declare function buildAgentRuntime(agentName: string, config: Config, opts: {
25
+ dataDir: string;
26
+ skillsDir: string;
27
+ sessionId?: string;
28
+ usageStore?: UsageStore;
29
+ }): AgentRuntime;
30
+ /**
31
+ * Assemble a system prompt from soul, date context, skills index, and prompt fragments.
32
+ */
33
+ export declare function buildSystemPrompt(soul: string | undefined, skillsIndex: string, promptFragments: string[]): string | undefined;
34
+ /**
35
+ * Initialize usage store if configured. Returns store + API port.
36
+ */
37
+ export declare function initUsageStore(config: Config): {
38
+ usageStore?: UsageStore;
39
+ apiPort: number;
40
+ };
41
+ /**
42
+ * Create an agent executor function (for Slack gateway, etc.).
43
+ * Each invocation gets its own isolated tool registry.
44
+ */
45
+ export declare function createAgentExecutor(config: Config, opts: {
46
+ dataDir: string;
47
+ skillsDir: string;
48
+ agentRegistry: AgentRegistry;
49
+ usageStore?: UsageStore;
50
+ source: string;
51
+ }): AgentExecutorFn;
@@ -0,0 +1,110 @@
1
+ import * as path from "path";
2
+ import * as fs from "fs";
3
+ import { resolveAgent, resolveWebSearch } from "./config/resolve.js";
4
+ import { createBuiltinRegistry } from "./tools/builtin/index.js";
5
+ import { createActivateSkillTool } from "./skills/index.js";
6
+ import { AgentRegistry } from "./multi/registry.js";
7
+ import { registerSpawnWrappers } from "./tools/builtin/spawn.js";
8
+ import { setupAgentSession } from "./agent/setup.js";
9
+ import { runAgentLoop } from "./agent/loop.js";
10
+ import { dateContext } from "./text.js";
11
+ import { createLogger } from "./logger.js";
12
+ import { createUsageStore } from "./usage/index.js";
13
+ const log = createLogger("bootstrap");
14
+ /**
15
+ * Build a fully-initialized agent runtime: tool registry, skills, spawn wrappers, session.
16
+ */
17
+ export function buildAgentRuntime(agentName, config, opts) {
18
+ const agentDef = config.agents[agentName];
19
+ if (!agentDef)
20
+ throw new Error(`Agent "${agentName}" not found in config`);
21
+ const sandbox = agentDef.sandbox ?? config.defaults.sandbox;
22
+ const toolRegistry = createBuiltinRegistry({
23
+ allowedCommands: sandbox?.allowedCommands,
24
+ allowedPaths: sandbox?.allowedPaths,
25
+ memoryConfig: config.defaults.memory,
26
+ webSearch: resolveWebSearch(agentName, config),
27
+ });
28
+ const agentRegistry = new AgentRegistry(config, opts.dataDir);
29
+ const resolved = resolveAgent(agentName, config, toolRegistry, opts.skillsDir);
30
+ // Skills setup
31
+ const promptFragments = [];
32
+ let skillsIndex = "";
33
+ if (resolved.skills.length > 0) {
34
+ const ctx = {
35
+ manifests: resolved.skills,
36
+ skillsDir: opts.skillsDir,
37
+ toolRegistry,
38
+ promptFragments,
39
+ activatedSkills: new Set(),
40
+ };
41
+ toolRegistry.register(createActivateSkillTool(ctx));
42
+ skillsIndex = "\n\nYou have the following skills available:\n\n"
43
+ + resolved.skills.map((s) => `- **${s.name}**: ${s.description}`).join("\n")
44
+ + "\n\nTo use a skill, call the `activate_skill` tool with the skill name.";
45
+ }
46
+ // Spawn wrapper registration
47
+ if (resolved.canSpawn.length > 0) {
48
+ registerSpawnWrappers(resolved.canSpawn, config, agentRegistry, toolRegistry, opts.usageStore);
49
+ log.info({ targets: resolved.canSpawn.map((t) => `${t.tool} -> ${t.agent}`) }, "spawn wrappers registered");
50
+ }
51
+ const sid = opts.sessionId ?? `session-${Date.now()}`;
52
+ const { soul, session } = setupAgentSession(opts.dataDir, agentName, sid);
53
+ return { resolved, toolRegistry, agentRegistry, promptFragments, skillsIndex, soul, session };
54
+ }
55
+ /**
56
+ * Assemble a system prompt from soul, date context, skills index, and prompt fragments.
57
+ */
58
+ export function buildSystemPrompt(soul, skillsIndex, promptFragments) {
59
+ return [soul, dateContext(), skillsIndex, ...promptFragments]
60
+ .filter(Boolean)
61
+ .join("\n\n") || undefined;
62
+ }
63
+ /**
64
+ * Initialize usage store if configured. Returns store + API port.
65
+ */
66
+ export function initUsageStore(config) {
67
+ let usageStore;
68
+ let apiPort = 7878;
69
+ if (config.defaults.usage) {
70
+ try {
71
+ const usageDbPath = config.defaults.usage.dbPath.replace(/^~/, process.env.HOME ?? "~");
72
+ const usageDir = path.dirname(usageDbPath);
73
+ if (!fs.existsSync(usageDir))
74
+ fs.mkdirSync(usageDir, { recursive: true });
75
+ usageStore = createUsageStore(usageDbPath);
76
+ apiPort = config.defaults.usage.apiPort;
77
+ }
78
+ catch (err) {
79
+ log.warn({ err }, "failed to initialize usage tracking — continuing without it");
80
+ }
81
+ }
82
+ return { usageStore, apiPort };
83
+ }
84
+ /**
85
+ * Create an agent executor function (for Slack gateway, etc.).
86
+ * Each invocation gets its own isolated tool registry.
87
+ */
88
+ export function createAgentExecutor(config, opts) {
89
+ return async (agentName, messages) => {
90
+ const runtime = buildAgentRuntime(agentName, config, {
91
+ dataDir: opts.dataDir,
92
+ skillsDir: opts.skillsDir,
93
+ sessionId: `${opts.source}-${Date.now()}`,
94
+ usageStore: opts.usageStore,
95
+ });
96
+ const systemPrompt = buildSystemPrompt(runtime.soul, runtime.skillsIndex, runtime.promptFragments);
97
+ return runAgentLoop(messages, {
98
+ model: runtime.resolved.model,
99
+ fallbacks: runtime.resolved.fallbacks,
100
+ systemPrompt,
101
+ toolRegistry: runtime.toolRegistry,
102
+ maxIterations: runtime.resolved.maxIterations,
103
+ compactionThreshold: runtime.resolved.compactionThreshold,
104
+ maxToolResultSize: runtime.resolved.maxToolResultSize,
105
+ agentName,
106
+ usageStore: opts.usageStore,
107
+ source: opts.source,
108
+ });
109
+ };
110
+ }
@@ -0,0 +1 @@
1
+ export declare function chat(agentName?: string): Promise<void>;
@@ -0,0 +1,102 @@
1
+ import * as readline from "readline";
2
+ import * as path from "path";
3
+ import { loadConfig } from "../config/index.js";
4
+ import { buildAgentRuntime, buildSystemPrompt } from "../bootstrap.js";
5
+ import { runAgentLoop } from "../agent/loop.js";
6
+ import { compactMessages } from "../session/compaction.js";
7
+ import { ensureOllama } from "./ollama.js";
8
+ import { resolveApiKey } from "./ui.js";
9
+ const CONFIG_PATH = path.join(process.cwd(), "agent-kit.json");
10
+ const DATA_DIR = path.join(process.cwd(), "data");
11
+ const SKILLS_DIR = path.join(process.cwd(), "skills");
12
+ export async function chat(agentName) {
13
+ if (!agentName) {
14
+ console.error("Usage: agent-kit chat <agent>");
15
+ process.exit(1);
16
+ }
17
+ await resolveApiKey({ save: false });
18
+ const config = loadConfig(CONFIG_PATH);
19
+ if (!config.agents[agentName]) {
20
+ const names = Object.keys(config.agents).join(", ");
21
+ console.error(`Agent "${agentName}" not found. Available: ${names}`);
22
+ process.exit(1);
23
+ }
24
+ // Warn if Ollama isn't running (memory tools won't work)
25
+ if (config.defaults.memory) {
26
+ const ollama = await ensureOllama();
27
+ if (!ollama.running) {
28
+ console.log(" (Ollama not running — memory tools unavailable)\n");
29
+ }
30
+ }
31
+ const runtime = buildAgentRuntime(agentName, config, {
32
+ dataDir: DATA_DIR,
33
+ skillsDir: SKILLS_DIR,
34
+ });
35
+ const { resolved, toolRegistry, promptFragments, skillsIndex, soul, session } = runtime;
36
+ const agentDef = config.agents[agentName];
37
+ const emoji = agentDef.emoji ?? "";
38
+ const display = agentDef.displayName ?? agentName;
39
+ console.log();
40
+ console.log(` ${emoji} ${display}`);
41
+ console.log(` Model: ${resolved.model}`);
42
+ console.log(` Tools: ${resolved.tools.map((t) => t.name).join(", ") || "(none)"}`);
43
+ if (resolved.skills.length > 0) {
44
+ console.log(` Skills: ${resolved.skills.map((s) => s.name).join(", ")}`);
45
+ }
46
+ console.log(` Commands: /new (reset), /quit`);
47
+ console.log();
48
+ let messages = session.getMessages();
49
+ const rl = readline.createInterface({
50
+ input: process.stdin,
51
+ output: process.stdout,
52
+ });
53
+ const ask = () => {
54
+ rl.question("You: ", async (input) => {
55
+ const trimmed = input.trim();
56
+ if (trimmed === "/quit") {
57
+ rl.close();
58
+ return;
59
+ }
60
+ if (trimmed === "/new") {
61
+ messages = [];
62
+ console.log(" Session reset.\n");
63
+ ask();
64
+ return;
65
+ }
66
+ if (!trimmed) {
67
+ ask();
68
+ return;
69
+ }
70
+ const userMsg = { role: "user", content: trimmed };
71
+ messages.push(userMsg);
72
+ session.append(userMsg);
73
+ messages = await compactMessages(messages, resolved.model, resolved.compactionThreshold);
74
+ try {
75
+ const systemPrompt = buildSystemPrompt(soul, skillsIndex, promptFragments);
76
+ const result = await runAgentLoop(messages, {
77
+ model: resolved.model,
78
+ fallbacks: resolved.fallbacks,
79
+ systemPrompt,
80
+ toolRegistry,
81
+ maxIterations: resolved.maxIterations,
82
+ compactionThreshold: resolved.compactionThreshold,
83
+ maxToolResultSize: resolved.maxToolResultSize,
84
+ agentName,
85
+ source: "cli",
86
+ });
87
+ const newMessages = result.messages.slice(messages.length - 1);
88
+ for (const msg of newMessages) {
89
+ session.append(msg);
90
+ }
91
+ messages = result.messages;
92
+ console.log(`\nAgent: ${result.text}`);
93
+ console.log(` (${result.usage.inputTokens + result.usage.outputTokens} tokens)\n`);
94
+ }
95
+ catch (err) {
96
+ console.error(`\n Error: ${err instanceof Error ? err.message : err}\n`);
97
+ }
98
+ ask();
99
+ });
100
+ };
101
+ ask();
102
+ }
@@ -0,0 +1,40 @@
1
+ import { type Config } from "../config/schema.js";
2
+ /**
3
+ * Read raw JSON from config file (no Zod defaults expansion).
4
+ * Returns parsed object or null if file doesn't exist.
5
+ */
6
+ export declare function readRawConfig(configPath: string): Record<string, unknown> | null;
7
+ /**
8
+ * Atomically write config JSON. Validates with ConfigSchema before writing.
9
+ * Writes to .tmp file, then renames for atomicity.
10
+ */
11
+ export declare function writeConfig(configPath: string, raw: Record<string, unknown>): Config;
12
+ /**
13
+ * Create a fresh minimal config for `agent-kit init`.
14
+ */
15
+ export declare function createFreshConfig(opts: {
16
+ configPath: string;
17
+ models?: Array<{
18
+ model: string;
19
+ alias: string;
20
+ }>;
21
+ defaultModel?: string;
22
+ }): Config;
23
+ /**
24
+ * Add or update an agent in the config file.
25
+ * Mutates the raw JSON (no Zod default expansion).
26
+ */
27
+ export declare function upsertAgent(configPath: string, agentName: string, agentDef: Record<string, unknown>): Config;
28
+ /**
29
+ * Add a cron job to the config file.
30
+ */
31
+ export declare function addCronJob(configPath: string, job: Record<string, unknown>): Config;
32
+ /**
33
+ * Ensure data directories exist for an agent.
34
+ */
35
+ export declare function ensureAgentDirs(dataDir: string, agentName: string): void;
36
+ /**
37
+ * Scaffold a package.json for a new agent-kit project.
38
+ * Makes the project self-contained and runnable via `npx agent-kit start`.
39
+ */
40
+ export declare function scaffoldProjectPackageJson(projectDir: string, projectName?: string): void;
@@ -0,0 +1,108 @@
1
+ import * as fs from "fs";
2
+ import * as path from "path";
3
+ import { ConfigSchema } from "../config/schema.js";
4
+ /**
5
+ * Read raw JSON from config file (no Zod defaults expansion).
6
+ * Returns parsed object or null if file doesn't exist.
7
+ */
8
+ export function readRawConfig(configPath) {
9
+ if (!fs.existsSync(configPath))
10
+ return null;
11
+ return JSON.parse(fs.readFileSync(configPath, "utf-8"));
12
+ }
13
+ /**
14
+ * Atomically write config JSON. Validates with ConfigSchema before writing.
15
+ * Writes to .tmp file, then renames for atomicity.
16
+ */
17
+ export function writeConfig(configPath, raw) {
18
+ const validated = ConfigSchema.parse(raw);
19
+ const tmpPath = configPath + ".tmp";
20
+ fs.writeFileSync(tmpPath, JSON.stringify(raw, null, 2) + "\n", "utf-8");
21
+ fs.renameSync(tmpPath, configPath);
22
+ return validated;
23
+ }
24
+ /**
25
+ * Create a fresh minimal config for `agent-kit init`.
26
+ */
27
+ export function createFreshConfig(opts) {
28
+ const raw = {
29
+ models: opts.models ?? [
30
+ { model: "anthropic:claude-sonnet-4-6", alias: "sonnet" },
31
+ ],
32
+ defaults: {
33
+ model: opts.defaultModel ?? "sonnet",
34
+ maxTokens: 4096,
35
+ maxIterations: 20,
36
+ compactionThreshold: 100_000,
37
+ commandTimeout: 30,
38
+ },
39
+ agents: {},
40
+ cron: [],
41
+ };
42
+ return writeConfig(opts.configPath, raw);
43
+ }
44
+ /**
45
+ * Add or update an agent in the config file.
46
+ * Mutates the raw JSON (no Zod default expansion).
47
+ */
48
+ export function upsertAgent(configPath, agentName, agentDef) {
49
+ const raw = readRawConfig(configPath);
50
+ if (!raw)
51
+ throw new Error("Config file not found");
52
+ if (!raw.agents || typeof raw.agents !== "object") {
53
+ raw.agents = {};
54
+ }
55
+ raw.agents[agentName] = agentDef;
56
+ return writeConfig(configPath, raw);
57
+ }
58
+ /**
59
+ * Add a cron job to the config file.
60
+ */
61
+ export function addCronJob(configPath, job) {
62
+ const raw = readRawConfig(configPath);
63
+ if (!raw)
64
+ throw new Error("Config file not found");
65
+ if (!Array.isArray(raw.cron)) {
66
+ raw.cron = [];
67
+ }
68
+ raw.cron.push(job);
69
+ return writeConfig(configPath, raw);
70
+ }
71
+ /**
72
+ * Ensure data directories exist for an agent.
73
+ */
74
+ export function ensureAgentDirs(dataDir, agentName) {
75
+ const agentDir = path.join(dataDir, "agents", agentName);
76
+ const sessionsDir = path.join(agentDir, "sessions");
77
+ fs.mkdirSync(sessionsDir, { recursive: true });
78
+ }
79
+ /**
80
+ * Scaffold a package.json for a new agent-kit project.
81
+ * Makes the project self-contained and runnable via `npx agent-kit start`.
82
+ */
83
+ export function scaffoldProjectPackageJson(projectDir, projectName) {
84
+ const pkgPath = path.join(projectDir, "package.json");
85
+ if (fs.existsSync(pkgPath))
86
+ return; // don't overwrite existing
87
+ const name = projectName ?? path.basename(projectDir);
88
+ const pkg = {
89
+ name,
90
+ version: "0.1.0",
91
+ private: true,
92
+ type: "module",
93
+ scripts: {
94
+ start: "agent-kit start",
95
+ chat: "agent-kit chat",
96
+ create: "agent-kit create",
97
+ },
98
+ dependencies: {
99
+ "@alejandroroman/agent-kit": "^0.1.0",
100
+ },
101
+ };
102
+ fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf-8");
103
+ // Create .gitignore if missing
104
+ const gitignorePath = path.join(projectDir, ".gitignore");
105
+ if (!fs.existsSync(gitignorePath)) {
106
+ fs.writeFileSync(gitignorePath, "node_modules/\n.env\n*.db\n*.db-shm\n*.db-wal\n", "utf-8");
107
+ }
108
+ }
@@ -0,0 +1 @@
1
+ export declare function create(): Promise<void>;
@@ -0,0 +1,37 @@
1
+ import * as fs from "fs";
2
+ import * as path from "path";
3
+ import * as p from "@clack/prompts";
4
+ import { banner, done, resolveApiKey } from "./ui.js";
5
+ import { loadConfig } from "../config/index.js";
6
+ import { runSetupAgent } from "./setup-agent/index.js";
7
+ const CONFIG_PATH = path.join(process.cwd(), "agent-kit.json");
8
+ const DATA_DIR = path.join(process.cwd(), "data");
9
+ const SKILLS_DIR = path.join(process.cwd(), "skills");
10
+ export async function create() {
11
+ banner();
12
+ // Require existing config
13
+ if (!fs.existsSync(CONFIG_PATH)) {
14
+ p.log.error("No agent-kit.json found. Run `agent-kit init` first.");
15
+ process.exit(1);
16
+ }
17
+ // Load config to verify it's valid
18
+ try {
19
+ loadConfig(CONFIG_PATH);
20
+ }
21
+ catch (err) {
22
+ p.log.error(`Invalid config: ${err instanceof Error ? err.message : err}`);
23
+ process.exit(1);
24
+ }
25
+ const apiKey = await resolveApiKey({ save: true });
26
+ p.log.info("Starting setup wizard... (type /quit to exit)\n");
27
+ const summary = await runSetupAgent({
28
+ apiKey,
29
+ configPath: CONFIG_PATH,
30
+ dataDir: DATA_DIR,
31
+ skillsDir: SKILLS_DIR,
32
+ basePath: process.cwd(),
33
+ mode: "create",
34
+ });
35
+ console.log();
36
+ done(summary);
37
+ }
@@ -0,0 +1 @@
1
+ export declare function init(): Promise<void>;
@@ -0,0 +1,85 @@
1
+ import * as fs from "fs";
2
+ import * as path from "path";
3
+ import { execSync } from "child_process";
4
+ import * as p from "@clack/prompts";
5
+ import { banner, isCancel, done, resolveApiKey } from "./ui.js";
6
+ import { checkOllama } from "./ollama.js";
7
+ import { createFreshConfig, scaffoldProjectPackageJson } from "./config-writer.js";
8
+ import { runSetupAgent } from "./setup-agent/index.js";
9
+ const CONFIG_PATH = path.join(process.cwd(), "agent-kit.json");
10
+ const DATA_DIR = path.join(process.cwd(), "data");
11
+ const SKILLS_DIR = path.join(process.cwd(), "skills");
12
+ function detectPackageManager() {
13
+ try {
14
+ execSync("pnpm --version", { stdio: "ignore" });
15
+ return "pnpm";
16
+ }
17
+ catch {
18
+ return "npm";
19
+ }
20
+ }
21
+ export async function init() {
22
+ banner();
23
+ // Check if config already exists
24
+ if (fs.existsSync(CONFIG_PATH)) {
25
+ p.log.error("agent-kit.json already exists. Use `agent-kit create` to add agents.");
26
+ process.exit(1);
27
+ }
28
+ // Detect or ask for API key (with save-to-.env offer)
29
+ const apiKey = await resolveApiKey({ save: true });
30
+ // Check Ollama status
31
+ const s = p.spinner();
32
+ s.start("Checking Ollama...");
33
+ const ollama = await checkOllama();
34
+ s.stop(ollama.running
35
+ ? "Ollama is running"
36
+ : ollama.installed
37
+ ? "Ollama installed but not running (memory tools will be unavailable until started)"
38
+ : "Ollama not found (memory tools require it — install from ollama.com)");
39
+ // Scaffold project
40
+ s.start("Setting up project...");
41
+ try {
42
+ scaffoldProjectPackageJson(process.cwd());
43
+ createFreshConfig({ configPath: CONFIG_PATH });
44
+ fs.mkdirSync(DATA_DIR, { recursive: true });
45
+ fs.mkdirSync(SKILLS_DIR, { recursive: true });
46
+ }
47
+ catch (err) {
48
+ s.stop(`Failed to create project: ${err instanceof Error ? err.message : err}`);
49
+ process.exit(1);
50
+ }
51
+ s.stop("Project created");
52
+ // Install dependencies
53
+ const pm = detectPackageManager();
54
+ s.start(`Installing dependencies (${pm} install)...`);
55
+ try {
56
+ execSync(`${pm} install`, { cwd: process.cwd(), stdio: "ignore" });
57
+ }
58
+ catch (err) {
59
+ s.stop(`Failed to install dependencies: ${err instanceof Error ? err.message : err}`);
60
+ p.log.warn("You can install manually later with: npm install");
61
+ }
62
+ s.stop("Dependencies installed");
63
+ // Ask if they want to create agents now
64
+ const createNow = await p.confirm({
65
+ message: "Create your first agent now? (AI-powered setup)",
66
+ });
67
+ if (isCancel(createNow))
68
+ return;
69
+ if (!createNow) {
70
+ done("Setup complete. Run `agent-kit create` to add agents later.");
71
+ return;
72
+ }
73
+ // Boot the setup agent
74
+ p.log.info("Starting setup wizard... (type /quit to exit)\n");
75
+ const summary = await runSetupAgent({
76
+ apiKey,
77
+ configPath: CONFIG_PATH,
78
+ dataDir: DATA_DIR,
79
+ skillsDir: SKILLS_DIR,
80
+ basePath: process.cwd(),
81
+ mode: "init",
82
+ });
83
+ console.log();
84
+ done(summary);
85
+ }
@@ -0,0 +1 @@
1
+ export declare function list(): void;
@@ -0,0 +1,36 @@
1
+ import * as path from "path";
2
+ import { loadConfig } from "../config/index.js";
3
+ const CONFIG_PATH = path.join(process.cwd(), "agent-kit.json");
4
+ export function list() {
5
+ const config = loadConfig(CONFIG_PATH);
6
+ const agents = Object.entries(config.agents);
7
+ if (agents.length === 0) {
8
+ console.log("No agents configured. Run `agent-kit init` to get started.");
9
+ return;
10
+ }
11
+ console.log();
12
+ console.log(" Agents:");
13
+ console.log();
14
+ for (const [name, def] of agents) {
15
+ const emoji = def.emoji ?? " ";
16
+ const display = def.displayName ?? name;
17
+ const model = def.model ?? config.defaults.model;
18
+ const tags = [];
19
+ if (def.spawn_only)
20
+ tags.push("spawn-only");
21
+ if (def.slack)
22
+ tags.push(`slack:${def.slack.channelName}`);
23
+ if (def.heartbeat?.enabled)
24
+ tags.push("heartbeat");
25
+ if (def.skills.length > 0)
26
+ tags.push(`${def.skills.length} skill(s)`);
27
+ const cronJobs = config.cron.filter((j) => j.agent === name && j.enabled);
28
+ if (cronJobs.length > 0)
29
+ tags.push(`${cronJobs.length} cron`);
30
+ const tagStr = tags.length > 0 ? ` [${tags.join(", ")}]` : "";
31
+ console.log(` ${emoji} ${display} (${name}) model:${model} tools:${def.tools.length}${tagStr}`);
32
+ }
33
+ console.log();
34
+ console.log(` ${agents.length} agent(s), ${config.cron.length} cron job(s)`);
35
+ console.log();
36
+ }
@@ -0,0 +1,6 @@
1
+ export interface OllamaStatus {
2
+ running: boolean;
3
+ installed: boolean;
4
+ }
5
+ export declare function checkOllama(): Promise<OllamaStatus>;
6
+ export declare function ensureOllama(): Promise<OllamaStatus>;
@@ -0,0 +1,44 @@
1
+ import { execSync, spawn } from "child_process";
2
+ const OLLAMA_URL = "http://localhost:11434";
3
+ export async function checkOllama() {
4
+ // Check if running
5
+ try {
6
+ const res = await fetch(`${OLLAMA_URL}/api/version`, { signal: AbortSignal.timeout(2000) });
7
+ if (res.ok)
8
+ return { running: true, installed: true };
9
+ }
10
+ catch {
11
+ // Not running — check if installed
12
+ }
13
+ try {
14
+ execSync("which ollama", { stdio: "ignore" });
15
+ return { running: false, installed: true };
16
+ }
17
+ catch {
18
+ return { running: false, installed: false };
19
+ }
20
+ }
21
+ export async function ensureOllama() {
22
+ const status = await checkOllama();
23
+ if (status.running)
24
+ return status;
25
+ if (status.installed) {
26
+ // Try to start it
27
+ const child = spawn("ollama", ["serve"], {
28
+ detached: true,
29
+ stdio: "ignore",
30
+ });
31
+ child.unref();
32
+ // Give it a moment to start
33
+ await new Promise((r) => setTimeout(r, 1500));
34
+ try {
35
+ const res = await fetch(`${OLLAMA_URL}/api/version`, { signal: AbortSignal.timeout(2000) });
36
+ if (res.ok)
37
+ return { running: true, installed: true };
38
+ }
39
+ catch {
40
+ // Failed to start
41
+ }
42
+ }
43
+ return status;
44
+ }
@@ -0,0 +1,9 @@
1
+ export interface RunSetupAgentOptions {
2
+ apiKey: string;
3
+ configPath: string;
4
+ dataDir: string;
5
+ skillsDir: string;
6
+ basePath: string;
7
+ mode: "init" | "create";
8
+ }
9
+ export declare function runSetupAgent(opts: RunSetupAgentOptions): Promise<string>;