activo 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.
Files changed (86) hide show
  1. package/FINAL_SIMPLIFIED_SPEC.md +456 -0
  2. package/README.md +62 -0
  3. package/TODO.md +193 -0
  4. package/dist/cli/banner.d.ts +3 -0
  5. package/dist/cli/banner.d.ts.map +1 -0
  6. package/dist/cli/banner.js +30 -0
  7. package/dist/cli/banner.js.map +1 -0
  8. package/dist/cli/headless.d.ts +3 -0
  9. package/dist/cli/headless.d.ts.map +1 -0
  10. package/dist/cli/headless.js +34 -0
  11. package/dist/cli/headless.js.map +1 -0
  12. package/dist/cli/index.d.ts +3 -0
  13. package/dist/cli/index.d.ts.map +1 -0
  14. package/dist/cli/index.js +42 -0
  15. package/dist/cli/index.js.map +1 -0
  16. package/dist/core/agent.d.ts +23 -0
  17. package/dist/core/agent.d.ts.map +1 -0
  18. package/dist/core/agent.js +171 -0
  19. package/dist/core/agent.js.map +1 -0
  20. package/dist/core/config.d.ts +24 -0
  21. package/dist/core/config.d.ts.map +1 -0
  22. package/dist/core/config.js +66 -0
  23. package/dist/core/config.js.map +1 -0
  24. package/dist/core/llm/ollama.d.ts +30 -0
  25. package/dist/core/llm/ollama.d.ts.map +1 -0
  26. package/dist/core/llm/ollama.js +173 -0
  27. package/dist/core/llm/ollama.js.map +1 -0
  28. package/dist/core/mcp/client.d.ts +22 -0
  29. package/dist/core/mcp/client.d.ts.map +1 -0
  30. package/dist/core/mcp/client.js +116 -0
  31. package/dist/core/mcp/client.js.map +1 -0
  32. package/dist/core/tools/builtIn.d.ts +9 -0
  33. package/dist/core/tools/builtIn.d.ts.map +1 -0
  34. package/dist/core/tools/builtIn.js +219 -0
  35. package/dist/core/tools/builtIn.js.map +1 -0
  36. package/dist/core/tools/index.d.ts +13 -0
  37. package/dist/core/tools/index.d.ts.map +1 -0
  38. package/dist/core/tools/index.js +43 -0
  39. package/dist/core/tools/index.js.map +1 -0
  40. package/dist/core/tools/standards.d.ts +6 -0
  41. package/dist/core/tools/standards.d.ts.map +1 -0
  42. package/dist/core/tools/standards.js +215 -0
  43. package/dist/core/tools/standards.js.map +1 -0
  44. package/dist/core/tools/types.d.ts +34 -0
  45. package/dist/core/tools/types.d.ts.map +1 -0
  46. package/dist/core/tools/types.js +2 -0
  47. package/dist/core/tools/types.js.map +1 -0
  48. package/dist/ui/App.d.ts +10 -0
  49. package/dist/ui/App.d.ts.map +1 -0
  50. package/dist/ui/App.js +167 -0
  51. package/dist/ui/App.js.map +1 -0
  52. package/dist/ui/components/InputBox.d.ts +11 -0
  53. package/dist/ui/components/InputBox.d.ts.map +1 -0
  54. package/dist/ui/components/InputBox.js +7 -0
  55. package/dist/ui/components/InputBox.js.map +1 -0
  56. package/dist/ui/components/MessageList.d.ts +17 -0
  57. package/dist/ui/components/MessageList.d.ts.map +1 -0
  58. package/dist/ui/components/MessageList.js +18 -0
  59. package/dist/ui/components/MessageList.js.map +1 -0
  60. package/dist/ui/components/StatusBar.d.ts +9 -0
  61. package/dist/ui/components/StatusBar.d.ts.map +1 -0
  62. package/dist/ui/components/StatusBar.js +6 -0
  63. package/dist/ui/components/StatusBar.js.map +1 -0
  64. package/dist/ui/components/ToolStatus.d.ts +8 -0
  65. package/dist/ui/components/ToolStatus.d.ts.map +1 -0
  66. package/dist/ui/components/ToolStatus.js +7 -0
  67. package/dist/ui/components/ToolStatus.js.map +1 -0
  68. package/package.json +64 -0
  69. package/screenshot.png +0 -0
  70. package/src/cli/banner.ts +34 -0
  71. package/src/cli/headless.ts +37 -0
  72. package/src/cli/index.ts +53 -0
  73. package/src/core/agent.ts +235 -0
  74. package/src/core/config.ts +98 -0
  75. package/src/core/llm/ollama.ts +238 -0
  76. package/src/core/mcp/client.ts +143 -0
  77. package/src/core/tools/builtIn.ts +221 -0
  78. package/src/core/tools/index.ts +53 -0
  79. package/src/core/tools/standards.ts +246 -0
  80. package/src/core/tools/types.ts +37 -0
  81. package/src/ui/App.tsx +238 -0
  82. package/src/ui/components/InputBox.tsx +37 -0
  83. package/src/ui/components/MessageList.tsx +80 -0
  84. package/src/ui/components/StatusBar.tsx +36 -0
  85. package/src/ui/components/ToolStatus.tsx +38 -0
  86. package/tsconfig.json +21 -0
