@pentoshi/clai 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 (102) hide show
  1. package/README.md +287 -0
  2. package/bin/clai.mjs +2 -0
  3. package/dist/agent/runner.d.ts +12 -0
  4. package/dist/agent/runner.js +249 -0
  5. package/dist/agent/runner.js.map +1 -0
  6. package/dist/commands/doctor.d.ts +1 -0
  7. package/dist/commands/doctor.js +29 -0
  8. package/dist/commands/doctor.js.map +1 -0
  9. package/dist/commands/providers.d.ts +13 -0
  10. package/dist/commands/providers.js +137 -0
  11. package/dist/commands/providers.js.map +1 -0
  12. package/dist/commands/update.d.ts +5 -0
  13. package/dist/commands/update.js +123 -0
  14. package/dist/commands/update.js.map +1 -0
  15. package/dist/index.d.ts +1 -0
  16. package/dist/index.js +172 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/llm/anthropic.d.ts +2 -0
  19. package/dist/llm/anthropic.js +127 -0
  20. package/dist/llm/anthropic.js.map +1 -0
  21. package/dist/llm/gemini.d.ts +2 -0
  22. package/dist/llm/gemini.js +109 -0
  23. package/dist/llm/gemini.js.map +1 -0
  24. package/dist/llm/groq.d.ts +2 -0
  25. package/dist/llm/groq.js +49 -0
  26. package/dist/llm/groq.js.map +1 -0
  27. package/dist/llm/http.d.ts +35 -0
  28. package/dist/llm/http.js +112 -0
  29. package/dist/llm/http.js.map +1 -0
  30. package/dist/llm/ollama.d.ts +2 -0
  31. package/dist/llm/ollama.js +95 -0
  32. package/dist/llm/ollama.js.map +1 -0
  33. package/dist/llm/openai.d.ts +2 -0
  34. package/dist/llm/openai.js +49 -0
  35. package/dist/llm/openai.js.map +1 -0
  36. package/dist/llm/openrouter.d.ts +2 -0
  37. package/dist/llm/openrouter.js +55 -0
  38. package/dist/llm/openrouter.js.map +1 -0
  39. package/dist/llm/provider.d.ts +23 -0
  40. package/dist/llm/provider.js +58 -0
  41. package/dist/llm/provider.js.map +1 -0
  42. package/dist/llm/router.d.ts +8 -0
  43. package/dist/llm/router.js +103 -0
  44. package/dist/llm/router.js.map +1 -0
  45. package/dist/modes/agent.d.ts +17 -0
  46. package/dist/modes/agent.js +6 -0
  47. package/dist/modes/agent.js.map +1 -0
  48. package/dist/modes/ask.d.ts +8 -0
  49. package/dist/modes/ask.js +46 -0
  50. package/dist/modes/ask.js.map +1 -0
  51. package/dist/os/detect.d.ts +10 -0
  52. package/dist/os/detect.js +17 -0
  53. package/dist/os/detect.js.map +1 -0
  54. package/dist/os/pkgmgr.d.ts +6 -0
  55. package/dist/os/pkgmgr.js +32 -0
  56. package/dist/os/pkgmgr.js.map +1 -0
  57. package/dist/prompts/index.d.ts +2 -0
  58. package/dist/prompts/index.js +60 -0
  59. package/dist/prompts/index.js.map +1 -0
  60. package/dist/repl.d.ts +7 -0
  61. package/dist/repl.js +216 -0
  62. package/dist/repl.js.map +1 -0
  63. package/dist/safety/classifier.d.ts +8 -0
  64. package/dist/safety/classifier.js +118 -0
  65. package/dist/safety/classifier.js.map +1 -0
  66. package/dist/safety/patterns.d.ts +5 -0
  67. package/dist/safety/patterns.js +45 -0
  68. package/dist/safety/patterns.js.map +1 -0
  69. package/dist/store/config.d.ts +20 -0
  70. package/dist/store/config.js +46 -0
  71. package/dist/store/config.js.map +1 -0
  72. package/dist/store/history.d.ts +24 -0
  73. package/dist/store/history.js +145 -0
  74. package/dist/store/history.js.map +1 -0
  75. package/dist/store/keys.d.ts +10 -0
  76. package/dist/store/keys.js +115 -0
  77. package/dist/store/keys.js.map +1 -0
  78. package/dist/store/logs.d.ts +2 -0
  79. package/dist/store/logs.js +31 -0
  80. package/dist/store/logs.js.map +1 -0
  81. package/dist/store/project.d.ts +2 -0
  82. package/dist/store/project.js +14 -0
  83. package/dist/store/project.js.map +1 -0
  84. package/dist/tools/fs.d.ts +5 -0
  85. package/dist/tools/fs.js +82 -0
  86. package/dist/tools/fs.js.map +1 -0
  87. package/dist/tools/http.d.ts +6 -0
  88. package/dist/tools/http.js +14 -0
  89. package/dist/tools/http.js.map +1 -0
  90. package/dist/tools/registry.d.ts +5 -0
  91. package/dist/tools/registry.js +79 -0
  92. package/dist/tools/registry.js.map +1 -0
  93. package/dist/tools/shell.d.ts +7 -0
  94. package/dist/tools/shell.js +16 -0
  95. package/dist/tools/shell.js.map +1 -0
  96. package/dist/types.d.ts +40 -0
  97. package/dist/types.js +9 -0
  98. package/dist/types.js.map +1 -0
  99. package/dist/ui/banner.d.ts +12 -0
  100. package/dist/ui/banner.js +55 -0
  101. package/dist/ui/banner.js.map +1 -0
  102. package/package.json +66 -0
