chainlesschain 0.37.10 → 0.37.12

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 (39) hide show
  1. package/README.md +166 -10
  2. package/package.json +1 -1
  3. package/src/commands/a2a.js +374 -0
  4. package/src/commands/bi.js +240 -0
  5. package/src/commands/cowork.js +317 -0
  6. package/src/commands/economy.js +375 -0
  7. package/src/commands/evolution.js +398 -0
  8. package/src/commands/hmemory.js +273 -0
  9. package/src/commands/hook.js +260 -0
  10. package/src/commands/init.js +184 -0
  11. package/src/commands/lowcode.js +320 -0
  12. package/src/commands/plugin.js +55 -2
  13. package/src/commands/sandbox.js +366 -0
  14. package/src/commands/skill.js +254 -201
  15. package/src/commands/workflow.js +359 -0
  16. package/src/commands/zkp.js +277 -0
  17. package/src/index.js +44 -0
  18. package/src/lib/a2a-protocol.js +371 -0
  19. package/src/lib/agent-coordinator.js +273 -0
  20. package/src/lib/agent-economy.js +369 -0
  21. package/src/lib/app-builder.js +377 -0
  22. package/src/lib/bi-engine.js +299 -0
  23. package/src/lib/cowork/ab-comparator-cli.js +180 -0
  24. package/src/lib/cowork/code-knowledge-graph-cli.js +232 -0
  25. package/src/lib/cowork/debate-review-cli.js +144 -0
  26. package/src/lib/cowork/decision-kb-cli.js +153 -0
  27. package/src/lib/cowork/project-style-analyzer-cli.js +168 -0
  28. package/src/lib/cowork-adapter.js +106 -0
  29. package/src/lib/evolution-system.js +508 -0
  30. package/src/lib/hierarchical-memory.js +471 -0
  31. package/src/lib/hook-manager.js +387 -0
  32. package/src/lib/plugin-manager.js +118 -0
  33. package/src/lib/project-detector.js +53 -0
  34. package/src/lib/sandbox-v2.js +503 -0
  35. package/src/lib/service-container.js +183 -0
  36. package/src/lib/skill-loader.js +274 -0
  37. package/src/lib/workflow-engine.js +503 -0
  38. package/src/lib/zkp-engine.js +241 -0
  39. package/src/repl/agent-repl.js +117 -112
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Project Style Analyzer for CLI
3
+ *
4
+ * Analyzes coding style, conventions, and patterns in a codebase using LLM.
5
+ */
6
+
7
+ import fs from "fs";
8
+ import path from "path";
9
+ import { createChatFn } from "../cowork-adapter.js";
10
+
11
+ const CODE_EXTENSIONS = new Set([
12
+ ".js",
13
+ ".ts",
14
+ ".jsx",
15
+ ".tsx",
16
+ ".vue",
17
+ ".py",
18
+ ".java",
19
+ ".go",
20
+ ".rs",
21
+ ".kt",
22
+ ]);
23
+
24
+ /**
25
+ * Analyze project coding style and conventions
26
+ *
27
+ * @param {object} params
28
+ * @param {string} params.targetPath - File or directory to analyze
29
+ * @param {object} [params.llmOptions] - LLM provider options
30
+ * @returns {Promise<object>} Style analysis result
31
+ */
32
+ export async function analyzeProjectStyle({ targetPath, llmOptions = {} }) {
33
+ const chat = createChatFn(llmOptions);
34
+ const stat = fs.statSync(targetPath);
35
+
36
+ // Collect sample files
37
+ const samples = [];
38
+ if (stat.isDirectory()) {
39
+ const files = collectSampleFiles(targetPath, 8);
40
+ for (const file of files) {
41
+ try {
42
+ const content = fs.readFileSync(file, "utf-8");
43
+ const relative = path.relative(process.cwd(), file);
44
+ samples.push({
45
+ path: relative,
46
+ content: content.substring(0, 3000),
47
+ ext: path.extname(file),
48
+ });
49
+ } catch {
50
+ // Skip
51
+ }
52
+ }
53
+ } else {
54
+ const content = fs.readFileSync(targetPath, "utf-8");
55
+ samples.push({
56
+ path: path.relative(process.cwd(), targetPath),
57
+ content: content.substring(0, 5000),
58
+ ext: path.extname(targetPath),
59
+ });
60
+ }
61
+
62
+ if (samples.length === 0) {
63
+ return { patterns: [], summary: "No code files found to analyze." };
64
+ }
65
+
66
+ // Check for config files
67
+ const configFiles = [];
68
+ const configCandidates = [
69
+ ".eslintrc.js",
70
+ ".eslintrc.json",
71
+ ".prettierrc",
72
+ "tsconfig.json",
73
+ "pyproject.toml",
74
+ ".editorconfig",
75
+ "biome.json",
76
+ ];
77
+ const baseDir = stat.isDirectory() ? targetPath : path.dirname(targetPath);
78
+ for (const cf of configCandidates) {
79
+ const cfPath = path.join(baseDir, cf);
80
+ if (fs.existsSync(cfPath)) {
81
+ try {
82
+ configFiles.push({
83
+ name: cf,
84
+ content: fs.readFileSync(cfPath, "utf-8").substring(0, 2000),
85
+ });
86
+ } catch {
87
+ // Skip
88
+ }
89
+ }
90
+ }
91
+
92
+ const codeContext = samples
93
+ .map((s) => `--- ${s.path} ---\n${s.content}`)
94
+ .join("\n\n");
95
+
96
+ const configContext =
97
+ configFiles.length > 0
98
+ ? `\n\nConfiguration files:\n${configFiles.map((c) => `--- ${c.name} ---\n${c.content}`).join("\n\n")}`
99
+ : "";
100
+
101
+ const messages = [
102
+ {
103
+ role: "system",
104
+ content: `You are a senior code reviewer analyzing project conventions. Identify:
105
+ 1. Naming conventions (variables, functions, files)
106
+ 2. Code organization patterns
107
+ 3. Import/export style
108
+ 4. Error handling patterns
109
+ 5. Comment/documentation style
110
+ 6. Testing patterns (if visible)
111
+ 7. Formatting preferences (indentation, quotes, semicolons)
112
+
113
+ Be specific with examples from the code samples provided.`,
114
+ },
115
+ {
116
+ role: "user",
117
+ content: `Analyze the coding style and conventions in these ${samples.length} code samples:\n\n${codeContext}${configContext}\n\nProvide a structured analysis of the project's coding conventions and patterns.`,
118
+ },
119
+ ];
120
+
121
+ try {
122
+ const response = await chat(messages, { maxTokens: 2000 });
123
+
124
+ return {
125
+ samplesAnalyzed: samples.length,
126
+ configFilesFound: configFiles.map((c) => c.name),
127
+ analysis: response,
128
+ summary: `Style Analysis for: ${targetPath}\n Samples: ${samples.length} files\n Config: ${configFiles.map((c) => c.name).join(", ") || "none found"}\n\n${response}`,
129
+ };
130
+ } catch (err) {
131
+ return {
132
+ samplesAnalyzed: samples.length,
133
+ summary: `Style analysis failed: ${err.message}`,
134
+ };
135
+ }
136
+ }
137
+
138
+ function collectSampleFiles(dir, maxFiles) {
139
+ const files = [];
140
+ const queue = [dir];
141
+
142
+ while (queue.length > 0 && files.length < maxFiles) {
143
+ const current = queue.shift();
144
+ try {
145
+ const entries = fs.readdirSync(current, { withFileTypes: true });
146
+ for (const entry of entries) {
147
+ if (
148
+ entry.name.startsWith(".") ||
149
+ entry.name === "node_modules" ||
150
+ entry.name === "dist"
151
+ ) {
152
+ continue;
153
+ }
154
+ const fullPath = path.join(current, entry.name);
155
+ if (entry.isDirectory()) {
156
+ queue.push(fullPath);
157
+ } else if (CODE_EXTENSIONS.has(path.extname(entry.name))) {
158
+ files.push(fullPath);
159
+ if (files.length >= maxFiles) break;
160
+ }
161
+ }
162
+ } catch {
163
+ // Skip
164
+ }
165
+ }
166
+
167
+ return files;
168
+ }
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Cowork Adapter — bridges CLI's LLM infrastructure to cowork modules.
3
+ *
4
+ * Provides:
5
+ * - Unified LLM chat function (works with any configured provider)
6
+ * - Logger shim compatible with desktop modules
7
+ * - Module initialization helper
8
+ */
9
+
10
+ import { LLMProviderRegistry, BUILT_IN_PROVIDERS } from "./llm-providers.js";
11
+
12
+ /**
13
+ * Create a chat completion function that routes through the active LLM provider.
14
+ *
15
+ * @param {object} [options]
16
+ * @param {string} [options.provider] - Provider name override
17
+ * @param {string} [options.model] - Model name override
18
+ * @param {string} [options.baseUrl] - Base URL override
19
+ * @param {string} [options.apiKey] - API key override
20
+ * @returns {(messages: object[], opts?: object) => Promise<string>}
21
+ */
22
+ export function createChatFn(options = {}) {
23
+ const provider = options.provider || process.env.LLM_PROVIDER || "ollama";
24
+ const providerDef = BUILT_IN_PROVIDERS[provider] || BUILT_IN_PROVIDERS.ollama;
25
+ const model = options.model || process.env.LLM_MODEL || providerDef.models[0];
26
+ const baseUrl = options.baseUrl || providerDef.baseUrl;
27
+
28
+ return async function chat(messages, opts = {}) {
29
+ const currentModel = opts.model || model;
30
+ const maxTokens = opts.maxTokens || 2048;
31
+
32
+ if (provider === "ollama") {
33
+ const res = await fetch(`${baseUrl}/api/chat`, {
34
+ method: "POST",
35
+ headers: { "Content-Type": "application/json" },
36
+ body: JSON.stringify({
37
+ model: currentModel,
38
+ messages,
39
+ stream: false,
40
+ options: { num_predict: maxTokens },
41
+ }),
42
+ });
43
+ if (!res.ok) throw new Error(`Ollama error: ${res.status}`);
44
+ const data = await res.json();
45
+ return data.message?.content || "";
46
+ }
47
+
48
+ if (provider === "anthropic") {
49
+ const key = options.apiKey || process.env[providerDef.apiKeyEnv];
50
+ if (!key) throw new Error("ANTHROPIC_API_KEY not set");
51
+ // Extract system message if present
52
+ const systemMsgs = messages.filter((m) => m.role === "system");
53
+ const otherMsgs = messages.filter((m) => m.role !== "system");
54
+ const body = {
55
+ model: currentModel,
56
+ max_tokens: maxTokens,
57
+ messages: otherMsgs,
58
+ };
59
+ if (systemMsgs.length > 0) {
60
+ body.system = systemMsgs.map((m) => m.content).join("\n");
61
+ }
62
+ const res = await fetch(`${baseUrl}/messages`, {
63
+ method: "POST",
64
+ headers: {
65
+ "Content-Type": "application/json",
66
+ "x-api-key": key,
67
+ "anthropic-version": "2023-06-01",
68
+ },
69
+ body: JSON.stringify(body),
70
+ });
71
+ if (!res.ok) throw new Error(`Anthropic error: ${res.status}`);
72
+ const data = await res.json();
73
+ return data.content?.[0]?.text || "";
74
+ }
75
+
76
+ // OpenAI-compatible (openai, deepseek, dashscope, mistral, gemini)
77
+ const key = options.apiKey || process.env[providerDef.apiKeyEnv];
78
+ if (!key) throw new Error(`${providerDef.apiKeyEnv} not set`);
79
+
80
+ const res = await fetch(`${baseUrl}/chat/completions`, {
81
+ method: "POST",
82
+ headers: {
83
+ "Content-Type": "application/json",
84
+ Authorization: `Bearer ${key}`,
85
+ },
86
+ body: JSON.stringify({
87
+ model: currentModel,
88
+ messages,
89
+ max_tokens: maxTokens,
90
+ }),
91
+ });
92
+ if (!res.ok) throw new Error(`API error: ${res.status}`);
93
+ const data = await res.json();
94
+ return data.choices?.[0]?.message?.content || "";
95
+ };
96
+ }
97
+
98
+ /**
99
+ * Logger shim — compatible with desktop module expectations
100
+ */
101
+ export const coworkLogger = {
102
+ info: (...args) => console.log("[cowork]", ...args),
103
+ warn: (...args) => console.warn("[cowork]", ...args),
104
+ error: (...args) => console.error("[cowork]", ...args),
105
+ debug: () => {},
106
+ };