@@ -0,0 +1,30 @@
1
+ import gradient from "gradient-string";
2
+ const ACTIVO_ASCII = `
3
+ _ ____ _____ _____ _____
4
+ / \\ / ___|_ _|_ _\\ \\ / / _ \\
5
+ / _ \\| | | | | | \\ \\ / / | | |
6
+ / ___ \\ |___ | | | | \\ V /| |_| |
7
+ /_/ \\_\\____| |_| |___| \\_/ \\___/
8
+ `;
9
+ const SUBTITLE = "AI-Powered Code Quality Analyzer";
10
+ const VERSION = "v0.2.0";
11
+ export function showBanner() {
12
+ const activoGradient = gradient(["#00d4ff", "#7b2ff7", "#f107a3"]);
13
+ console.log(activoGradient.multiline(ACTIVO_ASCII));
14
+ console.log();
15
+ console.log(` ${gradient(["#7b2ff7", "#00d4ff"])(SUBTITLE)} ${VERSION}`);
16
+ console.log();
17
+ console.log(" Type your request in natural language.");
18
+ console.log(" Examples:");
19
+ console.log(" • 이 프로젝트의 코드 품질을 분석해줘");
20
+ console.log(" • PDF 파일을 마크다운 규칙으로 변환해줘");
21
+ console.log(" • src 폴더의 명명규칙 위반을 찾아줘");
22
+ console.log();
23
+ console.log(" Press Ctrl+C twice to exit");
24
+ console.log("─".repeat(50));
25
+ console.log();
26
+ }
27
+ export function getShortBanner() {
28
+ return gradient(["#00d4ff", "#7b2ff7"])("ACTIVO") + " - Code Quality Analyzer";
29
+ }
30
+ //# sourceMappingURL=banner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"banner.js","sourceRoot":"","sources":["../../src/cli/banner.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,iBAAiB,CAAC;AAEvC,MAAM,YAAY,GAAG;;;;;;CAMpB,CAAC;AAEF,MAAM,QAAQ,GAAG,kCAAkC,CAAC;AACpD,MAAM,OAAO,GAAG,QAAQ,CAAC;AAEzB,MAAM,UAAU,UAAU;IACxB,MAAM,cAAc,GAAG,QAAQ,CAAC,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;IAEnE,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC;IACpD,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,KAAK,QAAQ,CAAC,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,OAAO,EAAE,CAAC,CAAC;IAC3E,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;IACxD,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAC3B,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;IACzC,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;IAC5C,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;IAC1C,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;IAC5C,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAC5B,OAAO,CAAC,GAAG,EAAE,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO,QAAQ,CAAC,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,0BAA0B,CAAC;AACjF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Config } from "../core/config.js";
2
+ export declare function runHeadless(prompt: string | undefined, config: Config): Promise<void>;
3
+ //# sourceMappingURL=headless.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headless.d.ts","sourceRoot":"","sources":["../../src/cli/headless.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAG3C,wBAAsB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA+B3F"}
@@ -0,0 +1,34 @@
1
+ import { OllamaClient } from "../core/llm/ollama.js";
2
+ import { processMessage } from "../core/agent.js";
3
+ import chalk from "chalk";
4
+ export async function runHeadless(prompt, config) {
5
+ if (!prompt) {
6
+ console.error(chalk.red("Error: Prompt is required in headless mode"));
7
+ console.error(chalk.yellow("Usage: activo -p \"your prompt here\""));
8
+ process.exit(1);
9
+ }
10
+ const client = new OllamaClient(config.ollama);
11
+ // Check connection
12
+ const isConnected = await client.isConnected();
13
+ if (!isConnected) {
14
+ console.error(chalk.red("Error: Cannot connect to Ollama"));
15
+ console.error(chalk.yellow(`Make sure Ollama is running at ${config.ollama.baseUrl}`));
16
+ process.exit(1);
17
+ }
18
+ try {
19
+ const result = await processMessage(prompt, [], client, config, (event) => {
20
+ if (event.type === "tool_use") {
21
+ console.error(chalk.dim(`[Tool] ${event.tool}: ${event.status}`));
22
+ }
23
+ else if (event.type === "thinking") {
24
+ // Skip thinking in headless mode
25
+ }
26
+ });
27
+ console.log(result.content);
28
+ }
29
+ catch (error) {
30
+ console.error(chalk.red(`Error: ${error}`));
31
+ process.exit(1);
32
+ }
33
+ }
34
+ //# sourceMappingURL=headless.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headless.js","sourceRoot":"","sources":["../../src/cli/headless.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAA0B,EAAE,MAAc;IAC1E,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC,CAAC;QACvE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,uCAAuC,CAAC,CAAC,CAAC;QACrE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAE/C,mBAAmB;IACnB,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;IAC/C,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC,CAAC;QAC5D,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,kCAAkC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QACvF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;YACxE,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBAC9B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YACpE,CAAC;iBAAM,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBACrC,iCAAiC;YACnC,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,KAAK,EAAE,CAAC,CAAC,CAAC;QAC5C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import { render } from "ink";
4
+ import React from "react";
5
+ import { App } from "../ui/App.js";
6
+ import { showBanner } from "./banner.js";
7
+ import { loadConfig } from "../core/config.js";
8
+ const program = new Command();
9
+ program
10
+ .name("activo")
11
+ .description("AI-powered code quality analyzer with Tool Calling and MCP support")
12
+ .version("0.2.0", "-v, --version", "Display version number");
13
+ program
14
+ .option("-p, --print", "Non-interactive mode (print and exit)")
15
+ .option("--headless", "Headless mode for CI/CD")
16
+ .option("--resume", "Resume from last session")
17
+ .option("--model <model>", "Specify Ollama model")
18
+ .argument("[prompt]", "Initial prompt")
19
+ .action(async (prompt, options) => {
20
+ // Show ASCII banner
21
+ showBanner();
22
+ // Load config
23
+ const config = loadConfig();
24
+ if (options.model) {
25
+ config.ollama.model = options.model;
26
+ }
27
+ // Headless/print mode
28
+ if (options.print || options.headless) {
29
+ const { runHeadless } = await import("./headless.js");
30
+ await runHeadless(prompt, config);
31
+ return;
32
+ }
33
+ // Interactive TUI mode
34
+ const { waitUntilExit } = render(React.createElement(App, {
35
+ initialPrompt: prompt,
36
+ config,
37
+ resume: options.resume,
38
+ }));
39
+ await waitUntilExit();
40
+ });
41
+ program.parse();
42
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,QAAQ,CAAC;KACd,WAAW,CAAC,oEAAoE,CAAC;KACjF,OAAO,CAAC,OAAO,EAAE,eAAe,EAAE,wBAAwB,CAAC,CAAC;AAE/D,OAAO;KACJ,MAAM,CAAC,aAAa,EAAE,uCAAuC,CAAC;KAC9D,MAAM,CAAC,YAAY,EAAE,yBAAyB,CAAC;KAC/C,MAAM,CAAC,UAAU,EAAE,0BAA0B,CAAC;KAC9C,MAAM,CAAC,iBAAiB,EAAE,sBAAsB,CAAC;KACjD,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC;KACtC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE;IAChC,oBAAoB;IACpB,UAAU,EAAE,CAAC;IAEb,cAAc;IACd,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAE5B,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,MAAM,CAAC,MAAM,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IACtC,CAAC;IAED,sBAAsB;IACtB,IAAI,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACtC,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC;QACtD,MAAM,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAClC,OAAO;IACT,CAAC;IAED,uBAAuB;IACvB,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,CAC9B,KAAK,CAAC,aAAa,CAAC,GAAG,EAAE;QACvB,aAAa,EAAE,MAAM;QACrB,MAAM;QACN,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC,CACH,CAAC;IAEF,MAAM,aAAa,EAAE,CAAC;AACxB,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { OllamaClient, ChatMessage } from "./llm/ollama.js";
2
+ import { Config } from "./config.js";
3
+ import { ToolResult } from "./tools/index.js";
4
+ export interface AgentEvent {
5
+ type: "thinking" | "content" | "tool_use" | "tool_result" | "done" | "error";
6
+ content?: string;
7
+ tool?: string;
8
+ status?: "start" | "complete" | "error";
9
+ args?: Record<string, unknown>;
10
+ result?: ToolResult;
11
+ error?: string;
12
+ }
13
+ export interface AgentResult {
14
+ content: string;
15
+ toolCalls: Array<{
16
+ tool: string;
17
+ args: Record<string, unknown>;
18
+ result: ToolResult;
19
+ }>;
20
+ }
21
+ export declare function processMessage(userMessage: string, history: ChatMessage[], client: OllamaClient, config: Config, onEvent?: (event: AgentEvent) => void): Promise<AgentResult>;
22
+ export declare function streamProcessMessage(userMessage: string, history: ChatMessage[], client: OllamaClient, config: Config, abortSignal?: AbortSignal): AsyncGenerator<AgentEvent>;
23
+ //# sourceMappingURL=agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/core/agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAsC,UAAU,EAAQ,MAAM,kBAAkB,CAAC;AAExF,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,UAAU,GAAG,SAAS,GAAG,UAAU,GAAG,aAAa,GAAG,MAAM,GAAG,OAAO,CAAC;IAC7E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,GAAG,UAAU,GAAG,OAAO,CAAC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,KAAK,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC9B,MAAM,EAAE,UAAU,CAAC;KACpB,CAAC,CAAC;CACJ;AA+BD,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,WAAW,EAAE,EACtB,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,GACpC,OAAO,CAAC,WAAW,CAAC,CA+EtB;AAED,wBAAuB,oBAAoB,CACzC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,WAAW,EAAE,EACtB,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,MAAM,EACd,WAAW,CAAC,EAAE,WAAW,GACxB,cAAc,CAAC,UAAU,CAAC,CAyF5B"}
@@ -0,0 +1,171 @@
1
+ import { getAllTools, executeTool } from "./tools/index.js";
2
+ const SYSTEM_PROMPT = `You are ACTIVO, an AI-powered code quality analyzer.
3
+
4
+ You help developers:
5
+ 1. Analyze code quality and find issues
6
+ 2. Import development standards from PDFs
7
+ 3. Check code against standards
8
+ 4. Navigate and understand codebases
9
+
10
+ You have access to these tools:
11
+ - read_file: Read file contents
12
+ - write_file: Write content to files
13
+ - list_directory: List directory contents
14
+ - grep_search: Search for patterns in files
15
+ - glob_search: Find files by pattern
16
+ - run_command: Execute shell commands
17
+ - import_pdf_standards: Convert PDF to markdown rules
18
+ - list_standards: List loaded standards
19
+ - check_code_quality: Check code against standards
20
+
21
+ When users ask in natural language, use the appropriate tools to help them.
22
+ Examples:
23
+ - "이 프로젝트 분석해줘" → Use list_directory, read_file to explore
24
+ - "PDF 규칙으로 변환해줘" → Use import_pdf_standards
25
+ - "코드 품질 검사해줘" → Use check_code_quality
26
+ - "UserService 찾아줘" → Use grep_search or glob_search
27
+
28
+ Always explain what you're doing and provide helpful insights.
29
+ Respond in the same language as the user's input.`;
30
+ export async function processMessage(userMessage, history, client, config, onEvent) {
31
+ const tools = getAllTools();
32
+ const toolDefinitions = tools.map((t) => ({
33
+ name: t.name,
34
+ description: t.description,
35
+ parameters: t.parameters,
36
+ }));
37
+ const messages = [
38
+ { role: "system", content: SYSTEM_PROMPT },
39
+ ...history,
40
+ { role: "user", content: userMessage },
41
+ ];
42
+ const toolCallResults = [];
43
+ let finalContent = "";
44
+ let iterations = 0;
45
+ const maxIterations = 10;
46
+ while (iterations < maxIterations) {
47
+ iterations++;
48
+ onEvent?.({ type: "thinking" });
49
+ const response = await client.chat(messages, tools);
50
+ messages.push(response);
51
+ // If no tool calls, we're done
52
+ if (!response.toolCalls?.length) {
53
+ finalContent = response.content;
54
+ break;
55
+ }
56
+ // Process tool calls
57
+ for (const toolCall of response.toolCalls) {
58
+ onEvent?.({
59
+ type: "tool_use",
60
+ tool: toolCall.name,
61
+ status: "start",
62
+ args: toolCall.arguments,
63
+ });
64
+ const result = await executeTool(toolCall);
65
+ onEvent?.({
66
+ type: "tool_result",
67
+ tool: toolCall.name,
68
+ status: result.success ? "complete" : "error",
69
+ result,
70
+ });
71
+ toolCallResults.push({
72
+ tool: toolCall.name,
73
+ args: toolCall.arguments,
74
+ result,
75
+ });
76
+ // Add tool result to messages
77
+ messages.push({
78
+ role: "tool",
79
+ content: result.success ? result.content : `Error: ${result.error}`,
80
+ toolCallId: toolCall.id,
81
+ });
82
+ }
83
+ // Continue the conversation with tool results
84
+ onEvent?.({ type: "content", content: response.content });
85
+ }
86
+ if (iterations >= maxIterations) {
87
+ onEvent?.({ type: "error", error: "Maximum iterations reached" });
88
+ }
89
+ onEvent?.({ type: "done" });
90
+ return {
91
+ content: finalContent,
92
+ toolCalls: toolCallResults,
93
+ };
94
+ }
95
+ export async function* streamProcessMessage(userMessage, history, client, config, abortSignal) {
96
+ const tools = getAllTools();
97
+ const messages = [
98
+ { role: "system", content: SYSTEM_PROMPT },
99
+ ...history,
100
+ { role: "user", content: userMessage },
101
+ ];
102
+ let iterations = 0;
103
+ const maxIterations = 10;
104
+ while (iterations < maxIterations) {
105
+ // Check if aborted
106
+ if (abortSignal?.aborted) {
107
+ yield { type: "error", error: "Operation cancelled" };
108
+ return;
109
+ }
110
+ iterations++;
111
+ yield { type: "thinking" };
112
+ let fullContent = "";
113
+ const pendingToolCalls = [];
114
+ for await (const event of client.streamChat(messages, tools, abortSignal)) {
115
+ // Check if aborted during streaming
116
+ if (abortSignal?.aborted) {
117
+ yield { type: "error", error: "Operation cancelled" };
118
+ return;
119
+ }
120
+ if (event.type === "content" && event.content) {
121
+ fullContent += event.content;
122
+ yield { type: "content", content: event.content };
123
+ }
124
+ else if (event.type === "tool_call" && event.toolCall) {
125
+ pendingToolCalls.push(event.toolCall);
126
+ }
127
+ else if (event.type === "error") {
128
+ yield { type: "error", error: event.error };
129
+ return;
130
+ }
131
+ }
132
+ messages.push({ role: "assistant", content: fullContent, toolCalls: pendingToolCalls.length > 0 ? pendingToolCalls : undefined });
133
+ // If no tool calls, we're done
134
+ if (pendingToolCalls.length === 0) {
135
+ break;
136
+ }
137
+ // Process tool calls
138
+ for (const toolCall of pendingToolCalls) {
139
+ // Check if aborted before each tool call
140
+ if (abortSignal?.aborted) {
141
+ yield { type: "error", error: "Operation cancelled" };
142
+ return;
143
+ }
144
+ yield {
145
+ type: "tool_use",
146
+ tool: toolCall.name,
147
+ status: "start",
148
+ args: toolCall.arguments,
149
+ };
150
+ const result = await executeTool(toolCall);
151
+ // Check if aborted after tool execution
152
+ if (abortSignal?.aborted) {
153
+ yield { type: "error", error: "Operation cancelled" };
154
+ return;
155
+ }
156
+ yield {
157
+ type: "tool_result",
158
+ tool: toolCall.name,
159
+ status: result.success ? "complete" : "error",
160
+ result,
161
+ };
162
+ messages.push({
163
+ role: "tool",
164
+ content: result.success ? result.content : `Error: ${result.error}`,
165
+ toolCallId: toolCall.id,
166
+ });
167
+ }
168
+ }
169
+ yield { type: "done" };
170
+ }
171
+ //# sourceMappingURL=agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/core/agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ export interface OllamaConfig {
2
+ baseUrl: string;
3
+ model: string;
4
+ contextLength: number;
5
+ keepAlive: number;
6
+ }
7
+ export interface Config {
8
+ ollama: OllamaConfig;
9
+ standards: {
10
+ directory: string;
11
+ };
12
+ mcp: {
13
+ servers: Record<string, MCPServerConfig>;
14
+ };
15
+ }
16
+ export interface MCPServerConfig {
17
+ command: string;
18
+ args?: string[];
19
+ env?: Record<string, string>;
20
+ }
21
+ export declare function loadConfig(): Config;
22
+ export declare function saveConfig(config: Config): void;
23
+ export declare function getProjectConfig(): Config;
24
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,MAAM;IACrB,MAAM,EAAE,YAAY,CAAC;IACrB,SAAS,EAAE;QACT,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,GAAG,EAAE;QACH,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;KAC1C,CAAC;CACH;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAqBD,wBAAgB,UAAU,IAAI,MAAM,CAkBnC;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAS/C;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAoBzC"}
@@ -0,0 +1,66 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import os from "os";
4
+ const DEFAULT_CONFIG = {
5
+ ollama: {
6
+ baseUrl: "http://localhost:11434",
7
+ model: "mistral:latest",
8
+ contextLength: 8192,
9
+ keepAlive: 1800, // 30 minutes
10
+ },
11
+ standards: {
12
+ directory: ".activo/standards",
13
+ },
14
+ mcp: {
15
+ servers: {},
16
+ },
17
+ };
18
+ function getConfigPath() {
19
+ return path.join(os.homedir(), ".activo", "config.json");
20
+ }
21
+ export function loadConfig() {
22
+ const configPath = getConfigPath();
23
+ if (fs.existsSync(configPath)) {
24
+ try {
25
+ const data = fs.readFileSync(configPath, "utf-8");
26
+ const loaded = JSON.parse(data);
27
+ return {
28
+ ollama: { ...DEFAULT_CONFIG.ollama, ...loaded.ollama },
29
+ standards: { ...DEFAULT_CONFIG.standards, ...loaded.standards },
30
+ mcp: { ...DEFAULT_CONFIG.mcp, ...loaded.mcp },
31
+ };
32
+ }
33
+ catch {
34
+ return DEFAULT_CONFIG;
35
+ }
36
+ }
37
+ return DEFAULT_CONFIG;
38
+ }
39
+ export function saveConfig(config) {
40
+ const configPath = getConfigPath();
41
+ const configDir = path.dirname(configPath);
42
+ if (!fs.existsSync(configDir)) {
43
+ fs.mkdirSync(configDir, { recursive: true });
44
+ }
45
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
46
+ }
47
+ export function getProjectConfig() {
48
+ const projectConfigPath = path.join(process.cwd(), ".activo", "config.json");
49
+ if (fs.existsSync(projectConfigPath)) {
50
+ try {
51
+ const data = fs.readFileSync(projectConfigPath, "utf-8");
52
+ const projectConfig = JSON.parse(data);
53
+ const globalConfig = loadConfig();
54
+ return {
55
+ ollama: { ...globalConfig.ollama, ...projectConfig.ollama },
56
+ standards: { ...globalConfig.standards, ...projectConfig.standards },
57
+ mcp: { ...globalConfig.mcp, ...projectConfig.mcp },
58
+ };
59
+ }
60
+ catch {
61
+ return loadConfig();
62
+ }
63
+ }
64
+ return loadConfig();
65
+ }
66
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { OllamaConfig } from "../config.js";
2
+ import { Tool, ToolCall } from "../tools/types.js";
3
+ export interface ChatMessage {
4
+ role: "system" | "user" | "assistant" | "tool";
5
+ content: string;
6
+ toolCalls?: ToolCall[];
7
+ toolCallId?: string;
8
+ }
9
+ export interface StreamEvent {
10
+ type: "content" | "tool_call" | "done" | "error";
11
+ content?: string;
12
+ toolCall?: ToolCall;
13
+ error?: string;
14
+ }
15
+ export declare class OllamaClient {
16
+ private baseUrl;
17
+ private model;
18
+ private contextLength;
19
+ private keepAlive;
20
+ constructor(config: OllamaConfig);
21
+ isConnected(): Promise<boolean>;
22
+ listModels(): Promise<string[]>;
23
+ chat(messages: ChatMessage[], tools?: Tool[]): Promise<ChatMessage>;
24
+ streamChat(messages: ChatMessage[], tools?: Tool[], abortSignal?: AbortSignal): AsyncGenerator<StreamEvent>;
25
+ private convertMessages;
26
+ private parseResponse;
27
+ getModel(): string;
28
+ setModel(model: string): void;
29
+ }
30
+ //# sourceMappingURL=ollama.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ollama.d.ts","sourceRoot":"","sources":["../../../src/core/llm/ollama.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAEnD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,SAAS,GAAG,WAAW,GAAG,MAAM,GAAG,OAAO,CAAC;IACjD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAiBD,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,SAAS,CAAS;gBAEd,MAAM,EAAE,YAAY;IAO1B,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAS/B,UAAU,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAO/B,IAAI,CACR,QAAQ,EAAE,WAAW,EAAE,EACvB,KAAK,CAAC,EAAE,IAAI,EAAE,GACb,OAAO,CAAC,WAAW,CAAC;IAwChB,UAAU,CACf,QAAQ,EAAE,WAAW,EAAE,EACvB,KAAK,CAAC,EAAE,IAAI,EAAE,EACd,WAAW,CAAC,EAAE,WAAW,GACxB,cAAc,CAAC,WAAW,CAAC;IAuF9B,OAAO,CAAC,eAAe;IAkBvB,OAAO,CAAC,aAAa;IAiBrB,QAAQ,IAAI,MAAM;IAIlB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;CAG9B"}
@@ -0,0 +1,173 @@
1
+ export class OllamaClient {
2
+ baseUrl;
3
+ model;
4
+ contextLength;
5
+ keepAlive;
6
+ constructor(config) {
7
+ this.baseUrl = config.baseUrl;
8
+ this.model = config.model;
9
+ this.contextLength = config.contextLength;
10
+ this.keepAlive = config.keepAlive;
11
+ }
12
+ async isConnected() {
13
+ try {
14
+ const response = await fetch(`${this.baseUrl}/api/tags`);
15
+ return response.ok;
16
+ }
17
+ catch {
18
+ return false;
19
+ }
20
+ }
21
+ async listModels() {
22
+ const response = await fetch(`${this.baseUrl}/api/tags`);
23
+ if (!response.ok)
24
+ throw new Error("Failed to list models");
25
+ const data = (await response.json());
26
+ return data.models.map((m) => m.name);
27
+ }
28
+ async chat(messages, tools) {
29
+ const ollamaMessages = this.convertMessages(messages);
30
+ const body = {
31
+ model: this.model,
32
+ messages: ollamaMessages,
33
+ stream: false,
34
+ options: {
35
+ num_ctx: this.contextLength,
36
+ },
37
+ keep_alive: this.keepAlive,
38
+ };
39
+ // Add tools if last message is from user
40
+ if (tools?.length && messages[messages.length - 1]?.role === "user") {
41
+ body.tools = tools.map((tool) => ({
42
+ type: "function",
43
+ function: {
44
+ name: tool.name,
45
+ description: tool.description,
46
+ parameters: tool.parameters,
47
+ },
48
+ }));
49
+ }
50
+ const response = await fetch(`${this.baseUrl}/api/chat`, {
51
+ method: "POST",
52
+ headers: { "Content-Type": "application/json" },
53
+ body: JSON.stringify(body),
54
+ });
55
+ if (!response.ok) {
56
+ const error = await response.text();
57
+ throw new Error(`Ollama error: ${error}`);
58
+ }
59
+ const data = (await response.json());
60
+ return this.parseResponse(data);
61
+ }
62
+ async *streamChat(messages, tools, abortSignal) {
63
+ const ollamaMessages = this.convertMessages(messages);
64
+ const body = {
65
+ model: this.model,
66
+ messages: ollamaMessages,
67
+ stream: true,
68
+ options: {
69
+ num_ctx: this.contextLength,
70
+ },
71
+ keep_alive: this.keepAlive,
72
+ };
73
+ if (tools?.length && messages[messages.length - 1]?.role === "user") {
74
+ body.tools = tools.map((tool) => ({
75
+ type: "function",
76
+ function: {
77
+ name: tool.name,
78
+ description: tool.description,
79
+ parameters: tool.parameters,
80
+ },
81
+ }));
82
+ }
83
+ const response = await fetch(`${this.baseUrl}/api/chat`, {
84
+ method: "POST",
85
+ headers: { "Content-Type": "application/json" },
86
+ body: JSON.stringify(body),
87
+ signal: abortSignal,
88
+ });
89
+ if (!response.ok) {
90
+ const error = await response.text();
91
+ yield { type: "error", error: `Ollama error: ${error}` };
92
+ return;
93
+ }
94
+ const reader = response.body?.getReader();
95
+ if (!reader) {
96
+ yield { type: "error", error: "No response body" };
97
+ return;
98
+ }
99
+ const decoder = new TextDecoder();
100
+ let buffer = "";
101
+ let accumulatedToolCalls = [];
102
+ while (true) {
103
+ const { done, value } = await reader.read();
104
+ if (done)
105
+ break;
106
+ buffer += decoder.decode(value, { stream: true });
107
+ const lines = buffer.split("\n");
108
+ buffer = lines.pop() || "";
109
+ for (const line of lines) {
110
+ if (!line.trim())
111
+ continue;
112
+ try {
113
+ const data = JSON.parse(line);
114
+ if (data.message?.content) {
115
+ yield { type: "content", content: data.message.content };
116
+ }
117
+ if (data.message?.tool_calls?.length) {
118
+ for (const tc of data.message.tool_calls) {
119
+ const toolCall = {
120
+ id: `tc_${Date.now()}_${Math.random().toString(36).slice(2)}`,
121
+ name: tc.function.name,
122
+ arguments: tc.function.arguments,
123
+ };
124
+ accumulatedToolCalls.push(toolCall);
125
+ yield { type: "tool_call", toolCall };
126
+ }
127
+ }
128
+ if (data.done) {
129
+ yield { type: "done" };
130
+ }
131
+ }
132
+ catch {
133
+ // Skip invalid JSON
134
+ }
135
+ }
136
+ }
137
+ }
138
+ convertMessages(messages) {
139
+ return messages.map((msg) => {
140
+ if (msg.role === "tool") {
141
+ return {
142
+ role: "tool",
143
+ content: msg.content,
144
+ };
145
+ }
146
+ return {
147
+ role: msg.role,
148
+ content: msg.content,
149
+ };
150
+ });
151
+ }
152
+ parseResponse(data) {
153
+ const result = {
154
+ role: "assistant",
155
+ content: data.message.content || "",
156
+ };
157
+ if (data.message.tool_calls?.length) {
158
+ result.toolCalls = data.message.tool_calls.map((tc, idx) => ({
159
+ id: `tc_${Date.now()}_${idx}`,
160
+ name: tc.function.name,
161
+ arguments: tc.function.arguments,
162
+ }));
163
+ }
164
+ return result;
165
+ }
166
+ getModel() {
167
+ return this.model;
168
+ }
169
+ setModel(model) {
170
+ this.model = model;
171
+ }
172
+ }
173
+ //# sourceMappingURL=ollama.js.map