chainlesschain 0.37.9 → 0.37.11

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 (84) hide show
  1. package/README.md +309 -19
  2. package/bin/chainlesschain.js +4 -0
  3. package/package.json +1 -1
  4. package/src/commands/a2a.js +374 -0
  5. package/src/commands/audit.js +286 -0
  6. package/src/commands/auth.js +387 -0
  7. package/src/commands/bi.js +240 -0
  8. package/src/commands/browse.js +184 -0
  9. package/src/commands/cowork.js +317 -0
  10. package/src/commands/did.js +376 -0
  11. package/src/commands/economy.js +375 -0
  12. package/src/commands/encrypt.js +233 -0
  13. package/src/commands/evolution.js +398 -0
  14. package/src/commands/export.js +125 -0
  15. package/src/commands/git.js +215 -0
  16. package/src/commands/hmemory.js +273 -0
  17. package/src/commands/hook.js +260 -0
  18. package/src/commands/import.js +259 -0
  19. package/src/commands/init.js +184 -0
  20. package/src/commands/instinct.js +202 -0
  21. package/src/commands/llm.js +155 -4
  22. package/src/commands/lowcode.js +320 -0
  23. package/src/commands/mcp.js +302 -0
  24. package/src/commands/memory.js +282 -0
  25. package/src/commands/note.js +187 -0
  26. package/src/commands/org.js +505 -0
  27. package/src/commands/p2p.js +274 -0
  28. package/src/commands/plugin.js +451 -0
  29. package/src/commands/sandbox.js +366 -0
  30. package/src/commands/search.js +237 -0
  31. package/src/commands/session.js +238 -0
  32. package/src/commands/skill.js +254 -201
  33. package/src/commands/sync.js +249 -0
  34. package/src/commands/tokens.js +214 -0
  35. package/src/commands/wallet.js +416 -0
  36. package/src/commands/workflow.js +359 -0
  37. package/src/commands/zkp.js +277 -0
  38. package/src/index.js +93 -1
  39. package/src/lib/a2a-protocol.js +371 -0
  40. package/src/lib/agent-coordinator.js +273 -0
  41. package/src/lib/agent-economy.js +369 -0
  42. package/src/lib/app-builder.js +377 -0
  43. package/src/lib/audit-logger.js +364 -0
  44. package/src/lib/bi-engine.js +299 -0
  45. package/src/lib/bm25-search.js +322 -0
  46. package/src/lib/browser-automation.js +216 -0
  47. package/src/lib/cowork/ab-comparator-cli.js +180 -0
  48. package/src/lib/cowork/code-knowledge-graph-cli.js +232 -0
  49. package/src/lib/cowork/debate-review-cli.js +144 -0
  50. package/src/lib/cowork/decision-kb-cli.js +153 -0
  51. package/src/lib/cowork/project-style-analyzer-cli.js +168 -0
  52. package/src/lib/cowork-adapter.js +106 -0
  53. package/src/lib/crypto-manager.js +246 -0
  54. package/src/lib/did-manager.js +270 -0
  55. package/src/lib/ensure-utf8.js +59 -0
  56. package/src/lib/evolution-system.js +508 -0
  57. package/src/lib/git-integration.js +220 -0
  58. package/src/lib/hierarchical-memory.js +471 -0
  59. package/src/lib/hook-manager.js +387 -0
  60. package/src/lib/instinct-manager.js +190 -0
  61. package/src/lib/knowledge-exporter.js +302 -0
  62. package/src/lib/knowledge-importer.js +293 -0
  63. package/src/lib/llm-providers.js +325 -0
  64. package/src/lib/mcp-client.js +413 -0
  65. package/src/lib/memory-manager.js +211 -0
  66. package/src/lib/note-versioning.js +244 -0
  67. package/src/lib/org-manager.js +424 -0
  68. package/src/lib/p2p-manager.js +317 -0
  69. package/src/lib/pdf-parser.js +96 -0
  70. package/src/lib/permission-engine.js +374 -0
  71. package/src/lib/plan-mode.js +333 -0
  72. package/src/lib/plugin-manager.js +430 -0
  73. package/src/lib/project-detector.js +53 -0
  74. package/src/lib/response-cache.js +156 -0
  75. package/src/lib/sandbox-v2.js +503 -0
  76. package/src/lib/service-container.js +183 -0
  77. package/src/lib/session-manager.js +189 -0
  78. package/src/lib/skill-loader.js +274 -0
  79. package/src/lib/sync-manager.js +347 -0
  80. package/src/lib/token-tracker.js +200 -0
  81. package/src/lib/wallet-manager.js +348 -0
  82. package/src/lib/workflow-engine.js +503 -0
  83. package/src/lib/zkp-engine.js +241 -0
  84. package/src/repl/agent-repl.js +259 -124
