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.
- package/README.md +166 -10
- package/package.json +1 -1
- package/src/commands/a2a.js +374 -0
- package/src/commands/bi.js +240 -0
- package/src/commands/cowork.js +317 -0
- package/src/commands/economy.js +375 -0
- package/src/commands/evolution.js +398 -0
- package/src/commands/hmemory.js +273 -0
- package/src/commands/hook.js +260 -0
- package/src/commands/init.js +184 -0
- package/src/commands/lowcode.js +320 -0
- package/src/commands/plugin.js +55 -2
- package/src/commands/sandbox.js +366 -0
- package/src/commands/skill.js +254 -201
- package/src/commands/workflow.js +359 -0
- package/src/commands/zkp.js +277 -0
- package/src/index.js +44 -0
- package/src/lib/a2a-protocol.js +371 -0
- package/src/lib/agent-coordinator.js +273 -0
- package/src/lib/agent-economy.js +369 -0
- package/src/lib/app-builder.js +377 -0
- package/src/lib/bi-engine.js +299 -0
- package/src/lib/cowork/ab-comparator-cli.js +180 -0
- package/src/lib/cowork/code-knowledge-graph-cli.js +232 -0
- package/src/lib/cowork/debate-review-cli.js +144 -0
- package/src/lib/cowork/decision-kb-cli.js +153 -0
- package/src/lib/cowork/project-style-analyzer-cli.js +168 -0
- package/src/lib/cowork-adapter.js +106 -0
- package/src/lib/evolution-system.js +508 -0
- package/src/lib/hierarchical-memory.js +471 -0
- package/src/lib/hook-manager.js +387 -0
- package/src/lib/plugin-manager.js +118 -0
- package/src/lib/project-detector.js +53 -0
- package/src/lib/sandbox-v2.js +503 -0
- package/src/lib/service-container.js +183 -0
- package/src/lib/skill-loader.js +274 -0
- package/src/lib/workflow-engine.js +503 -0
- package/src/lib/zkp-engine.js +241 -0
- 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
|
+
};
|