@@ -0,0 +1,8 @@
1
+ import type { CompletionRequest, CompletionResult, ProviderId } from "../types.js";
2
+ import type { LlmProvider, ProviderAuth } from "./provider.js";
3
+ export declare const providers: Record<ProviderId, LlmProvider>;
4
+ export declare function getProvider(provider: ProviderId): LlmProvider;
5
+ export declare function providerAuth(provider: ProviderId): Promise<ProviderAuth>;
6
+ export declare function completeWithProvider(request: CompletionRequest): Promise<CompletionResult>;
7
+ export declare function streamWithProvider(request: CompletionRequest, onToken: (token: string) => void): Promise<CompletionResult>;
8
+ export declare function pingProvider(providerId: ProviderId, secretOverride?: string): Promise<void>;
@@ -0,0 +1,103 @@
1
+ import { getConfig } from "../store/config.js";
2
+ import { getProviderSecret } from "../store/keys.js";
3
+ import { anthropicProvider } from "./anthropic.js";
4
+ import { geminiProvider } from "./gemini.js";
5
+ import { groqProvider } from "./groq.js";
6
+ import { ollamaProvider } from "./ollama.js";
7
+ import { openaiProvider } from "./openai.js";
8
+ import { openrouterProvider } from "./openrouter.js";
9
+ export const providers = {
10
+ groq: groqProvider,
11
+ gemini: geminiProvider,
12
+ openrouter: openrouterProvider,
13
+ openai: openaiProvider,
14
+ anthropic: anthropicProvider,
15
+ ollama: ollamaProvider,
16
+ };
17
+ const fallbackOrder = [
18
+ "groq",
19
+ "gemini",
20
+ "openrouter",
21
+ "openai",
22
+ "anthropic",
23
+ "ollama",
24
+ ];
25
+ export function getProvider(provider) {
26
+ return providers[provider];
27
+ }
28
+ export async function providerAuth(provider) {
29
+ const secret = await getProviderSecret(provider);
30
+ if (provider === "ollama") {
31
+ return { baseUrl: secret.value };
32
+ }
33
+ return { apiKey: secret.value };
34
+ }
35
+ export async function completeWithProvider(request) {
36
+ const config = getConfig();
37
+ const requested = request.provider ?? config.defaultProvider;
38
+ const order = [
39
+ requested,
40
+ ...fallbackOrder.filter((provider) => provider !== requested),
41
+ ];
42
+ const failures = [];
43
+ for (const providerId of order) {
44
+ const provider = providers[providerId];
45
+ const auth = await providerAuth(providerId);
46
+ const hasAuth = providerId === "ollama" ? Boolean(auth.baseUrl) : Boolean(auth.apiKey);
47
+ if (!hasAuth) {
48
+ failures.push(`${providerId}: no API key configured`);
49
+ continue;
50
+ }
51
+ try {
52
+ const model = providerId === requested
53
+ ? (request.model ?? provider.defaultModel)
54
+ : provider.defaultModel;
55
+ return await provider.complete({ ...request, provider: providerId, model }, auth);
56
+ }
57
+ catch (error) {
58
+ failures.push(`${providerId}: ${error instanceof Error ? error.message : String(error)}`);
59
+ }
60
+ }
61
+ throw new Error(`No provider could complete the request. ${failures.join(" | ")}`);
62
+ }
63
+ export async function streamWithProvider(request, onToken) {
64
+ const config = getConfig();
65
+ const requested = request.provider ?? config.defaultProvider;
66
+ const order = [
67
+ requested,
68
+ ...fallbackOrder.filter((provider) => provider !== requested),
69
+ ];
70
+ const failures = [];
71
+ for (const providerId of order) {
72
+ const provider = providers[providerId];
73
+ const auth = await providerAuth(providerId);
74
+ const hasAuth = providerId === "ollama" ? Boolean(auth.baseUrl) : Boolean(auth.apiKey);
75
+ if (!hasAuth) {
76
+ failures.push(`${providerId}: no API key configured`);
77
+ continue;
78
+ }
79
+ try {
80
+ const model = providerId === requested
81
+ ? (request.model ?? provider.defaultModel)
82
+ : provider.defaultModel;
83
+ if (provider.stream) {
84
+ return await provider.stream({ ...request, provider: providerId, model }, auth, onToken);
85
+ }
86
+ const result = await provider.complete({ ...request, provider: providerId, model }, auth);
87
+ onToken(result.text);
88
+ return result;
89
+ }
90
+ catch (error) {
91
+ failures.push(`${providerId}: ${error instanceof Error ? error.message : String(error)}`);
92
+ }
93
+ }
94
+ throw new Error(`No provider could stream the request. ${failures.join(" | ")}`);
95
+ }
96
+ export async function pingProvider(providerId, secretOverride) {
97
+ const provider = providers[providerId];
98
+ const auth = providerId === "ollama"
99
+ ? { baseUrl: secretOverride ?? (await providerAuth(providerId)).baseUrl }
100
+ : { apiKey: secretOverride ?? (await providerAuth(providerId)).apiKey };
101
+ await provider.ping(auth);
102
+ }
103
+ //# sourceMappingURL=router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/llm/router.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { ChatMessage, ProviderId, ToolCall } from "../types.js";
2
+ import { parseToolCall } from "../agent/runner.js";
3
+ export interface AgentOptions {
4
+ provider?: ProviderId | undefined;
5
+ model?: string | undefined;
6
+ history?: ChatMessage[] | undefined;
7
+ autoConfirm?: boolean | undefined;
8
+ maxSteps?: number | undefined;
9
+ onToolStart?: ((call: ToolCall) => void) | undefined;
10
+ onToolResult?: ((call: ToolCall, result: {
11
+ ok: boolean;
12
+ output: string;
13
+ exitCode?: number | undefined;
14
+ }) => void) | undefined;
15
+ }
16
+ export { parseToolCall };
17
+ export declare function runAgent(prompt: string, options?: AgentOptions): Promise<string>;
@@ -0,0 +1,6 @@
1
+ import { runAgentLoop, parseToolCall } from "../agent/runner.js";
2
+ export { parseToolCall };
3
+ export async function runAgent(prompt, options = {}) {
4
+ return runAgentLoop(prompt, options);
5
+ }
6
+ //# sourceMappingURL=agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/modes/agent.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAiBjE,OAAO,EAAE,aAAa,EAAE,CAAC;AAEzB,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,MAAc,EACd,UAAwB,EAAE;IAE1B,OAAO,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AACvC,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { ChatMessage, ProviderId } from "../types.js";
2
+ export interface AskOptions {
3
+ provider?: ProviderId | undefined;
4
+ model?: string | undefined;
5
+ history?: ChatMessage[] | undefined;
6
+ }
7
+ export declare function runAsk(prompt: string, options?: AskOptions): Promise<string>;
8
+ export declare function runAskStream(prompt: string, onToken: (token: string) => void, options?: AskOptions): Promise<string>;
@@ -0,0 +1,46 @@
1
+ import { completeWithProvider, streamWithProvider } from "../llm/router.js";
2
+ import { renderAskSystemPrompt } from "../prompts/index.js";
3
+ import { getConfig } from "../store/config.js";
4
+ import { ensureProviderConfigured } from "../commands/providers.js";
5
+ import { loadProjectContext } from "../store/project.js";
6
+ async function buildAskMessages(prompt, options) {
7
+ const config = getConfig();
8
+ const provider = options.provider ?? config.defaultProvider;
9
+ await ensureProviderConfigured(provider);
10
+ const projectContext = await loadProjectContext();
11
+ const systemPrompt = projectContext
12
+ ? `${renderAskSystemPrompt()}\n\nProject context from .clai/context.md:\n${projectContext}`
13
+ : renderAskSystemPrompt();
14
+ return {
15
+ provider,
16
+ model: options.model ?? config.defaultModel,
17
+ messages: [
18
+ { role: "system", content: systemPrompt },
19
+ ...(options.history ?? []),
20
+ { role: "user", content: prompt },
21
+ ],
22
+ };
23
+ }
24
+ export async function runAsk(prompt, options = {}) {
25
+ const request = await buildAskMessages(prompt, options);
26
+ const result = await completeWithProvider({
27
+ provider: request.provider,
28
+ model: request.model,
29
+ messages: request.messages,
30
+ temperature: 0.2,
31
+ maxTokens: 1_500,
32
+ });
33
+ return result.text;
34
+ }
35
+ export async function runAskStream(prompt, onToken, options = {}) {
36
+ const request = await buildAskMessages(prompt, options);
37
+ const result = await streamWithProvider({
38
+ provider: request.provider,
39
+ model: request.model,
40
+ messages: request.messages,
41
+ temperature: 0.2,
42
+ maxTokens: 1_500,
43
+ }, onToken);
44
+ return result.text;
45
+ }
46
+ //# sourceMappingURL=ask.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ask.js","sourceRoot":"","sources":["../../src/modes/ask.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAQzD,KAAK,UAAU,gBAAgB,CAC7B,MAAc,EACd,OAAmB;IAEnB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,MAAM,CAAC,eAAe,CAAC;IAC5D,MAAM,wBAAwB,CAAC,QAAQ,CAAC,CAAC;IACzC,MAAM,cAAc,GAAG,MAAM,kBAAkB,EAAE,CAAC;IAClD,MAAM,YAAY,GAAG,cAAc;QACjC,CAAC,CAAC,GAAG,qBAAqB,EAAE,+CAA+C,cAAc,EAAE;QAC3F,CAAC,CAAC,qBAAqB,EAAE,CAAC;IAC5B,OAAO;QACL,QAAQ;QACR,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,MAAM,CAAC,YAAY;QAC3C,QAAQ,EAAE;YACR,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE;YACzC,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;YAC1B,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE;SAClC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,MAAc,EACd,UAAsB,EAAE;IAExB,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxD,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC;QACxC,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,WAAW,EAAE,GAAG;QAChB,SAAS,EAAE,KAAK;KACjB,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,MAAc,EACd,OAAgC,EAChC,UAAsB,EAAE;IAExB,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxD,MAAM,MAAM,GAAG,MAAM,kBAAkB,CACrC;QACE,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,WAAW,EAAE,GAAG;QAChB,SAAS,EAAE,KAAK;KACjB,EACD,OAAO,CACR,CAAC;IACF,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC"}
@@ -0,0 +1,10 @@
1
+ export interface SystemInfo {
2
+ platform: NodeJS.Platform;
3
+ osName: string;
4
+ arch: string;
5
+ release: string;
6
+ shell: string;
7
+ cwd: string;
8
+ }
9
+ export declare function detectSystem(): SystemInfo;
10
+ export declare function isWindows(): boolean;
@@ -0,0 +1,17 @@
1
+ import { arch, platform, release, type } from 'node:os';
2
+ export function detectSystem() {
3
+ const currentPlatform = platform();
4
+ const osName = currentPlatform === 'darwin' ? 'macOS' : currentPlatform === 'win32' ? 'Windows' : type();
5
+ return {
6
+ platform: currentPlatform,
7
+ osName,
8
+ arch: arch(),
9
+ release: release(),
10
+ shell: process.env.SHELL ?? process.env.ComSpec ?? 'unknown',
11
+ cwd: process.cwd(),
12
+ };
13
+ }
14
+ export function isWindows() {
15
+ return process.platform === 'win32';
16
+ }
17
+ //# sourceMappingURL=detect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.js","sourceRoot":"","sources":["../../src/os/detect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAWxD,MAAM,UAAU,YAAY;IAC1B,MAAM,eAAe,GAAG,QAAQ,EAAE,CAAC;IACnC,MAAM,MAAM,GAAG,eAAe,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACzG,OAAO;QACL,QAAQ,EAAE,eAAe;QACzB,MAAM;QACN,IAAI,EAAE,IAAI,EAAE;QACZ,OAAO,EAAE,OAAO,EAAE;QAClB,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,SAAS;QAC5D,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;KACnB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,OAAO,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC;AACtC,CAAC"}
@@ -0,0 +1,6 @@
1
+ export interface PackageManager {
2
+ id: 'brew' | 'apt' | 'dnf' | 'pacman' | 'winget' | 'choco' | 'unknown';
3
+ installCommand(tool: string): string;
4
+ }
5
+ export declare function detectPackageManager(): Promise<PackageManager>;
6
+ export declare function commandAvailable(command: string): Promise<boolean>;
@@ -0,0 +1,32 @@
1
+ import { execa } from 'execa';
2
+ async function commandExists(command) {
3
+ try {
4
+ await execa(process.platform === 'win32' ? 'where' : 'which', [command]);
5
+ return true;
6
+ }
7
+ catch {
8
+ return false;
9
+ }
10
+ }
11
+ export async function detectPackageManager() {
12
+ if (process.platform === 'darwin' && (await commandExists('brew'))) {
13
+ return { id: 'brew', installCommand: (tool) => `brew install ${tool}` };
14
+ }
15
+ if (process.platform === 'win32') {
16
+ if (await commandExists('winget'))
17
+ return { id: 'winget', installCommand: (tool) => `winget install ${tool}` };
18
+ if (await commandExists('choco'))
19
+ return { id: 'choco', installCommand: (tool) => `choco install ${tool}` };
20
+ }
21
+ if (await commandExists('apt'))
22
+ return { id: 'apt', installCommand: (tool) => `sudo apt update && sudo apt install -y ${tool}` };
23
+ if (await commandExists('dnf'))
24
+ return { id: 'dnf', installCommand: (tool) => `sudo dnf install -y ${tool}` };
25
+ if (await commandExists('pacman'))
26
+ return { id: 'pacman', installCommand: (tool) => `sudo pacman -S --needed ${tool}` };
27
+ return { id: 'unknown', installCommand: (tool) => `Install ${tool} with your OS package manager` };
28
+ }
29
+ export async function commandAvailable(command) {
30
+ return commandExists(command);
31
+ }
32
+ //# sourceMappingURL=pkgmgr.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pkgmgr.js","sourceRoot":"","sources":["../../src/os/pkgmgr.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAO9B,KAAK,UAAU,aAAa,CAAC,OAAe;IAC1C,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;QACzE,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB;IACxC,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;QACnE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,gBAAgB,IAAI,EAAE,EAAE,CAAC;IAC1E,CAAC;IAED,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,IAAI,MAAM,aAAa,CAAC,QAAQ,CAAC;YAAE,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,kBAAkB,IAAI,EAAE,EAAE,CAAC;QAC/G,IAAI,MAAM,aAAa,CAAC,OAAO,CAAC;YAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,iBAAiB,IAAI,EAAE,EAAE,CAAC;IAC9G,CAAC;IAED,IAAI,MAAM,aAAa,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,0CAA0C,IAAI,EAAE,EAAE,CAAC;IACjI,IAAI,MAAM,aAAa,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,uBAAuB,IAAI,EAAE,EAAE,CAAC;IAC9G,IAAI,MAAM,aAAa,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,2BAA2B,IAAI,EAAE,EAAE,CAAC;IAExH,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,cAAc,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,IAAI,+BAA+B,EAAE,CAAC;AACrG,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,OAAe;IACpD,OAAO,aAAa,CAAC,OAAO,CAAC,CAAC;AAChC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function renderAskSystemPrompt(): string;
2
+ export declare function renderAgentSystemPrompt(toolList: string): string;
@@ -0,0 +1,60 @@
1
+ import { detectSystem } from '../os/detect.js';
2
+ const askPrompt = 'You are clai in /ask mode. Do NOT execute anything. For every user request, respond with: (1) one-line summary, (2) exact commands for their OS ({{os}}, shell={{shell}}), (3) what each command does, (4) caveats / safer alternatives.';
3
+ const agentPrompt = `You are clai, a terminal AI agent for cybersecurity, pentesting, and sysadmin.
4
+ OS: {{os}} | Shell: {{shell}} | CWD: {{cwd}}
5
+
6
+ TOOLS (use EXACT arg names — wrong names = failure):
7
+ - shell.exec: {"command":"<cmd>"} — run any shell command. Use full paths. cd does NOT work.
8
+ - fs.read: {"path":"<file>"} — read a file
9
+ - fs.write: {"path":"<file>","content":"<data>"} — write a file
10
+ - fs.list: {"path":"<dir>"} — list directory
11
+ - fs.search: {"pattern":"<regex>","path":"<dir>"} — search file CONTENTS (NOT filenames)
12
+ - pkg.install: {"tool":"<name>"} — install package (only if user asks or command not found)
13
+ - net.scan: {"target":"<ip/host>","ports":"<optional>"} — nmap scan
14
+ - http.fetch: {"url":"<url>","method":"<optional>","body":"<optional>"} — HTTP request
15
+ - sysinfo: {} — OS info
16
+ - pentest.recon: {"target":"<ip/host>"} — whois + dig + nmap
17
+
18
+ FORMAT — one tool per response:
19
+ \`\`\`tool
20
+ {"name":"shell.exec","args":{"command":"curl -s ifconfig.me"}}
21
+ \`\`\`
22
+
23
+ RULES:
24
+ 1. STAY ON TASK. Do EXACTLY what the user asked. Do NOT add extra scans, installs, or exploration.
25
+ 2. One tool per response. 1-2 lines of thinking MAX before the tool block.
26
+ 3. To find files/dirs by name: shell.exec find /path -maxdepth 3 -name '*pattern*'
27
+ 4. CONTINUE until the original task is done. Resolve sub-problems then proceed.
28
+ 5. Use conversation history for follow-ups. "it", "that", "such" = context from previous messages.
29
+ 6. Suppress noise: curl -s, wget -q. Always use full absolute paths.
30
+ 7. Never run cd, pwd, or re-list directories you already listed.
31
+ 8. Only pentest systems the user owns or has permission to test.
32
+
33
+ EXAMPLE — user asks "directory scan on example.com, seclists in /opt":
34
+ Step 1: Find the wordlist → shell.exec find /opt -maxdepth 3 -type d -name 'Discovery'
35
+ Step 2: List wordlists → fs.list /opt/wordlist/SecLists/Discovery/Web-Content
36
+ Step 3: Run scan → shell.exec gobuster dir -u https://example.com -w /opt/wordlist/SecLists/Discovery/Web-Content/common.txt -q
37
+ Step 4: Report findings. DONE.
38
+ Do NOT: scan localhost, fetch random ports, search file contents, install tools, or do anything else.`;
39
+ function render(template, values) {
40
+ return Object.entries(values).reduce((current, [key, value]) => current.replaceAll(`{{${key}}}`, value), template);
41
+ }
42
+ export function renderAskSystemPrompt() {
43
+ const system = detectSystem();
44
+ return render(askPrompt, {
45
+ os: `${system.osName} ${system.release} ${system.arch}`,
46
+ shell: system.shell,
47
+ cwd: system.cwd,
48
+ tool_list: 'none',
49
+ });
50
+ }
51
+ export function renderAgentSystemPrompt(toolList) {
52
+ const system = detectSystem();
53
+ return render(agentPrompt, {
54
+ os: `${system.osName} ${system.release} ${system.arch}`,
55
+ shell: system.shell,
56
+ cwd: system.cwd,
57
+ tool_list: toolList,
58
+ });
59
+ }
60
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,MAAM,SAAS,GAAG,0OAA0O,CAAC;AAE7P,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sGAmCkF,CAAC;AAGvG,SAAS,MAAM,CAAC,QAAgB,EAAE,MAA8B;IAC9D,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,GAAG,IAAI,EAAE,KAAK,CAAC,EAAE,QAAQ,CAAC,CAAC;AACrH,CAAC;AAED,MAAM,UAAU,qBAAqB;IACnC,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,OAAO,MAAM,CAAC,SAAS,EAAE;QACvB,EAAE,EAAE,GAAG,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,IAAI,EAAE;QACvD,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,SAAS,EAAE,MAAM;KAClB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,QAAgB;IACtD,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,OAAO,MAAM,CAAC,WAAW,EAAE;QACzB,EAAE,EAAE,GAAG,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,IAAI,EAAE;QACvD,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,SAAS,EAAE,QAAQ;KACpB,CAAC,CAAC;AACL,CAAC"}
package/dist/repl.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ import type { Mode, ProviderId } from "./types.js";
2
+ export interface ReplOptions {
3
+ mode?: Mode | undefined;
4
+ provider?: ProviderId | undefined;
5
+ model?: string | undefined;
6
+ }
7
+ export declare function startRepl(options?: ReplOptions): Promise<void>;
package/dist/repl.js ADDED
@@ -0,0 +1,216 @@
1
+ import readline from "node:readline/promises";
2
+ import { stdin as input, stdout as output } from "node:process";
3
+ import chalk from "chalk";
4
+ import { runAskStream } from "./modes/ask.js";
5
+ import { runAgent } from "./modes/agent.js";
6
+ import { providerSwitcher, printProviderKeys, setProviderKey, unsetProviderKey, } from "./commands/providers.js";
7
+ import { getConfig, getProviderModel, setDefaultMode, setProviderModel, updateConfig, } from "./store/config.js";
8
+ import { listSessions, saveSession } from "./store/history.js";
9
+ import { assertProvider } from "./llm/provider.js";
10
+ import { runUpdate, checkForUpdateSilent, getCurrentVersion } from "./commands/update.js";
11
+ import { renderBanner, renderSessionInfo, renderSuggestions, renderModeSwitch, renderProviderSwitch, PROMPT, } from "./ui/banner.js";
12
+ function splitCommand(line) {
13
+ return (line
14
+ .match(/(?:[^\s"]+|"[^"]*")+/g)
15
+ ?.map((part) => part.replace(/^"|"$/g, "")) ?? []);
16
+ }
17
+ function help() {
18
+ const cmds = [
19
+ ["/ask", "switch to ask mode"],
20
+ ["/agent", "switch to agent mode"],
21
+ ["/model <name>", "switch model"],
22
+ ["/provider [name]", "switch provider or open picker"],
23
+ ["/use <provider>", "alias for /provider <name>"],
24
+ ["/set <provider> [key]", "store API key"],
25
+ ["/unset <provider>", "remove key"],
26
+ ["/keys", "list configured providers"],
27
+ ["/clear", "clear context"],
28
+ ["/history", "show past sessions"],
29
+ ["/save <name>", "save session"],
30
+ ["/cwd <path>", "change working directory"],
31
+ ["/allow <tool>", "allow a tool for session"],
32
+ ["/update", "check for updates"],
33
+ ["/exit", "quit"],
34
+ ["/help", "list commands"],
35
+ ];
36
+ const maxCmd = Math.max(...cmds.map((c) => c[0].length));
37
+ return cmds
38
+ .map((c) => ` ${chalk.cyan(c[0].padEnd(maxCmd + 2))}${chalk.dim(c[1])}`)
39
+ .join("\n");
40
+ }
41
+ async function handleSlash(line, state) {
42
+ const [command, ...args] = splitCommand(line);
43
+ switch (command) {
44
+ case "/ask":
45
+ state.mode = "ask";
46
+ setDefaultMode("ask");
47
+ console.log(renderModeSwitch("ask"));
48
+ return true;
49
+ case "/agent":
50
+ state.mode = "agent";
51
+ setDefaultMode("agent");
52
+ console.log(renderModeSwitch("agent"));
53
+ return true;
54
+ case "/model": {
55
+ const model = args.join(" ");
56
+ if (!model)
57
+ console.log(chalk.dim("usage: /model <name>"));
58
+ else {
59
+ state.model = model;
60
+ setProviderModel(state.provider, model);
61
+ console.log(renderProviderSwitch(state.provider, model));
62
+ }
63
+ return true;
64
+ }
65
+ case "/provider":
66
+ case "/use": {
67
+ await providerSwitcher(args[0]);
68
+ const config = getConfig();
69
+ state.provider = config.defaultProvider;
70
+ state.model = getProviderModel(state.provider);
71
+ console.log(renderProviderSwitch(state.provider, state.model));
72
+ return true;
73
+ }
74
+ case "/set": {
75
+ if (!args[0])
76
+ console.log(chalk.dim("usage: /set <provider> [key]"));
77
+ else
78
+ await setProviderKey(args[0], args[1], {});
79
+ return true;
80
+ }
81
+ case "/unset": {
82
+ if (!args[0])
83
+ console.log(chalk.dim("usage: /unset <provider>"));
84
+ else
85
+ await unsetProviderKey(args[0]);
86
+ return true;
87
+ }
88
+ case "/keys":
89
+ await printProviderKeys();
90
+ return true;
91
+ case "/clear":
92
+ state.messages.length = 0;
93
+ console.log(chalk.dim(" context cleared"));
94
+ return true;
95
+ case "/history": {
96
+ const sessions = await listSessions();
97
+ if (sessions.length === 0)
98
+ console.log(chalk.dim(" no saved sessions"));
99
+ for (const session of sessions) {
100
+ console.log(chalk.dim(" ") +
101
+ `${session.createdAt} ${session.name ?? session.id} ${chalk.dim(`(${session.messages.length} msgs)`)}`);
102
+ }
103
+ return true;
104
+ }
105
+ case "/save": {
106
+ const record = await saveSession(state.messages, args.join(" ") || undefined);
107
+ console.log(chalk.dim(` saved session ${record.id}`));
108
+ return true;
109
+ }
110
+ case "/cwd": {
111
+ const dir = args.join(" ");
112
+ if (!dir)
113
+ console.log(chalk.dim(` ${process.cwd()}`));
114
+ else {
115
+ process.chdir(dir);
116
+ const config = getConfig();
117
+ updateConfig({
118
+ sandboxRoots: Array.from(new Set([...config.sandboxRoots, process.cwd()])),
119
+ });
120
+ console.log(chalk.dim(` cwd → ${process.cwd()}`));
121
+ }
122
+ return true;
123
+ }
124
+ case "/allow": {
125
+ const tool = args[0];
126
+ if (!tool)
127
+ console.log(chalk.dim("usage: /allow <tool>"));
128
+ else {
129
+ const config = getConfig();
130
+ updateConfig({
131
+ allowAlwaysTools: Array.from(new Set([...config.allowAlwaysTools, tool])),
132
+ });
133
+ console.log(chalk.dim(` allowed ${tool} ✓`));
134
+ }
135
+ return true;
136
+ }
137
+ case "/exit":
138
+ case "/quit":
139
+ return false;
140
+ case "/update":
141
+ await runUpdate();
142
+ return true;
143
+ case "/help":
144
+ console.log(help());
145
+ return true;
146
+ default:
147
+ console.log(chalk.dim(` unknown command: ${command}. Try /help`));
148
+ return true;
149
+ }
150
+ }
151
+ export async function startRepl(options = {}) {
152
+ const config = getConfig();
153
+ const state = {
154
+ mode: options.mode ?? config.defaultMode,
155
+ provider: options.provider ?? config.defaultProvider,
156
+ model: options.model ?? config.defaultModel,
157
+ messages: [],
158
+ };
159
+ if (options.provider) {
160
+ state.provider = assertProvider(options.provider);
161
+ }
162
+ const rl = readline.createInterface({ input, output });
163
+ // ── Startup banner ──────────────────────────────────────────────────────
164
+ console.log(renderBanner(getCurrentVersion()));
165
+ console.log(renderSessionInfo({
166
+ workdir: process.cwd(),
167
+ model: state.model,
168
+ provider: state.provider,
169
+ mode: state.mode,
170
+ }));
171
+ console.log(renderSuggestions());
172
+ console.log();
173
+ // Non-blocking update check
174
+ checkForUpdateSilent();
175
+ try {
176
+ while (true) {
177
+ const line = (await rl.question(PROMPT)).trim();
178
+ if (!line)
179
+ continue;
180
+ if (line.startsWith("/")) {
181
+ const shouldContinue = await handleSlash(line, state);
182
+ if (!shouldContinue)
183
+ break;
184
+ continue;
185
+ }
186
+ try {
187
+ const answer = state.mode === "ask"
188
+ ? await runAskStream(line, (token) => process.stdout.write(token), {
189
+ provider: state.provider,
190
+ model: state.model,
191
+ history: state.messages,
192
+ })
193
+ : await runAgent(line, {
194
+ provider: state.provider,
195
+ model: state.model,
196
+ history: state.messages,
197
+ });
198
+ if (state.mode === "ask") {
199
+ process.stdout.write("\n");
200
+ }
201
+ console.log(); // breathing room between exchanges
202
+ state.messages.push({ role: "user", content: line }, { role: "assistant", content: answer });
203
+ }
204
+ catch (error) {
205
+ console.error(chalk.red(error instanceof Error ? error.message : String(error)));
206
+ }
207
+ }
208
+ }
209
+ finally {
210
+ if (state.messages.length > 0) {
211
+ await saveSession(state.messages, `repl-${new Date().toISOString()}`);
212
+ }
213
+ rl.close();
214
+ }
215
+ }
216
+ //# sourceMappingURL=repl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repl.js","sourceRoot":"","sources":["../src/repl.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { RiskLevel, ToolCall } from "../types.js";
2
+ export interface RiskDecision {
3
+ level: RiskLevel;
4
+ reason: string;
5
+ }
6
+ export declare function isPrivateIpv4(value: string): boolean;
7
+ export declare function isPentestToolCall(call: ToolCall): boolean;
8
+ export declare function classifyToolCall(call: ToolCall): RiskDecision;