@aman_asmuei/aman-agent 0.1.0 → 0.2.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.js CHANGED
@@ -30,69 +30,207 @@ function saveConfig(config) {
30
30
  import fs2 from "fs";
31
31
  import path2 from "path";
32
32
  import os2 from "os";
33
- function assembleSystemPrompt() {
34
- const home = os2.homedir();
35
- const layers = [];
33
+
34
+ // src/token-budget.ts
35
+ function estimateTokens(text2) {
36
+ return Math.round(text2.split(/\s+/).filter(Boolean).length * 1.3);
37
+ }
38
+ var PRIORITIES = [
39
+ "identity",
40
+ // core.md — always include
41
+ "guardrails",
42
+ // rules.md — safety critical
43
+ "workflows",
44
+ // flow.md — behavioral
45
+ "tools",
46
+ // kit.md — capabilities
47
+ "skills"
48
+ // skills.md — can be truncated
49
+ ];
50
+ function buildBudgetedPrompt(components, maxTokens = 8e3) {
51
+ const included = [];
52
+ const truncated = [];
36
53
  const parts = [];
37
- const corePath = path2.join(home, ".acore", "core.md");
38
- if (fs2.existsSync(corePath)) {
39
- parts.push(fs2.readFileSync(corePath, "utf-8").trim());
40
- layers.push("identity");
54
+ let totalTokens = 0;
55
+ const sorted = [...components].sort((a, b) => {
56
+ const aPri = PRIORITIES.indexOf(a.name);
57
+ const bPri = PRIORITIES.indexOf(b.name);
58
+ return (aPri === -1 ? 99 : aPri) - (bPri === -1 ? 99 : bPri);
59
+ });
60
+ for (const comp of sorted) {
61
+ if (totalTokens + comp.tokens <= maxTokens) {
62
+ parts.push(comp.content);
63
+ included.push(comp.name);
64
+ totalTokens += comp.tokens;
65
+ } else {
66
+ const halfContent = comp.content.slice(0, Math.floor(comp.content.length / 2));
67
+ const halfTokens = estimateTokens(halfContent);
68
+ if (totalTokens + halfTokens <= maxTokens) {
69
+ parts.push(halfContent + "\n\n[... truncated for context budget ...]");
70
+ included.push(comp.name + " (partial)");
71
+ totalTokens += halfTokens;
72
+ } else {
73
+ truncated.push(comp.name);
74
+ }
75
+ }
76
+ }
77
+ return {
78
+ prompt: parts.join("\n\n---\n\n"),
79
+ included,
80
+ truncated,
81
+ totalTokens
82
+ };
83
+ }
84
+
85
+ // src/prompt.ts
86
+ var ECOSYSTEM_FILES = [
87
+ { name: "identity", dir: ".acore", file: "core.md" },
88
+ { name: "tools", dir: ".akit", file: "kit.md" },
89
+ { name: "workflows", dir: ".aflow", file: "flow.md" },
90
+ { name: "guardrails", dir: ".arules", file: "rules.md" },
91
+ { name: "skills", dir: ".askill", file: "skills.md" }
92
+ ];
93
+ function assembleSystemPrompt(maxTokens) {
94
+ const home = os2.homedir();
95
+ const components = [];
96
+ for (const entry of ECOSYSTEM_FILES) {
97
+ const filePath = path2.join(home, entry.dir, entry.file);
98
+ if (fs2.existsSync(filePath)) {
99
+ const content = fs2.readFileSync(filePath, "utf-8").trim();
100
+ components.push({
101
+ name: entry.name,
102
+ content,
103
+ tokens: estimateTokens(content)
104
+ });
105
+ }
41
106
  }
42
107
  const contextPath = path2.join(process.cwd(), ".acore", "context.md");
43
108
  if (fs2.existsSync(contextPath)) {
44
- parts.push(fs2.readFileSync(contextPath, "utf-8").trim());
45
- }
46
- const kitPath = path2.join(home, ".akit", "kit.md");
47
- if (fs2.existsSync(kitPath)) {
48
- parts.push(fs2.readFileSync(kitPath, "utf-8").trim());
49
- layers.push("tools");
50
- }
51
- const flowPath = path2.join(home, ".aflow", "flow.md");
52
- if (fs2.existsSync(flowPath)) {
53
- parts.push(fs2.readFileSync(flowPath, "utf-8").trim());
54
- layers.push("workflows");
55
- }
56
- const rulesPath = path2.join(home, ".arules", "rules.md");
57
- if (fs2.existsSync(rulesPath)) {
58
- parts.push(fs2.readFileSync(rulesPath, "utf-8").trim());
59
- layers.push("guardrails");
60
- }
61
- const skillsPath = path2.join(home, ".askill", "skills.md");
62
- if (fs2.existsSync(skillsPath)) {
63
- parts.push(fs2.readFileSync(skillsPath, "utf-8").trim());
64
- layers.push("skills");
109
+ const content = fs2.readFileSync(contextPath, "utf-8").trim();
110
+ components.push({
111
+ name: "context",
112
+ content,
113
+ tokens: estimateTokens(content)
114
+ });
65
115
  }
116
+ const budgeted = buildBudgetedPrompt(components, maxTokens);
66
117
  return {
67
- prompt: parts.join("\n\n---\n\n"),
68
- layers
118
+ prompt: budgeted.prompt,
119
+ layers: budgeted.included,
120
+ truncated: budgeted.truncated,
121
+ totalTokens: budgeted.totalTokens
69
122
  };
70
123
  }
71
124
 
72
125
  // src/llm/anthropic.ts
73
126
  import Anthropic from "@anthropic-ai/sdk";
127
+ function toAnthropicMessages(messages) {
128
+ return messages.map((m) => {
129
+ if (typeof m.content === "string") {
130
+ return { role: m.role, content: m.content };
131
+ }
132
+ return {
133
+ role: m.role,
134
+ content: m.content.map((block) => {
135
+ if (block.type === "text") {
136
+ return { type: "text", text: block.text };
137
+ }
138
+ if (block.type === "tool_use") {
139
+ return {
140
+ type: "tool_use",
141
+ id: block.id,
142
+ name: block.name,
143
+ input: block.input
144
+ };
145
+ }
146
+ if (block.type === "tool_result") {
147
+ return {
148
+ type: "tool_result",
149
+ tool_use_id: block.tool_use_id,
150
+ content: block.content
151
+ };
152
+ }
153
+ return { type: "text", text: "" };
154
+ })
155
+ };
156
+ });
157
+ }
74
158
  function createAnthropicClient(apiKey, model) {
75
159
  const client = new Anthropic({ apiKey });
76
160
  return {
77
- async chat(systemPrompt, messages, onChunk) {
78
- let fullText = "";
161
+ async chat(systemPrompt, messages, onChunk, tools) {
162
+ const anthropicMessages = toAnthropicMessages(messages);
163
+ const hasTools = tools && tools.length > 0;
79
164
  try {
80
- const stream = await client.messages.create({
81
- model,
82
- max_tokens: 8192,
83
- system: systemPrompt,
84
- messages: messages.map((m) => ({
85
- role: m.role,
86
- content: m.content
87
- })),
88
- stream: true
89
- });
90
- for await (const event of stream) {
91
- if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
92
- const text2 = event.delta.text;
93
- fullText += text2;
94
- onChunk({ type: "text", text: text2 });
165
+ if (hasTools) {
166
+ const response = await client.messages.create({
167
+ model,
168
+ max_tokens: 8192,
169
+ system: systemPrompt,
170
+ messages: anthropicMessages,
171
+ tools: tools.map((t) => ({
172
+ name: t.name,
173
+ description: t.description,
174
+ input_schema: t.input_schema
175
+ }))
176
+ });
177
+ const toolUses = response.content.filter(
178
+ (block) => block.type === "tool_use"
179
+ ).map((block) => ({
180
+ id: block.id,
181
+ name: block.name,
182
+ input: block.input
183
+ }));
184
+ const textContent = response.content.filter(
185
+ (block) => block.type === "text"
186
+ ).map((block) => block.text).join("");
187
+ if (textContent && toolUses.length === 0) {
188
+ onChunk({ type: "text", text: textContent });
189
+ onChunk({ type: "done" });
190
+ } else if (textContent) {
191
+ onChunk({ type: "text", text: textContent });
192
+ }
193
+ const contentBlocks = response.content.map(
194
+ (block) => {
195
+ if (block.type === "text") {
196
+ return { type: "text", text: block.text };
197
+ }
198
+ return {
199
+ type: "tool_use",
200
+ id: block.id,
201
+ name: block.name,
202
+ input: block.input
203
+ };
204
+ }
205
+ );
206
+ return {
207
+ message: {
208
+ role: "assistant",
209
+ content: toolUses.length > 0 ? contentBlocks : textContent
210
+ },
211
+ toolUses
212
+ };
213
+ } else {
214
+ let fullText = "";
215
+ const stream = await client.messages.create({
216
+ model,
217
+ max_tokens: 8192,
218
+ system: systemPrompt,
219
+ messages: anthropicMessages,
220
+ stream: true
221
+ });
222
+ for await (const event of stream) {
223
+ if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
224
+ const text2 = event.delta.text;
225
+ fullText += text2;
226
+ onChunk({ type: "text", text: text2 });
227
+ }
95
228
  }
229
+ onChunk({ type: "done" });
230
+ return {
231
+ message: { role: "assistant", content: fullText },
232
+ toolUses: []
233
+ };
96
234
  }
97
235
  } catch (error) {
98
236
  if (error instanceof Anthropic.AuthenticationError) {
@@ -105,18 +243,162 @@ function createAnthropicClient(apiKey, model) {
105
243
  }
106
244
  throw error;
107
245
  }
108
- onChunk({ type: "done" });
109
- return { role: "assistant", content: fullText };
110
246
  }
111
247
  };
112
248
  }
113
249
 
114
250
  // src/llm/openai.ts
115
251
  import OpenAI from "openai";
252
+ function toOpenAIMessages(systemPrompt, messages) {
253
+ const result = [
254
+ { role: "system", content: systemPrompt }
255
+ ];
256
+ for (const m of messages) {
257
+ if (typeof m.content === "string") {
258
+ result.push({
259
+ role: m.role,
260
+ content: m.content
261
+ });
262
+ } else if (m.role === "assistant") {
263
+ const textParts = m.content.filter((b) => b.type === "text");
264
+ const toolUseParts = m.content.filter((b) => b.type === "tool_use");
265
+ const text2 = textParts.map((b) => "text" in b ? b.text : "").join("");
266
+ if (toolUseParts.length > 0) {
267
+ result.push({
268
+ role: "assistant",
269
+ content: text2 || null,
270
+ tool_calls: toolUseParts.map((b) => ({
271
+ id: "id" in b ? b.id : "",
272
+ type: "function",
273
+ function: {
274
+ name: "name" in b ? b.name : "",
275
+ arguments: JSON.stringify("input" in b ? b.input : {})
276
+ }
277
+ }))
278
+ });
279
+ } else {
280
+ result.push({ role: "assistant", content: text2 });
281
+ }
282
+ } else if (m.role === "user") {
283
+ const toolResults = m.content.filter((b) => b.type === "tool_result");
284
+ if (toolResults.length > 0) {
285
+ for (const tr of toolResults) {
286
+ if (tr.type === "tool_result") {
287
+ result.push({
288
+ role: "tool",
289
+ tool_call_id: tr.tool_use_id,
290
+ content: tr.content
291
+ });
292
+ }
293
+ }
294
+ } else {
295
+ const text2 = m.content.map((b) => "text" in b ? b.text : "").join("");
296
+ result.push({ role: "user", content: text2 });
297
+ }
298
+ }
299
+ }
300
+ return result;
301
+ }
116
302
  function createOpenAIClient(apiKey, model) {
117
303
  const client = new OpenAI({ apiKey });
118
304
  return {
119
- async chat(systemPrompt, messages, onChunk) {
305
+ async chat(systemPrompt, messages, onChunk, tools) {
306
+ const openaiMessages = toOpenAIMessages(systemPrompt, messages);
307
+ const hasTools = tools && tools.length > 0;
308
+ try {
309
+ if (hasTools) {
310
+ const response = await client.chat.completions.create({
311
+ model,
312
+ max_tokens: 8192,
313
+ messages: openaiMessages,
314
+ tools: tools.map((t) => ({
315
+ type: "function",
316
+ function: {
317
+ name: t.name,
318
+ description: t.description,
319
+ parameters: t.input_schema
320
+ }
321
+ }))
322
+ });
323
+ const choice = response.choices[0];
324
+ const textContent = choice?.message?.content || "";
325
+ const toolCalls = choice?.message?.tool_calls || [];
326
+ const toolUses = toolCalls.map((tc) => ({
327
+ id: tc.id,
328
+ name: tc.function.name,
329
+ input: JSON.parse(tc.function.arguments || "{}")
330
+ }));
331
+ if (textContent && toolUses.length === 0) {
332
+ onChunk({ type: "text", text: textContent });
333
+ onChunk({ type: "done" });
334
+ } else if (textContent) {
335
+ onChunk({ type: "text", text: textContent });
336
+ }
337
+ if (toolUses.length > 0) {
338
+ const contentBlocks = [
339
+ ...textContent ? [{ type: "text", text: textContent }] : [],
340
+ ...toolUses.map((tu) => ({
341
+ type: "tool_use",
342
+ id: tu.id,
343
+ name: tu.name,
344
+ input: tu.input
345
+ }))
346
+ ];
347
+ return {
348
+ message: { role: "assistant", content: contentBlocks },
349
+ toolUses
350
+ };
351
+ }
352
+ return {
353
+ message: { role: "assistant", content: textContent },
354
+ toolUses: []
355
+ };
356
+ } else {
357
+ let fullText = "";
358
+ const stream = await client.chat.completions.create({
359
+ model,
360
+ max_tokens: 8192,
361
+ messages: openaiMessages,
362
+ stream: true
363
+ });
364
+ for await (const chunk of stream) {
365
+ const text2 = chunk.choices[0]?.delta?.content || "";
366
+ if (text2) {
367
+ fullText += text2;
368
+ onChunk({ type: "text", text: text2 });
369
+ }
370
+ }
371
+ onChunk({ type: "done" });
372
+ return {
373
+ message: { role: "assistant", content: fullText },
374
+ toolUses: []
375
+ };
376
+ }
377
+ } catch (error) {
378
+ if (error instanceof OpenAI.AuthenticationError) {
379
+ throw new Error(
380
+ "Invalid API key. Run with --model flag or delete ~/.aman-agent/config.json to reconfigure."
381
+ );
382
+ }
383
+ if (error instanceof OpenAI.RateLimitError) {
384
+ throw new Error("Rate limited by OpenAI. Please wait and retry.");
385
+ }
386
+ throw error;
387
+ }
388
+ }
389
+ };
390
+ }
391
+
392
+ // src/llm/ollama.ts
393
+ import OpenAI2 from "openai";
394
+ function createOllamaClient(model, baseURL) {
395
+ const client = new OpenAI2({
396
+ baseURL: baseURL || "http://localhost:11434/v1",
397
+ apiKey: "ollama"
398
+ // Ollama doesn't require a real key
399
+ });
400
+ return {
401
+ async chat(systemPrompt, messages, onChunk, _tools) {
120
402
  let fullText = "";
121
403
  try {
122
404
  const stream = await client.chat.completions.create({
@@ -126,7 +408,7 @@ function createOpenAIClient(apiKey, model) {
126
408
  { role: "system", content: systemPrompt },
127
409
  ...messages.map((m) => ({
128
410
  role: m.role,
129
- content: m.content
411
+ content: typeof m.content === "string" ? m.content : m.content.filter((b) => b.type === "text").map((b) => "text" in b ? b.text : "").join("")
130
412
  }))
131
413
  ],
132
414
  stream: true
@@ -139,22 +421,83 @@ function createOpenAIClient(apiKey, model) {
139
421
  }
140
422
  }
141
423
  } catch (error) {
142
- if (error instanceof OpenAI.AuthenticationError) {
424
+ if (error instanceof Error && error.message.includes("ECONNREFUSED")) {
143
425
  throw new Error(
144
- "Invalid API key. Run with --model flag or delete ~/.aman-agent/config.json to reconfigure."
426
+ "Cannot connect to Ollama. Make sure it's running: ollama serve"
145
427
  );
146
428
  }
147
- if (error instanceof OpenAI.RateLimitError) {
148
- throw new Error("Rate limited by OpenAI. Please wait and retry.");
149
- }
150
429
  throw error;
151
430
  }
152
431
  onChunk({ type: "done" });
153
- return { role: "assistant", content: fullText };
432
+ return {
433
+ message: { role: "assistant", content: fullText },
434
+ toolUses: []
435
+ };
154
436
  }
155
437
  };
156
438
  }
157
439
 
440
+ // src/mcp/client.ts
441
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
442
+ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
443
+ var McpManager = class {
444
+ connections = [];
445
+ tools = [];
446
+ async connect(name, command, args) {
447
+ try {
448
+ const transport = new StdioClientTransport({ command, args });
449
+ const client = new Client({
450
+ name: `aman-agent-${name}`,
451
+ version: "0.1.0"
452
+ });
453
+ await client.connect(transport);
454
+ this.connections.push({ name, client, transport });
455
+ const toolsResult = await client.listTools();
456
+ for (const tool of toolsResult.tools) {
457
+ this.tools.push({
458
+ name: tool.name,
459
+ description: tool.description || "",
460
+ input_schema: tool.inputSchema,
461
+ serverName: name
462
+ });
463
+ }
464
+ } catch {
465
+ console.error(` Warning: Could not connect to ${name} MCP server`);
466
+ }
467
+ }
468
+ getTools() {
469
+ return this.tools;
470
+ }
471
+ async callTool(toolName, args) {
472
+ const tool = this.tools.find((t) => t.name === toolName);
473
+ if (!tool) return `Error: tool ${toolName} not found`;
474
+ const conn = this.connections.find((c) => c.name === tool.serverName);
475
+ if (!conn) return `Error: server ${tool.serverName} not connected`;
476
+ try {
477
+ const result = await conn.client.callTool({
478
+ name: toolName,
479
+ arguments: args
480
+ });
481
+ if (result.content && Array.isArray(result.content)) {
482
+ return result.content.filter((c) => c.type === "text").map((c) => c.text ?? "").join("\n");
483
+ }
484
+ return JSON.stringify(result);
485
+ } catch (error) {
486
+ return `Error calling ${toolName}: ${error instanceof Error ? error.message : String(error)}`;
487
+ }
488
+ }
489
+ async disconnect() {
490
+ for (const conn of this.connections) {
491
+ try {
492
+ await conn.client.close();
493
+ } catch {
494
+ }
495
+ }
496
+ this.connections = [];
497
+ this.tools = [];
498
+ }
499
+ };
500
+
158
501
  // src/agent.ts
159
502
  import * as readline from "readline";
160
503
  import pc3 from "picocolors";
@@ -299,7 +642,7 @@ function clearReminders() {
299
642
  }
300
643
 
301
644
  // src/agent.ts
302
- async function runAgent(client, systemPrompt, aiName, model) {
645
+ async function runAgent(client, systemPrompt, aiName, model, tools, mcpManager) {
303
646
  const messages = [];
304
647
  const rl = readline.createInterface({
305
648
  input: process.stdin,
@@ -359,15 +702,56 @@ Type a message, ${pc3.dim("/help")} for commands, or ${pc3.dim("/quit")} to exit
359
702
  process.stdout.write(pc3.cyan(`
360
703
  ${aiName} > `));
361
704
  try {
362
- const response = await client.chat(systemPrompt, messages, (chunk) => {
363
- if (chunk.type === "text" && chunk.text) {
364
- process.stdout.write(chunk.text);
365
- }
366
- if (chunk.type === "done") {
367
- process.stdout.write("\n");
705
+ let response = await client.chat(
706
+ systemPrompt,
707
+ messages,
708
+ (chunk) => {
709
+ if (chunk.type === "text" && chunk.text) {
710
+ process.stdout.write(chunk.text);
711
+ }
712
+ if (chunk.type === "done") {
713
+ process.stdout.write("\n");
714
+ }
715
+ },
716
+ tools
717
+ );
718
+ messages.push(response.message);
719
+ while (response.toolUses.length > 0 && mcpManager) {
720
+ const toolResults = [];
721
+ for (const toolUse of response.toolUses) {
722
+ process.stdout.write(
723
+ pc3.dim(` [using ${toolUse.name}...]
724
+ `)
725
+ );
726
+ const result = await mcpManager.callTool(
727
+ toolUse.name,
728
+ toolUse.input
729
+ );
730
+ toolResults.push({
731
+ type: "tool_result",
732
+ tool_use_id: toolUse.id,
733
+ content: result
734
+ });
368
735
  }
369
- });
370
- messages.push(response);
736
+ messages.push({
737
+ role: "user",
738
+ content: toolResults
739
+ });
740
+ response = await client.chat(
741
+ systemPrompt,
742
+ messages,
743
+ (chunk) => {
744
+ if (chunk.type === "text" && chunk.text) {
745
+ process.stdout.write(chunk.text);
746
+ }
747
+ if (chunk.type === "done") {
748
+ process.stdout.write("\n");
749
+ }
750
+ },
751
+ tools
752
+ );
753
+ messages.push(response.message);
754
+ }
371
755
  } catch (error) {
372
756
  const message = error instanceof Error ? error.message : "Unknown error occurred";
373
757
  console.error(pc3.red(`
@@ -495,7 +879,7 @@ import fs6 from "fs";
495
879
  import path6 from "path";
496
880
  import os6 from "os";
497
881
  var program = new Command();
498
- program.name("aman-agent").description("Your AI companion, running locally").version("0.1.0").option("--model <model>", "Override LLM model").action(async (options) => {
882
+ program.name("aman-agent").description("Your AI companion, running locally").version("0.1.0").option("--model <model>", "Override LLM model").option("--budget <tokens>", "Token budget for system prompt (default: 8000)", parseInt).action(async (options) => {
499
883
  p.intro(pc5.bold("aman agent") + pc5.dim(" \u2014 starting your AI companion"));
500
884
  let config = loadConfig();
501
885
  if (!config) {
@@ -508,30 +892,51 @@ program.name("aman-agent").description("Your AI companion, running locally").ver
508
892
  label: "Claude (Anthropic)",
509
893
  hint: "recommended"
510
894
  },
511
- { value: "openai", label: "GPT (OpenAI)" }
895
+ { value: "openai", label: "GPT (OpenAI)" },
896
+ { value: "ollama", label: "Ollama (local)", hint: "free, runs offline" }
512
897
  ],
513
898
  initialValue: "anthropic"
514
899
  });
515
900
  if (p.isCancel(provider)) process.exit(0);
516
- const apiKey = await p.text({
517
- message: "API key",
518
- validate: (v) => v.length === 0 ? "API key is required" : void 0
519
- });
520
- if (p.isCancel(apiKey)) process.exit(0);
521
- const defaultModel = provider === "anthropic" ? "claude-sonnet-4-5-20250514" : "gpt-4o";
901
+ let apiKey = "";
902
+ let defaultModel = "";
903
+ if (provider === "ollama") {
904
+ apiKey = "ollama";
905
+ defaultModel = "llama3.2";
906
+ const modelInput = await p.text({
907
+ message: "Ollama model",
908
+ placeholder: "llama3.2",
909
+ defaultValue: "llama3.2"
910
+ });
911
+ if (p.isCancel(modelInput)) process.exit(0);
912
+ defaultModel = modelInput || "llama3.2";
913
+ } else {
914
+ apiKey = await p.text({
915
+ message: "API key",
916
+ validate: (v) => v.length === 0 ? "API key is required" : void 0
917
+ });
918
+ if (p.isCancel(apiKey)) process.exit(0);
919
+ defaultModel = provider === "anthropic" ? "claude-sonnet-4-5-20250514" : "gpt-4o";
920
+ }
522
921
  config = { provider, apiKey, model: defaultModel };
523
922
  saveConfig(config);
524
923
  p.log.success("Config saved to ~/.aman-agent/config.json");
525
924
  }
526
925
  const model = options.model || config.model;
527
- const { prompt: systemPrompt, layers } = assembleSystemPrompt();
926
+ const budget = options.budget || void 0;
927
+ const { prompt: systemPrompt, layers, truncated, totalTokens } = assembleSystemPrompt(budget);
528
928
  if (layers.length === 0) {
529
929
  p.log.warning(
530
930
  "No ecosystem configured. Run " + pc5.bold("npx @aman_asmuei/aman") + " first."
531
931
  );
532
932
  p.log.info("Starting with empty system prompt.");
533
933
  } else {
534
- p.log.success(`Loaded: ${layers.join(", ")}`);
934
+ p.log.success(
935
+ `Loaded: ${layers.join(", ")} ${pc5.dim(`(${totalTokens.toLocaleString()} tokens)`)}`
936
+ );
937
+ if (truncated.length > 0) {
938
+ p.log.warning(`Truncated: ${truncated.join(", ")} ${pc5.dim("(over budget)")}`);
939
+ }
535
940
  }
536
941
  p.log.info(`Model: ${pc5.dim(model)}`);
537
942
  const corePath = path6.join(os6.homedir(), ".acore", "core.md");
@@ -544,8 +949,40 @@ program.name("aman-agent").description("Your AI companion, running locally").ver
544
949
  p.log.success(`${pc5.bold(aiName)} is ready.`);
545
950
  const notifications = checkNotifications();
546
951
  displayNotifications(notifications);
547
- const client = config.provider === "anthropic" ? createAnthropicClient(config.apiKey, model) : createOpenAIClient(config.apiKey, model);
548
- await runAgent(client, systemPrompt, aiName, model);
952
+ const mcpManager = new McpManager();
953
+ p.log.step("Connecting to MCP servers...");
954
+ await mcpManager.connect("aman", "npx", ["-y", "@aman_asmuei/aman-mcp"]);
955
+ await mcpManager.connect("amem", "npx", ["-y", "@aman_asmuei/amem"]);
956
+ const mcpTools = mcpManager.getTools();
957
+ if (mcpTools.length > 0) {
958
+ p.log.success(`${mcpTools.length} MCP tools available`);
959
+ } else {
960
+ p.log.info(
961
+ "No MCP tools connected (install aman-mcp or amem for tool support)"
962
+ );
963
+ }
964
+ const toolDefs = mcpTools.map((t) => ({
965
+ name: t.name,
966
+ description: t.description,
967
+ input_schema: t.input_schema
968
+ }));
969
+ let client;
970
+ if (config.provider === "anthropic") {
971
+ client = createAnthropicClient(config.apiKey, model);
972
+ } else if (config.provider === "ollama") {
973
+ client = createOllamaClient(model);
974
+ } else {
975
+ client = createOpenAIClient(config.apiKey, model);
976
+ }
977
+ await runAgent(
978
+ client,
979
+ systemPrompt,
980
+ aiName,
981
+ model,
982
+ toolDefs.length > 0 ? toolDefs : void 0,
983
+ toolDefs.length > 0 ? mcpManager : void 0
984
+ );
985
+ await mcpManager.disconnect();
549
986
  });
550
987
  program.command("schedule").description("Manage scheduled tasks").argument("[action]", "add, list, or remove").argument("[id]", "task ID (for remove)").action(async (action, id) => {
551
988
  if (!action || action === "list") {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/config.ts","../src/prompt.ts","../src/llm/anthropic.ts","../src/llm/openai.ts","../src/agent.ts","../src/commands.ts","../src/reminders.ts","../src/scheduler.ts","../src/notifications.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport * as p from \"@clack/prompts\";\nimport pc from \"picocolors\";\nimport { loadConfig, saveConfig } from \"./config.js\";\nimport { assembleSystemPrompt } from \"./prompt.js\";\nimport { createAnthropicClient } from \"./llm/anthropic.js\";\nimport { createOpenAIClient } from \"./llm/openai.js\";\nimport { runAgent } from \"./agent.js\";\nimport {\n loadSchedules,\n addSchedule,\n removeSchedule,\n} from \"./scheduler.js\";\nimport {\n checkNotifications,\n displayNotifications,\n} from \"./notifications.js\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\n\ndeclare const __VERSION__: string;\n\nconst program = new Command();\n\nprogram\n .name(\"aman-agent\")\n .description(\"Your AI companion, running locally\")\n .version(__VERSION__)\n .option(\"--model <model>\", \"Override LLM model\")\n .action(async (options) => {\n p.intro(pc.bold(\"aman agent\") + pc.dim(\" — starting your AI companion\"));\n\n // Setup config if needed\n let config = loadConfig();\n if (!config) {\n p.log.info(\"First-time setup — configure your LLM connection.\");\n\n const provider = (await p.select({\n message: \"LLM provider\",\n options: [\n {\n value: \"anthropic\",\n label: \"Claude (Anthropic)\",\n hint: \"recommended\",\n },\n { value: \"openai\", label: \"GPT (OpenAI)\" },\n ],\n initialValue: \"anthropic\",\n })) as \"anthropic\" | \"openai\";\n if (p.isCancel(provider)) process.exit(0);\n\n const apiKey = (await p.text({\n message: \"API key\",\n validate: (v) =>\n v.length === 0 ? \"API key is required\" : undefined,\n })) as string;\n if (p.isCancel(apiKey)) process.exit(0);\n\n const defaultModel =\n provider === \"anthropic\" ? \"claude-sonnet-4-5-20250514\" : \"gpt-4o\";\n\n config = { provider, apiKey, model: defaultModel };\n saveConfig(config);\n p.log.success(\"Config saved to ~/.aman-agent/config.json\");\n }\n\n // Override model if specified\n const model = options.model || config.model;\n\n // Assemble system prompt from ecosystem\n const { prompt: systemPrompt, layers } = assembleSystemPrompt();\n\n if (layers.length === 0) {\n p.log.warning(\n \"No ecosystem configured. Run \" +\n pc.bold(\"npx @aman_asmuei/aman\") +\n \" first.\",\n );\n p.log.info(\"Starting with empty system prompt.\");\n } else {\n p.log.success(`Loaded: ${layers.join(\", \")}`);\n }\n\n p.log.info(`Model: ${pc.dim(model)}`);\n\n // Extract AI name from core.md\n const corePath = path.join(os.homedir(), \".acore\", \"core.md\");\n let aiName = \"Assistant\";\n if (fs.existsSync(corePath)) {\n const content = fs.readFileSync(corePath, \"utf-8\");\n const match = content.match(/^# (.+)$/m);\n if (match) aiName = match[1];\n }\n\n p.log.success(`${pc.bold(aiName)} is ready.`);\n\n // Session-start notifications\n const notifications = checkNotifications();\n displayNotifications(notifications);\n\n // Create LLM client\n const client =\n config.provider === \"anthropic\"\n ? createAnthropicClient(config.apiKey, model)\n : createOpenAIClient(config.apiKey, model);\n\n // Run the agent\n await runAgent(client, systemPrompt, aiName, model);\n });\n\nprogram\n .command(\"schedule\")\n .description(\"Manage scheduled tasks\")\n .argument(\"[action]\", \"add, list, or remove\")\n .argument(\"[id]\", \"task ID (for remove)\")\n .action(async (action?: string, id?: string) => {\n if (!action || action === \"list\") {\n const tasks = loadSchedules();\n if (tasks.length === 0) {\n console.log(pc.dim(\"No scheduled tasks.\"));\n return;\n }\n console.log(pc.bold(\"Scheduled tasks:\\n\"));\n for (const task of tasks) {\n const lastRun = task.lastRun\n ? pc.dim(` (last run: ${new Date(task.lastRun).toLocaleString()})`)\n : pc.dim(\" (never run)\");\n console.log(\n ` ${pc.cyan(task.id)} ${task.name} ${pc.dim(task.schedule)} [${task.mode}]${lastRun}`,\n );\n }\n return;\n }\n\n if (action === \"add\") {\n const name = (await p.text({\n message: \"Task name?\",\n validate: (v) => (v.length === 0 ? \"Name is required\" : undefined),\n })) as string;\n if (p.isCancel(name)) return;\n\n const schedule = (await p.select({\n message: \"Schedule?\",\n options: [\n { value: \"daily 9am\", label: \"Daily at 9am\" },\n { value: \"weekdays 9am\", label: \"Weekdays at 9am\" },\n { value: \"weekly friday 4pm\", label: \"Weekly Friday 4pm\" },\n { value: \"every 2h\", label: \"Every 2 hours\" },\n { value: \"every 4h\", label: \"Every 4 hours\" },\n ],\n })) as string;\n if (p.isCancel(schedule)) return;\n\n const actionType = (await p.select({\n message: \"What should happen?\",\n options: [\n { value: \"notify\", label: \"Show notification\" },\n { value: \"auto-run\", label: \"Run automatically\" },\n ],\n })) as \"notify\" | \"auto-run\";\n if (p.isCancel(actionType)) return;\n\n let taskAction = \"notify\";\n if (actionType === \"auto-run\") {\n const cmd = (await p.text({\n message: \"Command to run?\",\n placeholder: \"e.g. run:daily-standup\",\n validate: (v) =>\n v.length === 0 ? \"Command is required\" : undefined,\n })) as string;\n if (p.isCancel(cmd)) return;\n taskAction = cmd;\n }\n\n const task = addSchedule({\n name,\n schedule,\n action: taskAction,\n mode: actionType,\n });\n console.log(\n pc.green(`\\nScheduled task created: ${pc.bold(task.name)} (${task.id})`),\n );\n return;\n }\n\n if (action === \"remove\") {\n if (!id) {\n console.log(pc.red(\"Usage: aman-agent schedule remove <id>\"));\n return;\n }\n const removed = removeSchedule(id);\n if (removed) {\n console.log(pc.green(`Task ${id} removed.`));\n } else {\n console.log(pc.red(`Task ${id} not found.`));\n }\n return;\n }\n\n console.log(\n pc.red(`Unknown action: ${action}. Use add, list, or remove.`),\n );\n });\n\nprogram.parse();\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\n\nexport interface AgentConfig {\n provider: \"anthropic\" | \"openai\";\n apiKey: string;\n model: string;\n}\n\nconst CONFIG_DIR = path.join(os.homedir(), \".aman-agent\");\nconst CONFIG_PATH = path.join(CONFIG_DIR, \"config.json\");\n\nexport function loadConfig(): AgentConfig | null {\n if (!fs.existsSync(CONFIG_PATH)) return null;\n try {\n return JSON.parse(fs.readFileSync(CONFIG_PATH, \"utf-8\"));\n } catch {\n return null;\n }\n}\n\nexport function saveConfig(config: AgentConfig): void {\n fs.mkdirSync(CONFIG_DIR, { recursive: true });\n fs.writeFileSync(\n CONFIG_PATH,\n JSON.stringify(config, null, 2) + \"\\n\",\n \"utf-8\",\n );\n}\n\nexport function configExists(): boolean {\n return fs.existsSync(CONFIG_PATH);\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\n\nexport function assembleSystemPrompt(): { prompt: string; layers: string[] } {\n const home = os.homedir();\n const layers: string[] = [];\n const parts: string[] = [];\n\n // Identity (acore)\n const corePath = path.join(home, \".acore\", \"core.md\");\n if (fs.existsSync(corePath)) {\n parts.push(fs.readFileSync(corePath, \"utf-8\").trim());\n layers.push(\"identity\");\n }\n\n // Project context\n const contextPath = path.join(process.cwd(), \".acore\", \"context.md\");\n if (fs.existsSync(contextPath)) {\n parts.push(fs.readFileSync(contextPath, \"utf-8\").trim());\n }\n\n // Tools (akit)\n const kitPath = path.join(home, \".akit\", \"kit.md\");\n if (fs.existsSync(kitPath)) {\n parts.push(fs.readFileSync(kitPath, \"utf-8\").trim());\n layers.push(\"tools\");\n }\n\n // Workflows (aflow)\n const flowPath = path.join(home, \".aflow\", \"flow.md\");\n if (fs.existsSync(flowPath)) {\n parts.push(fs.readFileSync(flowPath, \"utf-8\").trim());\n layers.push(\"workflows\");\n }\n\n // Guardrails (arules)\n const rulesPath = path.join(home, \".arules\", \"rules.md\");\n if (fs.existsSync(rulesPath)) {\n parts.push(fs.readFileSync(rulesPath, \"utf-8\").trim());\n layers.push(\"guardrails\");\n }\n\n // Skills (askill)\n const skillsPath = path.join(home, \".askill\", \"skills.md\");\n if (fs.existsSync(skillsPath)) {\n parts.push(fs.readFileSync(skillsPath, \"utf-8\").trim());\n layers.push(\"skills\");\n }\n\n return {\n prompt: parts.join(\"\\n\\n---\\n\\n\"),\n layers,\n };\n}\n","import Anthropic from \"@anthropic-ai/sdk\";\nimport type { LLMClient, Message, StreamChunk } from \"./types.js\";\n\nexport function createAnthropicClient(\n apiKey: string,\n model: string,\n): LLMClient {\n const client = new Anthropic({ apiKey });\n\n return {\n async chat(systemPrompt, messages, onChunk) {\n let fullText = \"\";\n\n try {\n const stream = await client.messages.create({\n model,\n max_tokens: 8192,\n system: systemPrompt,\n messages: messages.map((m) => ({\n role: m.role,\n content: m.content,\n })),\n stream: true,\n });\n\n for await (const event of stream) {\n if (\n event.type === \"content_block_delta\" &&\n event.delta.type === \"text_delta\"\n ) {\n const text = event.delta.text;\n fullText += text;\n onChunk({ type: \"text\", text });\n }\n }\n } catch (error) {\n if (error instanceof Anthropic.AuthenticationError) {\n throw new Error(\n \"Invalid API key. Run with --model flag or delete ~/.aman-agent/config.json to reconfigure.\",\n );\n }\n if (error instanceof Anthropic.RateLimitError) {\n throw new Error(\"Rate limited by Anthropic. Please wait and retry.\");\n }\n throw error;\n }\n\n onChunk({ type: \"done\" });\n return { role: \"assistant\", content: fullText };\n },\n };\n}\n","import OpenAI from \"openai\";\nimport type { LLMClient, Message, StreamChunk } from \"./types.js\";\n\nexport function createOpenAIClient(apiKey: string, model: string): LLMClient {\n const client = new OpenAI({ apiKey });\n\n return {\n async chat(systemPrompt, messages, onChunk) {\n let fullText = \"\";\n\n try {\n const stream = await client.chat.completions.create({\n model,\n max_tokens: 8192,\n messages: [\n { role: \"system\", content: systemPrompt },\n ...messages.map((m) => ({\n role: m.role as \"user\" | \"assistant\",\n content: m.content,\n })),\n ],\n stream: true,\n });\n\n for await (const chunk of stream) {\n const text = chunk.choices[0]?.delta?.content || \"\";\n if (text) {\n fullText += text;\n onChunk({ type: \"text\", text });\n }\n }\n } catch (error) {\n if (error instanceof OpenAI.AuthenticationError) {\n throw new Error(\n \"Invalid API key. Run with --model flag or delete ~/.aman-agent/config.json to reconfigure.\",\n );\n }\n if (error instanceof OpenAI.RateLimitError) {\n throw new Error(\"Rate limited by OpenAI. Please wait and retry.\");\n }\n throw error;\n }\n\n onChunk({ type: \"done\" });\n return { role: \"assistant\", content: fullText };\n },\n };\n}\n","import * as readline from \"node:readline\";\nimport pc from \"picocolors\";\nimport type { LLMClient, Message } from \"./llm/types.js\";\nimport { handleCommand } from \"./commands.js\";\nimport { setReminder, clearReminders } from \"./reminders.js\";\n\nexport async function runAgent(\n client: LLMClient,\n systemPrompt: string,\n aiName: string,\n model: string,\n): Promise<void> {\n const messages: Message[] = [];\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n // Handle Ctrl+C gracefully\n rl.on(\"SIGINT\", () => {\n console.log(pc.dim(\"\\nGoodbye.\\n\"));\n rl.close();\n process.exit(0);\n });\n\n const prompt = (): Promise<string> => {\n return new Promise<string>((resolve) => {\n rl.question(pc.green(\"\\nYou > \"), (answer) => {\n resolve(answer);\n });\n });\n };\n\n console.log(\n `\\nType a message, ${pc.dim(\"/help\")} for commands, or ${pc.dim(\"/quit\")} to exit.\\n`,\n );\n\n while (true) {\n const input = await prompt();\n if (!input.trim()) continue;\n\n // Handle slash commands\n const cmdResult = handleCommand(input, model);\n if (cmdResult.handled) {\n if (cmdResult.quit) {\n clearReminders();\n console.log(pc.dim(\"\\nGoodbye.\\n\"));\n rl.close();\n return;\n }\n if (cmdResult.remind) {\n const duration = setReminder(\n cmdResult.remind.timeStr,\n cmdResult.remind.message,\n );\n if (duration) {\n console.log(pc.dim(`Reminder set for ${duration} from now.`));\n } else {\n console.log(\n pc.red(\"Invalid time format. Use: 5m, 30m, 1h, 2h, tomorrow\"),\n );\n }\n continue;\n }\n if (cmdResult.output) {\n console.log(cmdResult.output);\n }\n if (cmdResult.clearHistory) {\n messages.length = 0;\n }\n continue;\n }\n\n // Send to LLM\n messages.push({ role: \"user\", content: input });\n\n process.stdout.write(pc.cyan(`\\n${aiName} > `));\n\n try {\n const response = await client.chat(systemPrompt, messages, (chunk) => {\n if (chunk.type === \"text\" && chunk.text) {\n process.stdout.write(chunk.text);\n }\n if (chunk.type === \"done\") {\n process.stdout.write(\"\\n\");\n }\n });\n\n messages.push(response);\n } catch (error) {\n const message =\n error instanceof Error ? error.message : \"Unknown error occurred\";\n console.error(pc.red(`\\nError: ${message}`));\n // Remove the user message that failed\n messages.pop();\n }\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport pc from \"picocolors\";\n\nexport interface CommandResult {\n handled: boolean;\n output?: string;\n quit?: boolean;\n clearHistory?: boolean;\n remind?: { timeStr: string; message: string };\n}\n\nfunction readEcosystemFile(filePath: string, label: string): string {\n if (!fs.existsSync(filePath)) {\n return pc.dim(`No ${label} file found at ${filePath}`);\n }\n return fs.readFileSync(filePath, \"utf-8\").trim();\n}\n\nexport function handleCommand(input: string, model?: string): CommandResult {\n const cmd = input.trim().toLowerCase();\n const home = os.homedir();\n\n if (cmd === \"/quit\" || cmd === \"/exit\" || cmd === \"/q\") {\n return { handled: true, quit: true };\n }\n\n if (cmd === \"/help\") {\n return {\n handled: true,\n output: [\n pc.bold(\"Commands:\"),\n ` ${pc.cyan(\"/help\")} Show this help`,\n ` ${pc.cyan(\"/identity\")} View your AI identity`,\n ` ${pc.cyan(\"/tools\")} View installed tools`,\n ` ${pc.cyan(\"/workflows\")} View defined workflows`,\n ` ${pc.cyan(\"/rules\")} View guardrails`,\n ` ${pc.cyan(\"/skills\")} View installed skills`,\n ` ${pc.cyan(\"/remind\")} Set a reminder (e.g. /remind 30m Review PR)`,\n ` ${pc.cyan(\"/model\")} Show current LLM model`,\n ` ${pc.cyan(\"/clear\")} Clear conversation history`,\n ` ${pc.cyan(\"/quit\")} Exit`,\n ].join(\"\\n\"),\n };\n }\n\n if (cmd === \"/identity\") {\n const content = readEcosystemFile(\n path.join(home, \".acore\", \"core.md\"),\n \"identity (acore)\",\n );\n return { handled: true, output: content };\n }\n\n if (cmd === \"/tools\") {\n const content = readEcosystemFile(\n path.join(home, \".akit\", \"kit.md\"),\n \"tools (akit)\",\n );\n return { handled: true, output: content };\n }\n\n if (cmd === \"/workflows\") {\n const content = readEcosystemFile(\n path.join(home, \".aflow\", \"flow.md\"),\n \"workflows (aflow)\",\n );\n return { handled: true, output: content };\n }\n\n if (cmd === \"/rules\") {\n const content = readEcosystemFile(\n path.join(home, \".arules\", \"rules.md\"),\n \"guardrails (arules)\",\n );\n return { handled: true, output: content };\n }\n\n if (cmd === \"/skills\") {\n const content = readEcosystemFile(\n path.join(home, \".askill\", \"skills.md\"),\n \"skills (askill)\",\n );\n return { handled: true, output: content };\n }\n\n if (cmd === \"/model\") {\n return {\n handled: true,\n output: model ? `Model: ${pc.bold(model)}` : \"Model: unknown\",\n };\n }\n\n if (cmd === \"/clear\") {\n return { handled: true, output: pc.dim(\"Conversation cleared.\"), clearHistory: true };\n }\n\n if (cmd.startsWith(\"/remind\")) {\n const parts = input.trim().split(/\\s+/);\n if (parts.length < 3) {\n return {\n handled: true,\n output:\n \"Usage: /remind <time> <message>\\nExamples: /remind 30m Review PR, /remind 2h Deploy, /remind tomorrow Check metrics\",\n };\n }\n const timeStr = parts[1];\n const message = parts.slice(2).join(\" \");\n return { handled: true, remind: { timeStr, message } };\n }\n\n if (cmd.startsWith(\"/\")) {\n return {\n handled: true,\n output: `Unknown command: ${cmd}. Type ${pc.cyan(\"/help\")} for available commands.`,\n };\n }\n\n return { handled: false };\n}\n","import pc from \"picocolors\";\n\ninterface Reminder {\n message: string;\n dueAt: number;\n timer?: ReturnType<typeof setTimeout>;\n}\n\nconst activeReminders: Reminder[] = [];\n\nexport function parseTime(timeStr: string): number | null {\n const match = timeStr.match(/^(\\d+)(m|h)$/);\n if (match) {\n const value = parseInt(match[1]);\n const unit = match[2];\n return unit === \"m\" ? value * 60 * 1000 : value * 60 * 60 * 1000;\n }\n if (timeStr === \"tomorrow\") return 24 * 60 * 60 * 1000;\n return null;\n}\n\nexport function setReminder(timeStr: string, message: string): string | null {\n const ms = parseTime(timeStr);\n if (!ms) return null;\n\n const reminder: Reminder = {\n message,\n dueAt: Date.now() + ms,\n };\n\n reminder.timer = setTimeout(() => {\n console.log(`\\n${pc.yellow(\"\\u23f0\")} ${pc.bold(\"Reminder:\")} ${message}`);\n const idx = activeReminders.indexOf(reminder);\n if (idx >= 0) activeReminders.splice(idx, 1);\n }, ms);\n\n activeReminders.push(reminder);\n\n const mins = Math.round(ms / 60000);\n if (mins < 60) return `${mins} minutes`;\n const hours = Math.round(mins / 60);\n return `${hours} hour${hours > 1 ? \"s\" : \"\"}`;\n}\n\nexport function clearReminders(): void {\n for (const r of activeReminders) {\n if (r.timer) clearTimeout(r.timer);\n }\n activeReminders.length = 0;\n}\n\nexport function getActiveCount(): number {\n return activeReminders.length;\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\n\nconst SCHEDULES_PATH = path.join(os.homedir(), \".aman-agent\", \"schedules.json\");\n\nexport interface ScheduledTask {\n id: string;\n name: string;\n schedule: string;\n action: string;\n mode: \"notify\" | \"auto-run\";\n createdAt: string;\n lastRun?: string;\n}\n\nexport function loadSchedules(): ScheduledTask[] {\n if (!fs.existsSync(SCHEDULES_PATH)) return [];\n try {\n return JSON.parse(fs.readFileSync(SCHEDULES_PATH, \"utf-8\"));\n } catch {\n return [];\n }\n}\n\nexport function saveSchedules(tasks: ScheduledTask[]): void {\n const dir = path.dirname(SCHEDULES_PATH);\n fs.mkdirSync(dir, { recursive: true });\n fs.writeFileSync(\n SCHEDULES_PATH,\n JSON.stringify(tasks, null, 2) + \"\\n\",\n \"utf-8\",\n );\n}\n\nexport function addSchedule(\n task: Omit<ScheduledTask, \"id\" | \"createdAt\">,\n): ScheduledTask {\n const tasks = loadSchedules();\n const newTask: ScheduledTask = {\n ...task,\n id: Date.now().toString(36),\n createdAt: new Date().toISOString(),\n };\n tasks.push(newTask);\n saveSchedules(tasks);\n return newTask;\n}\n\nexport function removeSchedule(id: string): boolean {\n const tasks = loadSchedules();\n const filtered = tasks.filter((t) => t.id !== id);\n if (filtered.length === tasks.length) return false;\n saveSchedules(filtered);\n return true;\n}\n\nexport function getDueTasks(): ScheduledTask[] {\n const tasks = loadSchedules();\n const now = new Date();\n return tasks.filter((task) => {\n if (!task.lastRun) return true;\n const lastRun = new Date(task.lastRun);\n return isDue(task.schedule, lastRun, now);\n });\n}\n\nexport function isDue(schedule: string, lastRun: Date, now: Date): boolean {\n const hoursSinceLastRun =\n (now.getTime() - lastRun.getTime()) / (1000 * 60 * 60);\n\n if (schedule.startsWith(\"every \")) {\n const match = schedule.match(/every (\\d+)h/);\n if (match) return hoursSinceLastRun >= parseInt(match[1]);\n }\n if (schedule === \"daily\" || schedule.startsWith(\"daily \")) {\n return hoursSinceLastRun >= 20;\n }\n if (schedule === \"weekdays\" || schedule.startsWith(\"weekdays \")) {\n const day = now.getDay();\n return day >= 1 && day <= 5 && hoursSinceLastRun >= 20;\n }\n if (schedule.startsWith(\"weekly\")) {\n return hoursSinceLastRun >= 144;\n }\n return false;\n}\n\nexport function markRun(id: string): void {\n const tasks = loadSchedules();\n const task = tasks.find((t) => t.id === id);\n if (task) {\n task.lastRun = new Date().toISOString();\n saveSchedules(tasks);\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport pc from \"picocolors\";\nimport { getDueTasks } from \"./scheduler.js\";\n\nexport interface Notification {\n type: \"schedule\" | \"eval\" | \"health\";\n message: string;\n}\n\nexport function checkNotifications(): Notification[] {\n const notifications: Notification[] = [];\n\n // Check due scheduled tasks\n const dueTasks = getDueTasks();\n for (const task of dueTasks) {\n notifications.push({\n type: \"schedule\",\n message: `${task.name} (${task.schedule})`,\n });\n }\n\n // Check aeval — sessions not logged recently\n const evalPath = path.join(os.homedir(), \".aeval\", \"eval.md\");\n if (fs.existsSync(evalPath)) {\n const content = fs.readFileSync(evalPath, \"utf-8\");\n const dateMatch = content.match(/- Last updated: (.+)$/m);\n if (dateMatch) {\n const lastDate = new Date(dateMatch[1]);\n const daysSince =\n (Date.now() - lastDate.getTime()) / (1000 * 60 * 60 * 24);\n if (daysSince > 3) {\n notifications.push({\n type: \"eval\",\n message: `No session logged in ${Math.floor(daysSince)} days \\u2014 run /eval to log one`,\n });\n }\n }\n }\n\n return notifications;\n}\n\nexport function displayNotifications(notifications: Notification[]): void {\n if (notifications.length === 0) return;\n\n console.log(\n pc.yellow(\n `\\n\\u26a0 ${notifications.length} notification${notifications.length > 1 ? \"s\" : \"\"}:`,\n ),\n );\n for (const n of notifications) {\n console.log(` - ${n.message}`);\n }\n console.log(\"\");\n}\n"],"mappings":"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","names":["pc","fs","path","os","text","text","pc","fs","path","os","pc","pc","fs","path","os","fs","path","os","pc","path","os","fs","pc","fs","path","os","pc"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/config.ts","../src/prompt.ts","../src/token-budget.ts","../src/llm/anthropic.ts","../src/llm/openai.ts","../src/llm/ollama.ts","../src/mcp/client.ts","../src/agent.ts","../src/commands.ts","../src/reminders.ts","../src/scheduler.ts","../src/notifications.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport * as p from \"@clack/prompts\";\nimport pc from \"picocolors\";\nimport { loadConfig, saveConfig } from \"./config.js\";\nimport { assembleSystemPrompt } from \"./prompt.js\";\nimport { createAnthropicClient } from \"./llm/anthropic.js\";\nimport { createOpenAIClient } from \"./llm/openai.js\";\nimport { createOllamaClient } from \"./llm/ollama.js\";\nimport { McpManager } from \"./mcp/client.js\";\nimport { runAgent } from \"./agent.js\";\nimport {\n loadSchedules,\n addSchedule,\n removeSchedule,\n} from \"./scheduler.js\";\nimport {\n checkNotifications,\n displayNotifications,\n} from \"./notifications.js\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\n\ndeclare const __VERSION__: string;\n\nconst program = new Command();\n\nprogram\n .name(\"aman-agent\")\n .description(\"Your AI companion, running locally\")\n .version(__VERSION__)\n .option(\"--model <model>\", \"Override LLM model\")\n .option(\"--budget <tokens>\", \"Token budget for system prompt (default: 8000)\", parseInt)\n .action(async (options) => {\n p.intro(pc.bold(\"aman agent\") + pc.dim(\" — starting your AI companion\"));\n\n // Setup config if needed\n let config = loadConfig();\n if (!config) {\n p.log.info(\"First-time setup — configure your LLM connection.\");\n\n const provider = (await p.select({\n message: \"LLM provider\",\n options: [\n {\n value: \"anthropic\",\n label: \"Claude (Anthropic)\",\n hint: \"recommended\",\n },\n { value: \"openai\", label: \"GPT (OpenAI)\" },\n { value: \"ollama\", label: \"Ollama (local)\", hint: \"free, runs offline\" },\n ],\n initialValue: \"anthropic\",\n })) as \"anthropic\" | \"openai\" | \"ollama\";\n if (p.isCancel(provider)) process.exit(0);\n\n let apiKey = \"\";\n let defaultModel = \"\";\n\n if (provider === \"ollama\") {\n apiKey = \"ollama\";\n defaultModel = \"llama3.2\";\n const modelInput = (await p.text({\n message: \"Ollama model\",\n placeholder: \"llama3.2\",\n defaultValue: \"llama3.2\",\n })) as string;\n if (p.isCancel(modelInput)) process.exit(0);\n defaultModel = modelInput || \"llama3.2\";\n } else {\n apiKey = (await p.text({\n message: \"API key\",\n validate: (v) =>\n v.length === 0 ? \"API key is required\" : undefined,\n })) as string;\n if (p.isCancel(apiKey)) process.exit(0);\n defaultModel = provider === \"anthropic\" ? \"claude-sonnet-4-5-20250514\" : \"gpt-4o\";\n }\n\n config = { provider, apiKey, model: defaultModel };\n saveConfig(config);\n p.log.success(\"Config saved to ~/.aman-agent/config.json\");\n }\n\n // Override model if specified\n const model = options.model || config.model;\n\n // Assemble system prompt from ecosystem with token budget\n const budget = options.budget || undefined;\n const { prompt: systemPrompt, layers, truncated, totalTokens } = assembleSystemPrompt(budget);\n\n if (layers.length === 0) {\n p.log.warning(\n \"No ecosystem configured. Run \" +\n pc.bold(\"npx @aman_asmuei/aman\") +\n \" first.\",\n );\n p.log.info(\"Starting with empty system prompt.\");\n } else {\n p.log.success(\n `Loaded: ${layers.join(\", \")} ${pc.dim(`(${totalTokens.toLocaleString()} tokens)`)}`,\n );\n if (truncated.length > 0) {\n p.log.warning(`Truncated: ${truncated.join(\", \")} ${pc.dim(\"(over budget)\")}`);\n }\n }\n\n p.log.info(`Model: ${pc.dim(model)}`);\n\n // Extract AI name from core.md\n const corePath = path.join(os.homedir(), \".acore\", \"core.md\");\n let aiName = \"Assistant\";\n if (fs.existsSync(corePath)) {\n const content = fs.readFileSync(corePath, \"utf-8\");\n const match = content.match(/^# (.+)$/m);\n if (match) aiName = match[1];\n }\n\n p.log.success(`${pc.bold(aiName)} is ready.`);\n\n // Session-start notifications\n const notifications = checkNotifications();\n displayNotifications(notifications);\n\n // Start MCP servers\n const mcpManager = new McpManager();\n\n p.log.step(\"Connecting to MCP servers...\");\n\n // Connect to aman-mcp (identity, tools, workflows, rules, eval)\n await mcpManager.connect(\"aman\", \"npx\", [\"-y\", \"@aman_asmuei/aman-mcp\"]);\n\n // Connect to amem (memory)\n await mcpManager.connect(\"amem\", \"npx\", [\"-y\", \"@aman_asmuei/amem\"]);\n\n const mcpTools = mcpManager.getTools();\n if (mcpTools.length > 0) {\n p.log.success(`${mcpTools.length} MCP tools available`);\n } else {\n p.log.info(\n \"No MCP tools connected (install aman-mcp or amem for tool support)\",\n );\n }\n\n // Convert ToolDef[] to ToolDefinition[] for the LLM\n const toolDefs = mcpTools.map((t) => ({\n name: t.name,\n description: t.description,\n input_schema: t.input_schema,\n }));\n\n // Create LLM client\n let client;\n if (config.provider === \"anthropic\") {\n client = createAnthropicClient(config.apiKey, model);\n } else if (config.provider === \"ollama\") {\n client = createOllamaClient(model);\n } else {\n client = createOpenAIClient(config.apiKey, model);\n }\n\n // Run the agent\n await runAgent(\n client,\n systemPrompt,\n aiName,\n model,\n toolDefs.length > 0 ? toolDefs : undefined,\n toolDefs.length > 0 ? mcpManager : undefined,\n );\n\n // Cleanup on exit\n await mcpManager.disconnect();\n });\n\nprogram\n .command(\"schedule\")\n .description(\"Manage scheduled tasks\")\n .argument(\"[action]\", \"add, list, or remove\")\n .argument(\"[id]\", \"task ID (for remove)\")\n .action(async (action?: string, id?: string) => {\n if (!action || action === \"list\") {\n const tasks = loadSchedules();\n if (tasks.length === 0) {\n console.log(pc.dim(\"No scheduled tasks.\"));\n return;\n }\n console.log(pc.bold(\"Scheduled tasks:\\n\"));\n for (const task of tasks) {\n const lastRun = task.lastRun\n ? pc.dim(` (last run: ${new Date(task.lastRun).toLocaleString()})`)\n : pc.dim(\" (never run)\");\n console.log(\n ` ${pc.cyan(task.id)} ${task.name} ${pc.dim(task.schedule)} [${task.mode}]${lastRun}`,\n );\n }\n return;\n }\n\n if (action === \"add\") {\n const name = (await p.text({\n message: \"Task name?\",\n validate: (v) => (v.length === 0 ? \"Name is required\" : undefined),\n })) as string;\n if (p.isCancel(name)) return;\n\n const schedule = (await p.select({\n message: \"Schedule?\",\n options: [\n { value: \"daily 9am\", label: \"Daily at 9am\" },\n { value: \"weekdays 9am\", label: \"Weekdays at 9am\" },\n { value: \"weekly friday 4pm\", label: \"Weekly Friday 4pm\" },\n { value: \"every 2h\", label: \"Every 2 hours\" },\n { value: \"every 4h\", label: \"Every 4 hours\" },\n ],\n })) as string;\n if (p.isCancel(schedule)) return;\n\n const actionType = (await p.select({\n message: \"What should happen?\",\n options: [\n { value: \"notify\", label: \"Show notification\" },\n { value: \"auto-run\", label: \"Run automatically\" },\n ],\n })) as \"notify\" | \"auto-run\";\n if (p.isCancel(actionType)) return;\n\n let taskAction = \"notify\";\n if (actionType === \"auto-run\") {\n const cmd = (await p.text({\n message: \"Command to run?\",\n placeholder: \"e.g. run:daily-standup\",\n validate: (v) =>\n v.length === 0 ? \"Command is required\" : undefined,\n })) as string;\n if (p.isCancel(cmd)) return;\n taskAction = cmd;\n }\n\n const task = addSchedule({\n name,\n schedule,\n action: taskAction,\n mode: actionType,\n });\n console.log(\n pc.green(`\\nScheduled task created: ${pc.bold(task.name)} (${task.id})`),\n );\n return;\n }\n\n if (action === \"remove\") {\n if (!id) {\n console.log(pc.red(\"Usage: aman-agent schedule remove <id>\"));\n return;\n }\n const removed = removeSchedule(id);\n if (removed) {\n console.log(pc.green(`Task ${id} removed.`));\n } else {\n console.log(pc.red(`Task ${id} not found.`));\n }\n return;\n }\n\n console.log(\n pc.red(`Unknown action: ${action}. Use add, list, or remove.`),\n );\n });\n\nprogram.parse();\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\n\nexport interface AgentConfig {\n provider: \"anthropic\" | \"openai\" | \"ollama\";\n apiKey: string;\n model: string;\n}\n\nconst CONFIG_DIR = path.join(os.homedir(), \".aman-agent\");\nconst CONFIG_PATH = path.join(CONFIG_DIR, \"config.json\");\n\nexport function loadConfig(): AgentConfig | null {\n if (!fs.existsSync(CONFIG_PATH)) return null;\n try {\n return JSON.parse(fs.readFileSync(CONFIG_PATH, \"utf-8\"));\n } catch {\n return null;\n }\n}\n\nexport function saveConfig(config: AgentConfig): void {\n fs.mkdirSync(CONFIG_DIR, { recursive: true });\n fs.writeFileSync(\n CONFIG_PATH,\n JSON.stringify(config, null, 2) + \"\\n\",\n \"utf-8\",\n );\n}\n\nexport function configExists(): boolean {\n return fs.existsSync(CONFIG_PATH);\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport { estimateTokens, buildBudgetedPrompt } from \"./token-budget.js\";\nimport type { PromptComponent } from \"./token-budget.js\";\n\ninterface EcosystemFile {\n name: string;\n dir: string;\n file: string;\n}\n\nconst ECOSYSTEM_FILES: EcosystemFile[] = [\n { name: \"identity\", dir: \".acore\", file: \"core.md\" },\n { name: \"tools\", dir: \".akit\", file: \"kit.md\" },\n { name: \"workflows\", dir: \".aflow\", file: \"flow.md\" },\n { name: \"guardrails\", dir: \".arules\", file: \"rules.md\" },\n { name: \"skills\", dir: \".askill\", file: \"skills.md\" },\n];\n\nexport function assembleSystemPrompt(maxTokens?: number): {\n prompt: string;\n layers: string[];\n truncated: string[];\n totalTokens: number;\n} {\n const home = os.homedir();\n const components: PromptComponent[] = [];\n\n for (const entry of ECOSYSTEM_FILES) {\n const filePath = path.join(home, entry.dir, entry.file);\n if (fs.existsSync(filePath)) {\n const content = fs.readFileSync(filePath, \"utf-8\").trim();\n components.push({\n name: entry.name,\n content,\n tokens: estimateTokens(content),\n });\n }\n }\n\n // Project context (not prioritized — appended as extra)\n const contextPath = path.join(process.cwd(), \".acore\", \"context.md\");\n if (fs.existsSync(contextPath)) {\n const content = fs.readFileSync(contextPath, \"utf-8\").trim();\n components.push({\n name: \"context\",\n content,\n tokens: estimateTokens(content),\n });\n }\n\n const budgeted = buildBudgetedPrompt(components, maxTokens);\n\n return {\n prompt: budgeted.prompt,\n layers: budgeted.included,\n truncated: budgeted.truncated,\n totalTokens: budgeted.totalTokens,\n };\n}\n","// Rough token estimation: ~1.3 tokens per word for English markdown\nexport function estimateTokens(text: string): number {\n return Math.round(text.split(/\\s+/).filter(Boolean).length * 1.3);\n}\n\n// Priority order for system prompt components (highest to lowest)\nconst PRIORITIES = [\n \"identity\", // core.md — always include\n \"guardrails\", // rules.md — safety critical\n \"workflows\", // flow.md — behavioral\n \"tools\", // kit.md — capabilities\n \"skills\", // skills.md — can be truncated\n];\n\nexport interface PromptComponent {\n name: string;\n content: string;\n tokens: number;\n}\n\nexport function buildBudgetedPrompt(\n components: PromptComponent[],\n maxTokens: number = 8000, // default budget for system prompt\n): { prompt: string; included: string[]; truncated: string[]; totalTokens: number } {\n const included: string[] = [];\n const truncated: string[] = [];\n const parts: string[] = [];\n let totalTokens = 0;\n\n // Sort by priority\n const sorted = [...components].sort((a, b) => {\n const aPri = PRIORITIES.indexOf(a.name);\n const bPri = PRIORITIES.indexOf(b.name);\n return (aPri === -1 ? 99 : aPri) - (bPri === -1 ? 99 : bPri);\n });\n\n for (const comp of sorted) {\n if (totalTokens + comp.tokens <= maxTokens) {\n parts.push(comp.content);\n included.push(comp.name);\n totalTokens += comp.tokens;\n } else {\n // Try to include a truncated version (first 50% of content)\n const halfContent = comp.content.slice(0, Math.floor(comp.content.length / 2));\n const halfTokens = estimateTokens(halfContent);\n if (totalTokens + halfTokens <= maxTokens) {\n parts.push(halfContent + \"\\n\\n[... truncated for context budget ...]\");\n included.push(comp.name + \" (partial)\");\n totalTokens += halfTokens;\n } else {\n truncated.push(comp.name);\n }\n }\n }\n\n return {\n prompt: parts.join(\"\\n\\n---\\n\\n\"),\n included,\n truncated,\n totalTokens,\n };\n}\n","import Anthropic from \"@anthropic-ai/sdk\";\nimport type {\n LLMClient,\n Message,\n StreamChunk,\n ToolDefinition,\n ChatResponse,\n ContentBlock,\n} from \"./types.js\";\n\nfunction toAnthropicMessages(\n messages: Message[],\n): Anthropic.Messages.MessageParam[] {\n return messages.map((m) => {\n if (typeof m.content === \"string\") {\n return { role: m.role, content: m.content };\n }\n // Complex content blocks (tool_use, tool_result, etc.)\n return {\n role: m.role,\n content: m.content.map((block) => {\n if (block.type === \"text\") {\n return { type: \"text\" as const, text: block.text };\n }\n if (block.type === \"tool_use\") {\n return {\n type: \"tool_use\" as const,\n id: block.id,\n name: block.name,\n input: block.input,\n };\n }\n if (block.type === \"tool_result\") {\n return {\n type: \"tool_result\" as const,\n tool_use_id: block.tool_use_id,\n content: block.content,\n };\n }\n return { type: \"text\" as const, text: \"\" };\n }),\n };\n });\n}\n\nexport function createAnthropicClient(\n apiKey: string,\n model: string,\n): LLMClient {\n const client = new Anthropic({ apiKey });\n\n return {\n async chat(\n systemPrompt: string,\n messages: Message[],\n onChunk: (chunk: StreamChunk) => void,\n tools?: ToolDefinition[],\n ): Promise<ChatResponse> {\n const anthropicMessages = toAnthropicMessages(messages);\n const hasTools = tools && tools.length > 0;\n\n try {\n if (hasTools) {\n // Non-streaming when tools are present for simpler tool_use handling\n const response = await client.messages.create({\n model,\n max_tokens: 8192,\n system: systemPrompt,\n messages: anthropicMessages,\n tools: tools.map((t) => ({\n name: t.name,\n description: t.description,\n input_schema: t.input_schema as Anthropic.Messages.Tool[\"input_schema\"],\n })),\n });\n\n const toolUses = response.content\n .filter(\n (block): block is Anthropic.Messages.ToolUseBlock =>\n block.type === \"tool_use\",\n )\n .map((block) => ({\n id: block.id,\n name: block.name,\n input: block.input as Record<string, unknown>,\n }));\n\n const textContent = response.content\n .filter(\n (block): block is Anthropic.Messages.TextBlock =>\n block.type === \"text\",\n )\n .map((block) => block.text)\n .join(\"\");\n\n // Stream text to output if there's text and no tool calls\n if (textContent && toolUses.length === 0) {\n onChunk({ type: \"text\", text: textContent });\n onChunk({ type: \"done\" });\n } else if (textContent) {\n // There's text alongside tool calls — show it\n onChunk({ type: \"text\", text: textContent });\n }\n\n // Build the content blocks for the message\n const contentBlocks: ContentBlock[] = response.content.map(\n (block) => {\n if (block.type === \"text\") {\n return { type: \"text\" as const, text: block.text };\n }\n // tool_use\n return {\n type: \"tool_use\" as const,\n id: (block as Anthropic.Messages.ToolUseBlock).id,\n name: (block as Anthropic.Messages.ToolUseBlock).name,\n input: (block as Anthropic.Messages.ToolUseBlock)\n .input as Record<string, unknown>,\n };\n },\n );\n\n return {\n message: {\n role: \"assistant\",\n content: toolUses.length > 0 ? contentBlocks : textContent,\n },\n toolUses,\n };\n } else {\n // Streaming when no tools — original behavior\n let fullText = \"\";\n\n const stream = await client.messages.create({\n model,\n max_tokens: 8192,\n system: systemPrompt,\n messages: anthropicMessages,\n stream: true,\n });\n\n for await (const event of stream) {\n if (\n event.type === \"content_block_delta\" &&\n event.delta.type === \"text_delta\"\n ) {\n const text = event.delta.text;\n fullText += text;\n onChunk({ type: \"text\", text });\n }\n }\n\n onChunk({ type: \"done\" });\n return {\n message: { role: \"assistant\", content: fullText },\n toolUses: [],\n };\n }\n } catch (error) {\n if (error instanceof Anthropic.AuthenticationError) {\n throw new Error(\n \"Invalid API key. Run with --model flag or delete ~/.aman-agent/config.json to reconfigure.\",\n );\n }\n if (error instanceof Anthropic.RateLimitError) {\n throw new Error(\"Rate limited by Anthropic. Please wait and retry.\");\n }\n throw error;\n }\n },\n };\n}\n","import OpenAI from \"openai\";\nimport type {\n LLMClient,\n Message,\n StreamChunk,\n ToolDefinition,\n ChatResponse,\n} from \"./types.js\";\n\nfunction toOpenAIMessages(\n systemPrompt: string,\n messages: Message[],\n): OpenAI.Chat.Completions.ChatCompletionMessageParam[] {\n const result: OpenAI.Chat.Completions.ChatCompletionMessageParam[] = [\n { role: \"system\", content: systemPrompt },\n ];\n\n for (const m of messages) {\n if (typeof m.content === \"string\") {\n result.push({\n role: m.role as \"user\" | \"assistant\",\n content: m.content,\n });\n } else if (m.role === \"assistant\") {\n // Assistant message with tool calls\n const textParts = m.content.filter((b) => b.type === \"text\");\n const toolUseParts = m.content.filter((b) => b.type === \"tool_use\");\n const text = textParts.map((b) => (\"text\" in b ? b.text : \"\")).join(\"\");\n\n if (toolUseParts.length > 0) {\n result.push({\n role: \"assistant\",\n content: text || null,\n tool_calls: toolUseParts.map((b) => ({\n id: \"id\" in b ? b.id : \"\",\n type: \"function\" as const,\n function: {\n name: \"name\" in b ? b.name : \"\",\n arguments: JSON.stringify(\"input\" in b ? b.input : {}),\n },\n })),\n });\n } else {\n result.push({ role: \"assistant\", content: text });\n }\n } else if (m.role === \"user\") {\n // Check if it contains tool results\n const toolResults = m.content.filter((b) => b.type === \"tool_result\");\n if (toolResults.length > 0) {\n for (const tr of toolResults) {\n if (tr.type === \"tool_result\") {\n result.push({\n role: \"tool\",\n tool_call_id: tr.tool_use_id,\n content: tr.content,\n });\n }\n }\n } else {\n const text = m.content\n .map((b) => (\"text\" in b ? b.text : \"\"))\n .join(\"\");\n result.push({ role: \"user\", content: text });\n }\n }\n }\n\n return result;\n}\n\nexport function createOpenAIClient(apiKey: string, model: string): LLMClient {\n const client = new OpenAI({ apiKey });\n\n return {\n async chat(\n systemPrompt: string,\n messages: Message[],\n onChunk: (chunk: StreamChunk) => void,\n tools?: ToolDefinition[],\n ): Promise<ChatResponse> {\n const openaiMessages = toOpenAIMessages(systemPrompt, messages);\n const hasTools = tools && tools.length > 0;\n\n try {\n if (hasTools) {\n // Non-streaming with tools\n const response = await client.chat.completions.create({\n model,\n max_tokens: 8192,\n messages: openaiMessages,\n tools: tools.map((t) => ({\n type: \"function\" as const,\n function: {\n name: t.name,\n description: t.description,\n parameters: t.input_schema,\n },\n })),\n });\n\n const choice = response.choices[0];\n const textContent = choice?.message?.content || \"\";\n const toolCalls = choice?.message?.tool_calls || [];\n\n const toolUses = toolCalls.map((tc) => ({\n id: tc.id,\n name: tc.function.name,\n input: JSON.parse(tc.function.arguments || \"{}\") as Record<\n string,\n unknown\n >,\n }));\n\n if (textContent && toolUses.length === 0) {\n onChunk({ type: \"text\", text: textContent });\n onChunk({ type: \"done\" });\n } else if (textContent) {\n onChunk({ type: \"text\", text: textContent });\n }\n\n // Build content blocks\n if (toolUses.length > 0) {\n const contentBlocks = [\n ...(textContent\n ? [{ type: \"text\" as const, text: textContent }]\n : []),\n ...toolUses.map((tu) => ({\n type: \"tool_use\" as const,\n id: tu.id,\n name: tu.name,\n input: tu.input,\n })),\n ];\n return {\n message: { role: \"assistant\", content: contentBlocks },\n toolUses,\n };\n }\n\n return {\n message: { role: \"assistant\", content: textContent },\n toolUses: [],\n };\n } else {\n // Streaming without tools — original behavior\n let fullText = \"\";\n\n const stream = await client.chat.completions.create({\n model,\n max_tokens: 8192,\n messages: openaiMessages,\n stream: true,\n });\n\n for await (const chunk of stream) {\n const text = chunk.choices[0]?.delta?.content || \"\";\n if (text) {\n fullText += text;\n onChunk({ type: \"text\", text });\n }\n }\n\n onChunk({ type: \"done\" });\n return {\n message: { role: \"assistant\", content: fullText },\n toolUses: [],\n };\n }\n } catch (error) {\n if (error instanceof OpenAI.AuthenticationError) {\n throw new Error(\n \"Invalid API key. Run with --model flag or delete ~/.aman-agent/config.json to reconfigure.\",\n );\n }\n if (error instanceof OpenAI.RateLimitError) {\n throw new Error(\"Rate limited by OpenAI. Please wait and retry.\");\n }\n throw error;\n }\n },\n };\n}\n","import OpenAI from \"openai\";\nimport type {\n LLMClient,\n Message,\n StreamChunk,\n ChatResponse,\n} from \"./types.js\";\n\nexport function createOllamaClient(\n model: string,\n baseURL?: string,\n): LLMClient {\n const client = new OpenAI({\n baseURL: baseURL || \"http://localhost:11434/v1\",\n apiKey: \"ollama\", // Ollama doesn't require a real key\n });\n\n return {\n async chat(\n systemPrompt: string,\n messages: Message[],\n onChunk: (chunk: StreamChunk) => void,\n _tools?, // Ollama doesn't support tool use — ignored\n ): Promise<ChatResponse> {\n let fullText = \"\";\n\n try {\n const stream = await client.chat.completions.create({\n model,\n max_tokens: 8192,\n messages: [\n { role: \"system\", content: systemPrompt },\n ...messages.map((m) => ({\n role: m.role as \"user\" | \"assistant\",\n content:\n typeof m.content === \"string\"\n ? m.content\n : m.content\n .filter((b) => b.type === \"text\")\n .map((b) => (\"text\" in b ? b.text : \"\"))\n .join(\"\"),\n })),\n ],\n stream: true,\n });\n\n for await (const chunk of stream) {\n const text = chunk.choices[0]?.delta?.content || \"\";\n if (text) {\n fullText += text;\n onChunk({ type: \"text\", text });\n }\n }\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes(\"ECONNREFUSED\")\n ) {\n throw new Error(\n \"Cannot connect to Ollama. Make sure it's running: ollama serve\",\n );\n }\n throw error;\n }\n\n onChunk({ type: \"done\" });\n return {\n message: { role: \"assistant\", content: fullText },\n toolUses: [],\n };\n },\n };\n}\n","import { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { StdioClientTransport } from \"@modelcontextprotocol/sdk/client/stdio.js\";\n\ninterface McpConnection {\n name: string;\n client: Client;\n transport: StdioClientTransport;\n}\n\nexport interface ToolDef {\n name: string;\n description: string;\n input_schema: Record<string, unknown>;\n serverName: string;\n}\n\nexport class McpManager {\n private connections: McpConnection[] = [];\n private tools: ToolDef[] = [];\n\n async connect(\n name: string,\n command: string,\n args: string[],\n ): Promise<void> {\n try {\n const transport = new StdioClientTransport({ command, args });\n const client = new Client({\n name: `aman-agent-${name}`,\n version: \"0.1.0\",\n });\n await client.connect(transport);\n\n this.connections.push({ name, client, transport });\n\n // List tools from this server\n const toolsResult = await client.listTools();\n for (const tool of toolsResult.tools) {\n this.tools.push({\n name: tool.name,\n description: tool.description || \"\",\n input_schema: tool.inputSchema as Record<string, unknown>,\n serverName: name,\n });\n }\n } catch {\n // Server not available — skip silently\n console.error(` Warning: Could not connect to ${name} MCP server`);\n }\n }\n\n getTools(): ToolDef[] {\n return this.tools;\n }\n\n async callTool(\n toolName: string,\n args: Record<string, unknown>,\n ): Promise<string> {\n const tool = this.tools.find((t) => t.name === toolName);\n if (!tool) return `Error: tool ${toolName} not found`;\n\n const conn = this.connections.find((c) => c.name === tool.serverName);\n if (!conn) return `Error: server ${tool.serverName} not connected`;\n\n try {\n const result = await conn.client.callTool({\n name: toolName,\n arguments: args,\n });\n // Extract text from result\n if (result.content && Array.isArray(result.content)) {\n return (result.content as Array<{ type: string; text?: string }>)\n .filter((c) => c.type === \"text\")\n .map((c) => c.text ?? \"\")\n .join(\"\\n\");\n }\n return JSON.stringify(result);\n } catch (error) {\n return `Error calling ${toolName}: ${error instanceof Error ? error.message : String(error)}`;\n }\n }\n\n async disconnect(): Promise<void> {\n for (const conn of this.connections) {\n try {\n await conn.client.close();\n } catch {\n /* ignore cleanup errors */\n }\n }\n this.connections = [];\n this.tools = [];\n }\n}\n","import * as readline from \"node:readline\";\nimport pc from \"picocolors\";\nimport type {\n LLMClient,\n Message,\n ToolDefinition,\n ToolResultBlock,\n} from \"./llm/types.js\";\nimport { handleCommand } from \"./commands.js\";\nimport { setReminder, clearReminders } from \"./reminders.js\";\nimport type { McpManager } from \"./mcp/client.js\";\n\nexport async function runAgent(\n client: LLMClient,\n systemPrompt: string,\n aiName: string,\n model: string,\n tools?: ToolDefinition[],\n mcpManager?: McpManager,\n): Promise<void> {\n const messages: Message[] = [];\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n // Handle Ctrl+C gracefully\n rl.on(\"SIGINT\", () => {\n console.log(pc.dim(\"\\nGoodbye.\\n\"));\n rl.close();\n process.exit(0);\n });\n\n const prompt = (): Promise<string> => {\n return new Promise<string>((resolve) => {\n rl.question(pc.green(\"\\nYou > \"), (answer) => {\n resolve(answer);\n });\n });\n };\n\n console.log(\n `\\nType a message, ${pc.dim(\"/help\")} for commands, or ${pc.dim(\"/quit\")} to exit.\\n`,\n );\n\n while (true) {\n const input = await prompt();\n if (!input.trim()) continue;\n\n // Handle slash commands\n const cmdResult = handleCommand(input, model);\n if (cmdResult.handled) {\n if (cmdResult.quit) {\n clearReminders();\n console.log(pc.dim(\"\\nGoodbye.\\n\"));\n rl.close();\n return;\n }\n if (cmdResult.remind) {\n const duration = setReminder(\n cmdResult.remind.timeStr,\n cmdResult.remind.message,\n );\n if (duration) {\n console.log(pc.dim(`Reminder set for ${duration} from now.`));\n } else {\n console.log(\n pc.red(\"Invalid time format. Use: 5m, 30m, 1h, 2h, tomorrow\"),\n );\n }\n continue;\n }\n if (cmdResult.output) {\n console.log(cmdResult.output);\n }\n if (cmdResult.clearHistory) {\n messages.length = 0;\n }\n continue;\n }\n\n // Send to LLM\n messages.push({ role: \"user\", content: input });\n\n process.stdout.write(pc.cyan(`\\n${aiName} > `));\n\n try {\n let response = await client.chat(\n systemPrompt,\n messages,\n (chunk) => {\n if (chunk.type === \"text\" && chunk.text) {\n process.stdout.write(chunk.text);\n }\n if (chunk.type === \"done\") {\n process.stdout.write(\"\\n\");\n }\n },\n tools,\n );\n\n // Add assistant message to history\n messages.push(response.message);\n\n // Agentic tool loop: execute tools until LLM stops requesting them\n while (response.toolUses.length > 0 && mcpManager) {\n const toolResults: ToolResultBlock[] = [];\n\n for (const toolUse of response.toolUses) {\n process.stdout.write(\n pc.dim(` [using ${toolUse.name}...]\\n`),\n );\n const result = await mcpManager.callTool(\n toolUse.name,\n toolUse.input,\n );\n toolResults.push({\n type: \"tool_result\",\n tool_use_id: toolUse.id,\n content: result,\n });\n }\n\n // Add tool results as a user message\n messages.push({\n role: \"user\",\n content: toolResults,\n });\n\n // Call LLM again with tool results\n response = await client.chat(\n systemPrompt,\n messages,\n (chunk) => {\n if (chunk.type === \"text\" && chunk.text) {\n process.stdout.write(chunk.text);\n }\n if (chunk.type === \"done\") {\n process.stdout.write(\"\\n\");\n }\n },\n tools,\n );\n\n // Add assistant response to history\n messages.push(response.message);\n }\n } catch (error) {\n const message =\n error instanceof Error ? error.message : \"Unknown error occurred\";\n console.error(pc.red(`\\nError: ${message}`));\n // Remove the user message that failed\n messages.pop();\n }\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport pc from \"picocolors\";\n\nexport interface CommandResult {\n handled: boolean;\n output?: string;\n quit?: boolean;\n clearHistory?: boolean;\n remind?: { timeStr: string; message: string };\n}\n\nfunction readEcosystemFile(filePath: string, label: string): string {\n if (!fs.existsSync(filePath)) {\n return pc.dim(`No ${label} file found at ${filePath}`);\n }\n return fs.readFileSync(filePath, \"utf-8\").trim();\n}\n\nexport function handleCommand(input: string, model?: string): CommandResult {\n const cmd = input.trim().toLowerCase();\n const home = os.homedir();\n\n if (cmd === \"/quit\" || cmd === \"/exit\" || cmd === \"/q\") {\n return { handled: true, quit: true };\n }\n\n if (cmd === \"/help\") {\n return {\n handled: true,\n output: [\n pc.bold(\"Commands:\"),\n ` ${pc.cyan(\"/help\")} Show this help`,\n ` ${pc.cyan(\"/identity\")} View your AI identity`,\n ` ${pc.cyan(\"/tools\")} View installed tools`,\n ` ${pc.cyan(\"/workflows\")} View defined workflows`,\n ` ${pc.cyan(\"/rules\")} View guardrails`,\n ` ${pc.cyan(\"/skills\")} View installed skills`,\n ` ${pc.cyan(\"/remind\")} Set a reminder (e.g. /remind 30m Review PR)`,\n ` ${pc.cyan(\"/model\")} Show current LLM model`,\n ` ${pc.cyan(\"/clear\")} Clear conversation history`,\n ` ${pc.cyan(\"/quit\")} Exit`,\n ].join(\"\\n\"),\n };\n }\n\n if (cmd === \"/identity\") {\n const content = readEcosystemFile(\n path.join(home, \".acore\", \"core.md\"),\n \"identity (acore)\",\n );\n return { handled: true, output: content };\n }\n\n if (cmd === \"/tools\") {\n const content = readEcosystemFile(\n path.join(home, \".akit\", \"kit.md\"),\n \"tools (akit)\",\n );\n return { handled: true, output: content };\n }\n\n if (cmd === \"/workflows\") {\n const content = readEcosystemFile(\n path.join(home, \".aflow\", \"flow.md\"),\n \"workflows (aflow)\",\n );\n return { handled: true, output: content };\n }\n\n if (cmd === \"/rules\") {\n const content = readEcosystemFile(\n path.join(home, \".arules\", \"rules.md\"),\n \"guardrails (arules)\",\n );\n return { handled: true, output: content };\n }\n\n if (cmd === \"/skills\") {\n const content = readEcosystemFile(\n path.join(home, \".askill\", \"skills.md\"),\n \"skills (askill)\",\n );\n return { handled: true, output: content };\n }\n\n if (cmd === \"/model\") {\n return {\n handled: true,\n output: model ? `Model: ${pc.bold(model)}` : \"Model: unknown\",\n };\n }\n\n if (cmd === \"/clear\") {\n return { handled: true, output: pc.dim(\"Conversation cleared.\"), clearHistory: true };\n }\n\n if (cmd.startsWith(\"/remind\")) {\n const parts = input.trim().split(/\\s+/);\n if (parts.length < 3) {\n return {\n handled: true,\n output:\n \"Usage: /remind <time> <message>\\nExamples: /remind 30m Review PR, /remind 2h Deploy, /remind tomorrow Check metrics\",\n };\n }\n const timeStr = parts[1];\n const message = parts.slice(2).join(\" \");\n return { handled: true, remind: { timeStr, message } };\n }\n\n if (cmd.startsWith(\"/\")) {\n return {\n handled: true,\n output: `Unknown command: ${cmd}. Type ${pc.cyan(\"/help\")} for available commands.`,\n };\n }\n\n return { handled: false };\n}\n","import pc from \"picocolors\";\n\ninterface Reminder {\n message: string;\n dueAt: number;\n timer?: ReturnType<typeof setTimeout>;\n}\n\nconst activeReminders: Reminder[] = [];\n\nexport function parseTime(timeStr: string): number | null {\n const match = timeStr.match(/^(\\d+)(m|h)$/);\n if (match) {\n const value = parseInt(match[1]);\n const unit = match[2];\n return unit === \"m\" ? value * 60 * 1000 : value * 60 * 60 * 1000;\n }\n if (timeStr === \"tomorrow\") return 24 * 60 * 60 * 1000;\n return null;\n}\n\nexport function setReminder(timeStr: string, message: string): string | null {\n const ms = parseTime(timeStr);\n if (!ms) return null;\n\n const reminder: Reminder = {\n message,\n dueAt: Date.now() + ms,\n };\n\n reminder.timer = setTimeout(() => {\n console.log(`\\n${pc.yellow(\"\\u23f0\")} ${pc.bold(\"Reminder:\")} ${message}`);\n const idx = activeReminders.indexOf(reminder);\n if (idx >= 0) activeReminders.splice(idx, 1);\n }, ms);\n\n activeReminders.push(reminder);\n\n const mins = Math.round(ms / 60000);\n if (mins < 60) return `${mins} minutes`;\n const hours = Math.round(mins / 60);\n return `${hours} hour${hours > 1 ? \"s\" : \"\"}`;\n}\n\nexport function clearReminders(): void {\n for (const r of activeReminders) {\n if (r.timer) clearTimeout(r.timer);\n }\n activeReminders.length = 0;\n}\n\nexport function getActiveCount(): number {\n return activeReminders.length;\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\n\nconst SCHEDULES_PATH = path.join(os.homedir(), \".aman-agent\", \"schedules.json\");\n\nexport interface ScheduledTask {\n id: string;\n name: string;\n schedule: string;\n action: string;\n mode: \"notify\" | \"auto-run\";\n createdAt: string;\n lastRun?: string;\n}\n\nexport function loadSchedules(): ScheduledTask[] {\n if (!fs.existsSync(SCHEDULES_PATH)) return [];\n try {\n return JSON.parse(fs.readFileSync(SCHEDULES_PATH, \"utf-8\"));\n } catch {\n return [];\n }\n}\n\nexport function saveSchedules(tasks: ScheduledTask[]): void {\n const dir = path.dirname(SCHEDULES_PATH);\n fs.mkdirSync(dir, { recursive: true });\n fs.writeFileSync(\n SCHEDULES_PATH,\n JSON.stringify(tasks, null, 2) + \"\\n\",\n \"utf-8\",\n );\n}\n\nexport function addSchedule(\n task: Omit<ScheduledTask, \"id\" | \"createdAt\">,\n): ScheduledTask {\n const tasks = loadSchedules();\n const newTask: ScheduledTask = {\n ...task,\n id: Date.now().toString(36),\n createdAt: new Date().toISOString(),\n };\n tasks.push(newTask);\n saveSchedules(tasks);\n return newTask;\n}\n\nexport function removeSchedule(id: string): boolean {\n const tasks = loadSchedules();\n const filtered = tasks.filter((t) => t.id !== id);\n if (filtered.length === tasks.length) return false;\n saveSchedules(filtered);\n return true;\n}\n\nexport function getDueTasks(): ScheduledTask[] {\n const tasks = loadSchedules();\n const now = new Date();\n return tasks.filter((task) => {\n if (!task.lastRun) return true;\n const lastRun = new Date(task.lastRun);\n return isDue(task.schedule, lastRun, now);\n });\n}\n\nexport function isDue(schedule: string, lastRun: Date, now: Date): boolean {\n const hoursSinceLastRun =\n (now.getTime() - lastRun.getTime()) / (1000 * 60 * 60);\n\n if (schedule.startsWith(\"every \")) {\n const match = schedule.match(/every (\\d+)h/);\n if (match) return hoursSinceLastRun >= parseInt(match[1]);\n }\n if (schedule === \"daily\" || schedule.startsWith(\"daily \")) {\n return hoursSinceLastRun >= 20;\n }\n if (schedule === \"weekdays\" || schedule.startsWith(\"weekdays \")) {\n const day = now.getDay();\n return day >= 1 && day <= 5 && hoursSinceLastRun >= 20;\n }\n if (schedule.startsWith(\"weekly\")) {\n return hoursSinceLastRun >= 144;\n }\n return false;\n}\n\nexport function markRun(id: string): void {\n const tasks = loadSchedules();\n const task = tasks.find((t) => t.id === id);\n if (task) {\n task.lastRun = new Date().toISOString();\n saveSchedules(tasks);\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport pc from \"picocolors\";\nimport { getDueTasks } from \"./scheduler.js\";\n\nexport interface Notification {\n type: \"schedule\" | \"eval\" | \"health\";\n message: string;\n}\n\nexport function checkNotifications(): Notification[] {\n const notifications: Notification[] = [];\n\n // Check due scheduled tasks\n const dueTasks = getDueTasks();\n for (const task of dueTasks) {\n notifications.push({\n type: \"schedule\",\n message: `${task.name} (${task.schedule})`,\n });\n }\n\n // Check aeval — sessions not logged recently\n const evalPath = path.join(os.homedir(), \".aeval\", \"eval.md\");\n if (fs.existsSync(evalPath)) {\n const content = fs.readFileSync(evalPath, \"utf-8\");\n const dateMatch = content.match(/- Last updated: (.+)$/m);\n if (dateMatch) {\n const lastDate = new Date(dateMatch[1]);\n const daysSince =\n (Date.now() - lastDate.getTime()) / (1000 * 60 * 60 * 24);\n if (daysSince > 3) {\n notifications.push({\n type: \"eval\",\n message: `No session logged in ${Math.floor(daysSince)} days \\u2014 run /eval to log one`,\n });\n }\n }\n }\n\n return notifications;\n}\n\nexport function displayNotifications(notifications: Notification[]): void {\n if (notifications.length === 0) return;\n\n console.log(\n pc.yellow(\n `\\n\\u26a0 ${notifications.length} notification${notifications.length > 1 ? \"s\" : \"\"}:`,\n ),\n );\n for (const n of notifications) {\n console.log(` - ${n.message}`);\n }\n console.log(\"\");\n}\n"],"mappings":"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","names":["pc","fs","path","os","text","os","path","fs","text","text","OpenAI","text","pc","fs","path","os","pc","pc","fs","path","os","fs","path","os","pc","path","os","fs","pc","fs","path","os","pc"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aman_asmuei/aman-agent",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Your AI companion, running locally — powered by the aman ecosystem",
5
5
  "type": "module",
6
6
  "bin": {
@@ -22,6 +22,7 @@
22
22
  "dependencies": {
23
23
  "@anthropic-ai/sdk": "^0.39.0",
24
24
  "@clack/prompts": "^0.9.1",
25
+ "@modelcontextprotocol/sdk": "^1.27.1",
25
26
  "commander": "^13.1.0",
26
27
  "openai": "^4.80.0",
27
28
  "picocolors": "^1.1.1"