@@ -0,0 +1,325 @@
1
+ /**
2
+ * LLM Provider registry — supports multiple AI providers with a unified interface.
3
+ */
4
+
5
+ /**
6
+ * Built-in provider definitions.
7
+ */
8
+ export const BUILT_IN_PROVIDERS = {
9
+ ollama: {
10
+ name: "ollama",
11
+ displayName: "Ollama (Local)",
12
+ baseUrl: "http://localhost:11434",
13
+ apiKeyEnv: null,
14
+ models: ["qwen2:7b", "llama3:8b", "mistral:7b", "codellama:7b"],
15
+ free: true,
16
+ },
17
+ openai: {
18
+ name: "openai",
19
+ displayName: "OpenAI",
20
+ baseUrl: "https://api.openai.com/v1",
21
+ apiKeyEnv: "OPENAI_API_KEY",
22
+ models: ["gpt-4o", "gpt-4o-mini", "gpt-4-turbo", "gpt-3.5-turbo", "o1"],
23
+ free: false,
24
+ },
25
+ anthropic: {
26
+ name: "anthropic",
27
+ displayName: "Anthropic",
28
+ baseUrl: "https://api.anthropic.com/v1",
29
+ apiKeyEnv: "ANTHROPIC_API_KEY",
30
+ models: [
31
+ "claude-opus-4-6",
32
+ "claude-sonnet-4-6",
33
+ "claude-haiku-4-5-20251001",
34
+ ],
35
+ free: false,
36
+ },
37
+ deepseek: {
38
+ name: "deepseek",
39
+ displayName: "DeepSeek",
40
+ baseUrl: "https://api.deepseek.com/v1",
41
+ apiKeyEnv: "DEEPSEEK_API_KEY",
42
+ models: ["deepseek-chat", "deepseek-coder", "deepseek-reasoner"],
43
+ free: false,
44
+ },
45
+ dashscope: {
46
+ name: "dashscope",
47
+ displayName: "DashScope (Alibaba)",
48
+ baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1",
49
+ apiKeyEnv: "DASHSCOPE_API_KEY",
50
+ models: ["qwen-turbo", "qwen-plus", "qwen-max"],
51
+ free: false,
52
+ },
53
+ gemini: {
54
+ name: "gemini",
55
+ displayName: "Google Gemini",
56
+ baseUrl: "https://generativelanguage.googleapis.com/v1beta",
57
+ apiKeyEnv: "GEMINI_API_KEY",
58
+ models: ["gemini-2.0-flash", "gemini-2.0-pro", "gemini-1.5-flash"],
59
+ free: false,
60
+ },
61
+ mistral: {
62
+ name: "mistral",
63
+ displayName: "Mistral AI",
64
+ baseUrl: "https://api.mistral.ai/v1",
65
+ apiKeyEnv: "MISTRAL_API_KEY",
66
+ models: [
67
+ "mistral-large-latest",
68
+ "mistral-medium-latest",
69
+ "mistral-small-latest",
70
+ ],
71
+ free: false,
72
+ },
73
+ };
74
+
75
+ /**
76
+ * Provider registry — manages available providers and active selection.
77
+ */
78
+ export class LLMProviderRegistry {
79
+ constructor(db) {
80
+ this.db = db;
81
+ this.providers = new Map();
82
+ this._ensureTable();
83
+ this._loadBuiltins();
84
+ this._loadCustom();
85
+ }
86
+
87
+ _ensureTable() {
88
+ this.db.exec(`
89
+ CREATE TABLE IF NOT EXISTS llm_providers (
90
+ name TEXT PRIMARY KEY,
91
+ display_name TEXT NOT NULL,
92
+ base_url TEXT NOT NULL,
93
+ api_key_env TEXT,
94
+ models TEXT DEFAULT '[]',
95
+ is_active INTEGER DEFAULT 0,
96
+ custom INTEGER DEFAULT 0,
97
+ created_at TEXT DEFAULT (datetime('now'))
98
+ )
99
+ `);
100
+ }
101
+
102
+ _loadBuiltins() {
103
+ for (const [name, def] of Object.entries(BUILT_IN_PROVIDERS)) {
104
+ this.providers.set(name, { ...def, custom: false });
105
+ }
106
+ }
107
+
108
+ _loadCustom() {
109
+ const rows = this.db
110
+ .prepare("SELECT * FROM llm_providers WHERE custom = 1")
111
+ .all();
112
+ for (const row of rows) {
113
+ this.providers.set(row.name, {
114
+ name: row.name,
115
+ displayName: row.display_name,
116
+ baseUrl: row.base_url,
117
+ apiKeyEnv: row.api_key_env,
118
+ models: JSON.parse(row.models || "[]"),
119
+ custom: true,
120
+ free: false,
121
+ });
122
+ }
123
+ }
124
+
125
+ /**
126
+ * List all providers.
127
+ */
128
+ list() {
129
+ const result = [];
130
+ for (const [name, provider] of this.providers) {
131
+ const hasKey = provider.apiKeyEnv
132
+ ? !!process.env[provider.apiKeyEnv]
133
+ : true;
134
+ result.push({
135
+ name,
136
+ displayName: provider.displayName,
137
+ baseUrl: provider.baseUrl,
138
+ models: provider.models,
139
+ hasApiKey: hasKey,
140
+ custom: provider.custom || false,
141
+ free: provider.free || false,
142
+ });
143
+ }
144
+ return result;
145
+ }
146
+
147
+ /**
148
+ * Get a specific provider.
149
+ */
150
+ get(name) {
151
+ return this.providers.get(name) || null;
152
+ }
153
+
154
+ /**
155
+ * Add a custom provider.
156
+ */
157
+ addProvider(name, config) {
158
+ const provider = {
159
+ name,
160
+ displayName: config.displayName || name,
161
+ baseUrl: config.baseUrl,
162
+ apiKeyEnv: config.apiKeyEnv || null,
163
+ models: config.models || [],
164
+ custom: true,
165
+ free: config.free || false,
166
+ };
167
+
168
+ this.db
169
+ .prepare(
170
+ "INSERT OR REPLACE INTO llm_providers (name, display_name, base_url, api_key_env, models, custom) VALUES (?, ?, ?, ?, ?, 1)",
171
+ )
172
+ .run(
173
+ name,
174
+ provider.displayName,
175
+ provider.baseUrl,
176
+ provider.apiKeyEnv,
177
+ JSON.stringify(provider.models),
178
+ );
179
+
180
+ this.providers.set(name, provider);
181
+ return provider;
182
+ }
183
+
184
+ /**
185
+ * Remove a custom provider.
186
+ */
187
+ removeProvider(name) {
188
+ const provider = this.providers.get(name);
189
+ if (!provider) return false;
190
+ if (!provider.custom)
191
+ throw new Error(`Cannot remove built-in provider "${name}"`);
192
+
193
+ this.db
194
+ .prepare("DELETE FROM llm_providers WHERE name = ? AND custom = 1")
195
+ .run(name);
196
+ this.providers.delete(name);
197
+ return true;
198
+ }
199
+
200
+ /**
201
+ * Get/set the active provider.
202
+ */
203
+ getActive() {
204
+ const row = this.db
205
+ .prepare("SELECT name FROM llm_providers WHERE is_active = 1")
206
+ .get();
207
+ return row ? row.name : "ollama";
208
+ }
209
+
210
+ setActive(name) {
211
+ if (!this.providers.has(name)) {
212
+ throw new Error(`Provider "${name}" not found`);
213
+ }
214
+ // Reset all
215
+ this.db.prepare("UPDATE llm_providers SET is_active = 0 WHERE 1=1").run();
216
+ // Set active
217
+ this.db
218
+ .prepare(
219
+ "INSERT OR REPLACE INTO llm_providers (name, display_name, base_url, api_key_env, models, is_active) VALUES (?, ?, ?, ?, ?, 1)",
220
+ )
221
+ .run(
222
+ name,
223
+ this.providers.get(name).displayName,
224
+ this.providers.get(name).baseUrl,
225
+ this.providers.get(name).apiKeyEnv,
226
+ JSON.stringify(this.providers.get(name).models),
227
+ );
228
+ return this.providers.get(name);
229
+ }
230
+
231
+ /**
232
+ * Get API key for a provider (from env or config).
233
+ */
234
+ getApiKey(name) {
235
+ const provider = this.providers.get(name);
236
+ if (!provider) return null;
237
+ if (!provider.apiKeyEnv) return null;
238
+ return process.env[provider.apiKeyEnv] || null;
239
+ }
240
+
241
+ /**
242
+ * Test provider connectivity.
243
+ */
244
+ async testProvider(name, model) {
245
+ const provider = this.providers.get(name);
246
+ if (!provider) throw new Error(`Provider "${name}" not found`);
247
+
248
+ const start = Date.now();
249
+ const testModel = model || provider.models[0];
250
+
251
+ if (name === "ollama") {
252
+ const res = await fetch(`${provider.baseUrl}/api/generate`, {
253
+ method: "POST",
254
+ headers: { "Content-Type": "application/json" },
255
+ body: JSON.stringify({ model: testModel, prompt: "Hi", stream: false }),
256
+ });
257
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
258
+ const data = await res.json();
259
+ return {
260
+ ok: true,
261
+ elapsed: Date.now() - start,
262
+ response: data.response?.trim(),
263
+ };
264
+ }
265
+
266
+ if (name === "gemini") {
267
+ const key = this.getApiKey(name);
268
+ if (!key) throw new Error("GEMINI_API_KEY not set");
269
+ const res = await fetch(
270
+ `${provider.baseUrl}/models/${testModel}:generateContent?key=${key}`,
271
+ {
272
+ method: "POST",
273
+ headers: { "Content-Type": "application/json" },
274
+ body: JSON.stringify({ contents: [{ parts: [{ text: "Hi" }] }] }),
275
+ },
276
+ );
277
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
278
+ const data = await res.json();
279
+ const text = data.candidates?.[0]?.content?.parts?.[0]?.text || "";
280
+ return { ok: true, elapsed: Date.now() - start, response: text.trim() };
281
+ }
282
+
283
+ if (name === "anthropic") {
284
+ const key = this.getApiKey(name);
285
+ if (!key) throw new Error("ANTHROPIC_API_KEY not set");
286
+ const res = await fetch(`${provider.baseUrl}/messages`, {
287
+ method: "POST",
288
+ headers: {
289
+ "Content-Type": "application/json",
290
+ "x-api-key": key,
291
+ "anthropic-version": "2023-06-01",
292
+ },
293
+ body: JSON.stringify({
294
+ model: testModel,
295
+ max_tokens: 10,
296
+ messages: [{ role: "user", content: "Hi" }],
297
+ }),
298
+ });
299
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
300
+ const data = await res.json();
301
+ const text = data.content?.[0]?.text || "";
302
+ return { ok: true, elapsed: Date.now() - start, response: text.trim() };
303
+ }
304
+
305
+ // OpenAI-compatible (openai, deepseek, dashscope, mistral)
306
+ const key = this.getApiKey(name);
307
+ if (!key) throw new Error(`${provider.apiKeyEnv} not set`);
308
+ const res = await fetch(`${provider.baseUrl}/chat/completions`, {
309
+ method: "POST",
310
+ headers: {
311
+ "Content-Type": "application/json",
312
+ Authorization: `Bearer ${key}`,
313
+ },
314
+ body: JSON.stringify({
315
+ model: testModel,
316
+ messages: [{ role: "user", content: "Hi" }],
317
+ max_tokens: 10,
318
+ }),
319
+ });
320
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
321
+ const data = await res.json();
322
+ const text = data.choices?.[0]?.message?.content || "";
323
+ return { ok: true, elapsed: Date.now() - start, response: text.trim() };
324
+ }
325
+ }