hypercore-cli 1.1.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.
- package/LICENSE +21 -0
- package/README.md +110 -0
- package/dist/api-XGC7D5AW.js +162 -0
- package/dist/auth-DNQWYQKT.js +21 -0
- package/dist/background-2EGCAAQH.js +14 -0
- package/dist/backlog-Q2NZCLNY.js +24 -0
- package/dist/chunk-2CMSCWQW.js +162 -0
- package/dist/chunk-2LJ2DVEB.js +167 -0
- package/dist/chunk-3RPFCQKJ.js +288 -0
- package/dist/chunk-43OLRXM5.js +263 -0
- package/dist/chunk-4DVYJAJL.js +57 -0
- package/dist/chunk-6OL3GA3P.js +173 -0
- package/dist/chunk-AUHU7ALH.js +2023 -0
- package/dist/chunk-B6A2AKLN.js +139 -0
- package/dist/chunk-BE46C7JW.js +46 -0
- package/dist/chunk-CUVAUOXL.js +58 -0
- package/dist/chunk-GH7E2OJE.js +223 -0
- package/dist/chunk-GOOTEPBK.js +271 -0
- package/dist/chunk-GPPMJYSM.js +133 -0
- package/dist/chunk-GU2FZQ6A.js +69 -0
- package/dist/chunk-IOPKN5GD.js +190 -0
- package/dist/chunk-IXOIOGR5.js +1505 -0
- package/dist/chunk-KRPOPWGA.js +251 -0
- package/dist/chunk-MGLJ53QN.js +219 -0
- package/dist/chunk-MV4TTRYX.js +533 -0
- package/dist/chunk-OPZYEVYR.js +150 -0
- package/dist/chunk-QTSLP47C.js +166 -0
- package/dist/chunk-R3GPQC7I.js +393 -0
- package/dist/chunk-RKB2JOV2.js +43 -0
- package/dist/chunk-RNG3K465.js +80 -0
- package/dist/chunk-TGTYKBGC.js +86 -0
- package/dist/chunk-U5SGAIMM.js +681 -0
- package/dist/chunk-V5UHPPSY.js +140 -0
- package/dist/chunk-WHLVZCQY.js +245 -0
- package/dist/chunk-XDRCBMZZ.js +66 -0
- package/dist/chunk-XOS6HPEF.js +134 -0
- package/dist/chunk-ZSBHUGWR.js +262 -0
- package/dist/claude-NSQ442XD.js +12 -0
- package/dist/commands-CK3WFAGI.js +128 -0
- package/dist/commands-U63OEO5J.js +1044 -0
- package/dist/commands-ZE6GD3WC.js +232 -0
- package/dist/config-4EW42BSF.js +8 -0
- package/dist/config-loader-SXO674TF.js +24 -0
- package/dist/diagnose-AFW3ZTZ4.js +12 -0
- package/dist/display-IIUBEYWN.js +58 -0
- package/dist/extractor-QV53W2YJ.js +129 -0
- package/dist/history-WMSCHERZ.js +180 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +406 -0
- package/dist/instance-registry-YSIJXSO7.js +15 -0
- package/dist/keybindings-JAAMLH3G.js +15 -0
- package/dist/loader-WHNTZTLP.js +58 -0
- package/dist/network-MM6YWPGO.js +279 -0
- package/dist/notify-HPTALZDC.js +14 -0
- package/dist/openai-compat-UQWJXBEK.js +12 -0
- package/dist/permissions-JUKXMNDH.js +10 -0
- package/dist/prompt-QV45TXRL.js +166 -0
- package/dist/quality-ST7PPNFR.js +16 -0
- package/dist/repl-RT3AHL7M.js +3375 -0
- package/dist/roadmap-5OBEKROY.js +17 -0
- package/dist/server-PORT7OEG.js +57 -0
- package/dist/session-4VUNDWLH.js +21 -0
- package/dist/skills-V4A35XKG.js +175 -0
- package/dist/store-Y4LU5QTO.js +25 -0
- package/dist/team-HO7Z4SIM.js +385 -0
- package/dist/telemetry-6R4EIE6O.js +30 -0
- package/dist/test-runner-ZQH5Y6OJ.js +619 -0
- package/dist/theme-3SYJ3UQA.js +14 -0
- package/dist/upgrade-7TGI3SXO.js +83 -0
- package/dist/verify-JUDKTPKZ.js +14 -0
- package/dist/web/static/app.js +562 -0
- package/dist/web/static/index.html +132 -0
- package/dist/web/static/mirror.css +1001 -0
- package/dist/web/static/mirror.html +184 -0
- package/dist/web/static/mirror.js +1125 -0
- package/dist/web/static/onboard.css +302 -0
- package/dist/web/static/onboard.html +140 -0
- package/dist/web/static/onboard.js +260 -0
- package/dist/web/static/style.css +602 -0
- package/dist/web/static/workspace.css +1568 -0
- package/dist/web/static/workspace.html +408 -0
- package/dist/web/static/workspace.js +1683 -0
- package/dist/web-Z5HSCQHW.js +39 -0
- package/package.json +67 -0
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createToolRegistry
|
|
3
|
+
} from "./chunk-IXOIOGR5.js";
|
|
4
|
+
import {
|
|
5
|
+
callLLM
|
|
6
|
+
} from "./chunk-43OLRXM5.js";
|
|
7
|
+
import {
|
|
8
|
+
callOpenAILLM
|
|
9
|
+
} from "./chunk-GOOTEPBK.js";
|
|
10
|
+
import {
|
|
11
|
+
MODEL_ALIASES,
|
|
12
|
+
MODEL_PROVIDERS
|
|
13
|
+
} from "./chunk-V5UHPPSY.js";
|
|
14
|
+
import {
|
|
15
|
+
loadAgent,
|
|
16
|
+
loadLine,
|
|
17
|
+
loadPWP,
|
|
18
|
+
loadSkill
|
|
19
|
+
} from "./chunk-WHLVZCQY.js";
|
|
20
|
+
|
|
21
|
+
// src/core/workspace-init.ts
|
|
22
|
+
import { mkdir, copyFile, writeFile, readdir } from "fs/promises";
|
|
23
|
+
import { join, dirname } from "path";
|
|
24
|
+
import { fileURLToPath } from "url";
|
|
25
|
+
import { existsSync } from "fs";
|
|
26
|
+
var HYPERCORE_DIR = join(process.env.HOME || "~", ".hypercore");
|
|
27
|
+
function getTemplatesDir() {
|
|
28
|
+
const thisFile = fileURLToPath(import.meta.url);
|
|
29
|
+
const projectRoot = join(dirname(thisFile), "..", "..");
|
|
30
|
+
return join(projectRoot, "templates");
|
|
31
|
+
}
|
|
32
|
+
async function copyTemplateDir(srcDir, destDir) {
|
|
33
|
+
await mkdir(destDir, { recursive: true });
|
|
34
|
+
try {
|
|
35
|
+
const entries = await readdir(srcDir, { withFileTypes: true });
|
|
36
|
+
for (const entry of entries) {
|
|
37
|
+
const srcPath = join(srcDir, entry.name);
|
|
38
|
+
const destPath = join(destDir, entry.name);
|
|
39
|
+
if (entry.isDirectory()) {
|
|
40
|
+
await copyTemplateDir(srcPath, destPath);
|
|
41
|
+
} else {
|
|
42
|
+
if (!existsSync(destPath)) {
|
|
43
|
+
await copyFile(srcPath, destPath);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
} catch {
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function escapeTomlValue(value) {
|
|
51
|
+
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r");
|
|
52
|
+
}
|
|
53
|
+
function generateConfigToml(provider, apiKey, tavilyKey) {
|
|
54
|
+
const modelConfigs = {
|
|
55
|
+
anthropic: { name: "claude-sonnet-4-20250514" },
|
|
56
|
+
minimax: { name: "MiniMax-M2.5", base_url: "https://api.minimax.io/anthropic" },
|
|
57
|
+
gemini: { name: "gemini-2.5-flash", base_url: "https://generativelanguage.googleapis.com/v1beta/openai" },
|
|
58
|
+
deepseek: { name: "deepseek-chat", base_url: "https://api.deepseek.com/v1" }
|
|
59
|
+
};
|
|
60
|
+
const modelConfig = modelConfigs[provider] || modelConfigs["gemini"];
|
|
61
|
+
let config = `# Hypercore \u914D\u7F6E\u6587\u4EF6
|
|
62
|
+
# \u81EA\u52A8\u751F\u6210\uFF0C\u53EF\u624B\u52A8\u4FEE\u6539
|
|
63
|
+
|
|
64
|
+
[model]
|
|
65
|
+
provider = "${provider}"
|
|
66
|
+
name = "${modelConfig.name}"
|
|
67
|
+
api_key = "${escapeTomlValue(apiKey)}"
|
|
68
|
+
`;
|
|
69
|
+
if (modelConfig.base_url) {
|
|
70
|
+
config += `base_url = "${modelConfig.base_url}"
|
|
71
|
+
`;
|
|
72
|
+
}
|
|
73
|
+
config += `
|
|
74
|
+
[output]
|
|
75
|
+
dir = "${join(HYPERCORE_DIR, "outputs")}"
|
|
76
|
+
`;
|
|
77
|
+
if (tavilyKey) {
|
|
78
|
+
config += `
|
|
79
|
+
[search]
|
|
80
|
+
provider = "tavily"
|
|
81
|
+
api_key = "${escapeTomlValue(tavilyKey)}"
|
|
82
|
+
`;
|
|
83
|
+
}
|
|
84
|
+
config += `
|
|
85
|
+
# [keys] \u2014 \u591A\u6A21\u578B\u63D0\u4F9B\u5546 API Key\uFF08\u5DE5\u4F4D\u7EA7\u6A21\u578B\u5207\u6362\u65F6\u4F7F\u7528\uFF09
|
|
86
|
+
# [keys]
|
|
87
|
+
# anthropic = "sk-ant-..."
|
|
88
|
+
# gemini = "AIza..."
|
|
89
|
+
# deepseek = "sk-..."
|
|
90
|
+
# minimax = "..."
|
|
91
|
+
`;
|
|
92
|
+
return config;
|
|
93
|
+
}
|
|
94
|
+
function generatePWP(role) {
|
|
95
|
+
return `# \u4E2A\u4EBA\u5DE5\u4F5C\u7A7A\u95F4\u534F\u8BAE\uFF08PWP\uFF09
|
|
96
|
+
|
|
97
|
+
## \u8EAB\u4EFD
|
|
98
|
+
\u4F60\u662F\u4E00\u4E2A AI \u534F\u4F5C\u7CFB\u7EDF\uFF0C\u4E3A\u4EE5\u4E0B\u7528\u6237\u670D\u52A1\uFF1A
|
|
99
|
+
${role}
|
|
100
|
+
|
|
101
|
+
\u4F60\u7684\u76EE\u6807\u662F\u5E2E\u52A9\u7528\u6237\u9AD8\u6548\u5B8C\u6210\u77E5\u8BC6\u5DE5\u4F5C\uFF0C\u4EA7\u51FA\u9AD8\u8D28\u91CF\u5185\u5BB9\u3002
|
|
102
|
+
|
|
103
|
+
## \u54C1\u8D28\u6807\u51C6
|
|
104
|
+
- \u6240\u6709\u8F93\u51FA\u5FC5\u987B\u6709\u5B9E\u8D28\u5185\u5BB9\u548C\u72EC\u5230\u6D1E\u5BDF\uFF0C\u4E0D\u8981\u7A7A\u6D1E\u7684\u5957\u8BDD
|
|
105
|
+
- \u5B81\u6DF1\u52FF\u6D45\uFF0C\u5B81\u7CBE\u52FF\u6CDB
|
|
106
|
+
- \u5FC5\u987B\u6709\u539F\u521B\u89C2\u70B9\u6216\u72EC\u7279\u89C6\u89D2
|
|
107
|
+
- \u6570\u636E\u548C\u6848\u4F8B\u5FC5\u987B\u6709\u6765\u6E90\u652F\u6491
|
|
108
|
+
- \u8BED\u8A00\u7B80\u6D01\u6709\u529B\uFF0C\u4E0D\u62D6\u6CE5\u5E26\u6C34
|
|
109
|
+
- \u5982\u679C\u4FE1\u606F\u4E0D\u8DB3\uFF0C\u660E\u786E\u6807\u6CE8\u800C\u975E\u7F16\u9020
|
|
110
|
+
`;
|
|
111
|
+
}
|
|
112
|
+
async function initializeWorkspace(options) {
|
|
113
|
+
const { provider, apiKey, tavilyKey, role } = options;
|
|
114
|
+
await mkdir(HYPERCORE_DIR, { recursive: true });
|
|
115
|
+
for (const sub of ["agents", "skills", "lines", "outputs", "memory"]) {
|
|
116
|
+
await mkdir(join(HYPERCORE_DIR, sub), { recursive: true });
|
|
117
|
+
}
|
|
118
|
+
const templatesDir = getTemplatesDir();
|
|
119
|
+
await copyTemplateDir(join(templatesDir, "agents"), join(HYPERCORE_DIR, "agents"));
|
|
120
|
+
await copyTemplateDir(join(templatesDir, "skills"), join(HYPERCORE_DIR, "skills"));
|
|
121
|
+
await copyTemplateDir(join(templatesDir, "lines"), join(HYPERCORE_DIR, "lines"));
|
|
122
|
+
if (role) {
|
|
123
|
+
const pwpPath = join(HYPERCORE_DIR, "PWP.md");
|
|
124
|
+
if (!existsSync(pwpPath)) {
|
|
125
|
+
await writeFile(pwpPath, generatePWP(role), "utf-8");
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const configPath = join(HYPERCORE_DIR, "config.toml");
|
|
129
|
+
if (existsSync(configPath)) {
|
|
130
|
+
const { copyFile: cpFile } = await import("fs/promises");
|
|
131
|
+
await cpFile(configPath, configPath + ".bak");
|
|
132
|
+
}
|
|
133
|
+
await writeFile(
|
|
134
|
+
configPath,
|
|
135
|
+
generateConfigToml(provider, apiKey, tavilyKey),
|
|
136
|
+
"utf-8"
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// src/core/engine.ts
|
|
141
|
+
import { writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
142
|
+
import { join as join2 } from "path";
|
|
143
|
+
|
|
144
|
+
// src/core/prompt-assembler.ts
|
|
145
|
+
function assembleSystemPrompt(pwp, agent, skill) {
|
|
146
|
+
const parts = [];
|
|
147
|
+
parts.push("## \u5DE5\u4F5C\u7A7A\u95F4\u534F\u8BAE\uFF08PWP\uFF09");
|
|
148
|
+
if (pwp.identity) {
|
|
149
|
+
parts.push(pwp.identity);
|
|
150
|
+
}
|
|
151
|
+
if (pwp.qualityStandards.length > 0) {
|
|
152
|
+
parts.push("\n### \u54C1\u8D28\u6807\u51C6");
|
|
153
|
+
for (const standard of pwp.qualityStandards) {
|
|
154
|
+
parts.push(`- ${standard}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
parts.push(`
|
|
158
|
+
## \u4F60\u7684\u89D2\u8272\uFF1A${agent.name}`);
|
|
159
|
+
if (agent.role) {
|
|
160
|
+
parts.push(agent.role);
|
|
161
|
+
}
|
|
162
|
+
if (agent.style) {
|
|
163
|
+
parts.push(`
|
|
164
|
+
### \u98CE\u683C`);
|
|
165
|
+
parts.push(agent.style);
|
|
166
|
+
}
|
|
167
|
+
if (skill) {
|
|
168
|
+
parts.push(`
|
|
169
|
+
## \u9886\u57DF\u77E5\u8BC6\uFF1A${skill.name}`);
|
|
170
|
+
if (skill.knowledge) {
|
|
171
|
+
parts.push(skill.knowledge);
|
|
172
|
+
}
|
|
173
|
+
if (skill.toolStrategy) {
|
|
174
|
+
parts.push("\n### \u5DE5\u5177\u4F7F\u7528\u7B56\u7565");
|
|
175
|
+
parts.push(skill.toolStrategy);
|
|
176
|
+
}
|
|
177
|
+
if (skill.qualityStandards.length > 0) {
|
|
178
|
+
parts.push("\n### \u9886\u57DF\u8D28\u91CF\u6807\u51C6");
|
|
179
|
+
for (const standard of skill.qualityStandards) {
|
|
180
|
+
parts.push(`- ${standard}`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
parts.push("\n## \u901A\u7528\u6307\u4EE4");
|
|
185
|
+
parts.push("- \u6240\u6709\u8F93\u51FA\u4F7F\u7528\u4E2D\u6587");
|
|
186
|
+
parts.push("- \u9700\u8981\u6700\u65B0\u4FE1\u606F\u65F6\u4E3B\u52A8\u4F7F\u7528 web_search \u5DE5\u5177");
|
|
187
|
+
parts.push("- \u8F93\u51FA\u5FC5\u987B\u6709\u5B9E\u8D28\u5185\u5BB9\u548C\u6D1E\u5BDF\uFF0C\u4E0D\u8981\u7A7A\u6D1E\u7684\u5957\u8BDD");
|
|
188
|
+
parts.push("- \u5982\u679C\u4FE1\u606F\u4E0D\u8DB3\uFF0C\u660E\u786E\u6807\u6CE8\u800C\u975E\u7F16\u9020");
|
|
189
|
+
return parts.join("\n");
|
|
190
|
+
}
|
|
191
|
+
function assembleUserPrompt(station, userInputs, upstreamOutput) {
|
|
192
|
+
const parts = [];
|
|
193
|
+
parts.push("## \u5F53\u524D\u4EFB\u52A1");
|
|
194
|
+
parts.push(station.task);
|
|
195
|
+
if (Object.keys(userInputs).length > 0) {
|
|
196
|
+
parts.push("\n## \u7528\u6237\u8F93\u5165");
|
|
197
|
+
for (const [key, value] of Object.entries(userInputs)) {
|
|
198
|
+
parts.push(`- **${key}**: ${value}`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (upstreamOutput) {
|
|
202
|
+
parts.push("\n## \u4E0A\u4E00\u4E2A\u5DE5\u4F4D\u7684\u4EA7\u51FA");
|
|
203
|
+
if (upstreamOutput.length > 4e3) {
|
|
204
|
+
parts.push(upstreamOutput.slice(0, 4e3));
|
|
205
|
+
parts.push("\n...(\u5185\u5BB9\u5DF2\u622A\u53D6\uFF0C\u4EE5\u4E0A\u4E3A\u4E3B\u8981\u90E8\u5206)");
|
|
206
|
+
} else {
|
|
207
|
+
parts.push(upstreamOutput);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
if (station.checkpoint === "decision") {
|
|
211
|
+
parts.push("\n## \u6CE8\u610F");
|
|
212
|
+
parts.push("\u8BF7\u63D0\u4F9B\u591A\u4E2A\u5019\u9009\u65B9\u6848\u4F9B\u7528\u6237\u9009\u62E9\u3002\u5217\u51FA 2-3 \u4E2A\u65B9\u6848\uFF0C\u6BCF\u4E2A\u65B9\u6848\u5305\u542B\u6807\u9898\u548C\u7B80\u8981\u8BF4\u660E\u3002");
|
|
213
|
+
} else if (station.checkpoint === "approval") {
|
|
214
|
+
parts.push("\n## \u6CE8\u610F");
|
|
215
|
+
parts.push("\u8FD9\u662F\u7EC8\u5BA1\u5DE5\u4F4D\u3002\u8BF7\u786E\u4FDD\u4EA7\u51FA\u7684\u5B8C\u6574\u6027\u548C\u8D28\u91CF\uFF0C\u7528\u6237\u5C06\u5BA1\u9605\u4F60\u7684\u6700\u7EC8\u4EA7\u51FA\u3002");
|
|
216
|
+
}
|
|
217
|
+
return parts.join("\n");
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// src/core/engine.ts
|
|
221
|
+
var Engine = class {
|
|
222
|
+
client;
|
|
223
|
+
config;
|
|
224
|
+
hypercoreDir;
|
|
225
|
+
tools = [];
|
|
226
|
+
constructor(client, config, hypercoreDir) {
|
|
227
|
+
this.client = client;
|
|
228
|
+
this.config = config;
|
|
229
|
+
this.hypercoreDir = hypercoreDir;
|
|
230
|
+
}
|
|
231
|
+
/** 初始化工具(async,需在 run 前调用) */
|
|
232
|
+
async init() {
|
|
233
|
+
this.tools = await createToolRegistry(this.config);
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* 解析工位级模型覆盖
|
|
237
|
+
* 支持别名(flash, sonnet)和完整模型名
|
|
238
|
+
* 返回解析后的模型名和 SDK 类型
|
|
239
|
+
*/
|
|
240
|
+
resolveStationModel(station) {
|
|
241
|
+
if (!station.model) {
|
|
242
|
+
return {
|
|
243
|
+
model: this.config.modelConfig.model,
|
|
244
|
+
sdkType: this.config.modelConfig.sdkType,
|
|
245
|
+
baseURL: this.config.modelConfig.baseURL,
|
|
246
|
+
apiKey: this.config.modelConfig.apiKey
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
const alias = MODEL_ALIASES[station.model.toLowerCase()];
|
|
250
|
+
if (alias) {
|
|
251
|
+
const providerInfo = MODEL_PROVIDERS[alias.provider];
|
|
252
|
+
const apiKey = this.config.providerKeys[alias.provider] || this.config.modelConfig.apiKey;
|
|
253
|
+
return {
|
|
254
|
+
model: alias.model,
|
|
255
|
+
sdkType: providerInfo.sdkType,
|
|
256
|
+
baseURL: providerInfo.baseURL,
|
|
257
|
+
apiKey
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
const modelLower = station.model.toLowerCase();
|
|
261
|
+
if (modelLower.includes("claude")) {
|
|
262
|
+
const apiKey = this.config.providerKeys["anthropic"] || this.config.modelConfig.apiKey;
|
|
263
|
+
return { model: station.model, sdkType: "anthropic", apiKey };
|
|
264
|
+
}
|
|
265
|
+
if (modelLower.includes("gemini")) {
|
|
266
|
+
const apiKey = this.config.providerKeys["gemini"] || this.config.modelConfig.apiKey;
|
|
267
|
+
return { model: station.model, sdkType: "openai", baseURL: MODEL_PROVIDERS["gemini"].baseURL, apiKey };
|
|
268
|
+
}
|
|
269
|
+
if (modelLower.includes("deepseek")) {
|
|
270
|
+
const apiKey = this.config.providerKeys["deepseek"] || this.config.modelConfig.apiKey;
|
|
271
|
+
return { model: station.model, sdkType: "openai", baseURL: MODEL_PROVIDERS["deepseek"].baseURL, apiKey };
|
|
272
|
+
}
|
|
273
|
+
if (modelLower.includes("gpt")) {
|
|
274
|
+
const apiKey = this.config.providerKeys["openai-compatible"] || this.config.modelConfig.apiKey;
|
|
275
|
+
return { model: station.model, sdkType: "openai", baseURL: this.config.modelConfig.baseURL, apiKey };
|
|
276
|
+
}
|
|
277
|
+
return {
|
|
278
|
+
model: station.model,
|
|
279
|
+
sdkType: this.config.modelConfig.sdkType,
|
|
280
|
+
baseURL: this.config.modelConfig.baseURL,
|
|
281
|
+
apiKey: this.config.modelConfig.apiKey
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* 根据 sdkType 调用对应的 LLM 客户端
|
|
286
|
+
* 支持工位级模型覆盖(不同 sdkType 动态创建客户端)
|
|
287
|
+
*/
|
|
288
|
+
async invokeLLM(options, sdkTypeOverride, baseURLOverride, apiKeyOverride) {
|
|
289
|
+
const sdkType = sdkTypeOverride || this.config.modelConfig.sdkType;
|
|
290
|
+
const apiKey = apiKeyOverride || this.config.modelConfig.apiKey;
|
|
291
|
+
if (sdkType === "openai") {
|
|
292
|
+
if (this.config.modelConfig.sdkType !== "openai" || baseURLOverride || apiKeyOverride) {
|
|
293
|
+
const OpenAI2 = await import("openai");
|
|
294
|
+
const tempClient = new OpenAI2.default({
|
|
295
|
+
apiKey,
|
|
296
|
+
baseURL: baseURLOverride || this.config.modelConfig.baseURL
|
|
297
|
+
});
|
|
298
|
+
return callOpenAILLM(tempClient, options);
|
|
299
|
+
}
|
|
300
|
+
const OpenAI = await import("openai");
|
|
301
|
+
return callOpenAILLM(this.client, options);
|
|
302
|
+
}
|
|
303
|
+
if (this.config.modelConfig.sdkType !== "anthropic" || apiKeyOverride) {
|
|
304
|
+
const Anthropic2 = await import("@anthropic-ai/sdk");
|
|
305
|
+
const tempClient = new Anthropic2.default({ apiKey });
|
|
306
|
+
return callLLM(tempClient, options);
|
|
307
|
+
}
|
|
308
|
+
const Anthropic = await import("@anthropic-ai/sdk");
|
|
309
|
+
return callLLM(this.client, options);
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* 评估条件表达式
|
|
313
|
+
* 支持简单的关键词匹配:检查上游输出是否包含指定关键词
|
|
314
|
+
* 格式:'contains:关键词' 或 'not_empty' 或直接传入关键词
|
|
315
|
+
*/
|
|
316
|
+
evaluateCondition(condition, upstreamOutput) {
|
|
317
|
+
if (!upstreamOutput) return false;
|
|
318
|
+
const condLower = condition.toLowerCase().trim();
|
|
319
|
+
if (condLower === "not_empty") {
|
|
320
|
+
return upstreamOutput.trim().length > 0;
|
|
321
|
+
}
|
|
322
|
+
if (condLower.startsWith("contains:")) {
|
|
323
|
+
const keyword = condition.slice("contains:".length).trim();
|
|
324
|
+
return upstreamOutput.includes(keyword);
|
|
325
|
+
}
|
|
326
|
+
if (condLower.startsWith("not_contains:")) {
|
|
327
|
+
const keyword = condition.slice("not_contains:".length).trim();
|
|
328
|
+
return !upstreamOutput.includes(keyword);
|
|
329
|
+
}
|
|
330
|
+
return upstreamOutput.includes(condition.trim());
|
|
331
|
+
}
|
|
332
|
+
async run(lineName, userInputs, callbacks) {
|
|
333
|
+
const startTime = /* @__PURE__ */ new Date();
|
|
334
|
+
if (this.tools.length === 0) {
|
|
335
|
+
await this.init();
|
|
336
|
+
}
|
|
337
|
+
const line = await loadLine(this.hypercoreDir, lineName);
|
|
338
|
+
let pwp;
|
|
339
|
+
try {
|
|
340
|
+
pwp = await loadPWP(this.hypercoreDir);
|
|
341
|
+
} catch {
|
|
342
|
+
pwp = { identity: "", qualityStandards: [], rawContent: "" };
|
|
343
|
+
}
|
|
344
|
+
const stationResults = [];
|
|
345
|
+
let upstreamOutput;
|
|
346
|
+
const totalTokens = { inputTokens: 0, outputTokens: 0 };
|
|
347
|
+
for (const station of line.stations) {
|
|
348
|
+
if (station.condition) {
|
|
349
|
+
const shouldRun = this.evaluateCondition(station.condition, upstreamOutput);
|
|
350
|
+
if (!shouldRun) {
|
|
351
|
+
callbacks.onStationSkipped?.(station.index, station.name, `\u6761\u4EF6\u4E0D\u6EE1\u8DB3: ${station.condition}`);
|
|
352
|
+
stationResults.push({
|
|
353
|
+
stationIndex: station.index,
|
|
354
|
+
stationName: station.name,
|
|
355
|
+
agentName: station.agentName,
|
|
356
|
+
output: upstreamOutput || "",
|
|
357
|
+
toolCalls: [],
|
|
358
|
+
tokenUsage: { inputTokens: 0, outputTokens: 0 }
|
|
359
|
+
});
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
callbacks.onStationStart(
|
|
364
|
+
station.index,
|
|
365
|
+
line.stations.length,
|
|
366
|
+
station.name,
|
|
367
|
+
station.agentName
|
|
368
|
+
);
|
|
369
|
+
const { model: stationModel, sdkType: stationSdkType, baseURL: stationBaseURL, apiKey: stationApiKey } = this.resolveStationModel(station);
|
|
370
|
+
let agent;
|
|
371
|
+
try {
|
|
372
|
+
agent = await loadAgent(this.hypercoreDir, station.agentName);
|
|
373
|
+
} catch {
|
|
374
|
+
agent = {
|
|
375
|
+
name: station.agentName,
|
|
376
|
+
role: `\u4F60\u662F${station.agentName}`,
|
|
377
|
+
skillIds: [],
|
|
378
|
+
style: "",
|
|
379
|
+
rawContent: ""
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
let skill;
|
|
383
|
+
if (station.skillName) {
|
|
384
|
+
try {
|
|
385
|
+
skill = await loadSkill(this.hypercoreDir, station.skillName);
|
|
386
|
+
} catch {
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
const systemPrompt = assembleSystemPrompt(pwp, agent, skill);
|
|
390
|
+
const userPrompt = assembleUserPrompt(station, userInputs, upstreamOutput);
|
|
391
|
+
const maxRetry = station.retry || 0;
|
|
392
|
+
let result = null;
|
|
393
|
+
let lastError = null;
|
|
394
|
+
for (let attempt = 0; attempt <= maxRetry; attempt++) {
|
|
395
|
+
try {
|
|
396
|
+
if (attempt > 0) {
|
|
397
|
+
callbacks.onStationRetry?.(
|
|
398
|
+
station.index,
|
|
399
|
+
station.name,
|
|
400
|
+
attempt,
|
|
401
|
+
maxRetry,
|
|
402
|
+
lastError?.message || "\u672A\u77E5\u9519\u8BEF"
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
result = await this.invokeLLM(
|
|
406
|
+
{
|
|
407
|
+
systemPrompt,
|
|
408
|
+
userPrompt,
|
|
409
|
+
tools: this.tools,
|
|
410
|
+
model: stationModel,
|
|
411
|
+
onText: (text) => callbacks.onStationText(text),
|
|
412
|
+
onToolCall: (name, input) => callbacks.onToolCall(name, input),
|
|
413
|
+
onToolCallDone: callbacks.onToolCallDone ? (name, dur) => callbacks.onToolCallDone(name, dur) : void 0,
|
|
414
|
+
onThinking: callbacks.onThinking ? (text) => callbacks.onThinking(text) : void 0
|
|
415
|
+
},
|
|
416
|
+
stationSdkType,
|
|
417
|
+
stationBaseURL,
|
|
418
|
+
stationApiKey !== this.config.modelConfig.apiKey ? stationApiKey : void 0
|
|
419
|
+
);
|
|
420
|
+
break;
|
|
421
|
+
} catch (err) {
|
|
422
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
423
|
+
if (attempt >= maxRetry) {
|
|
424
|
+
throw lastError;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
if (!result) throw new Error(`\u5DE5\u4F4D ${station.name} \u6267\u884C\u5931\u8D25`);
|
|
429
|
+
const stationResult = {
|
|
430
|
+
stationIndex: station.index,
|
|
431
|
+
stationName: station.name,
|
|
432
|
+
agentName: station.agentName,
|
|
433
|
+
output: result.output,
|
|
434
|
+
toolCalls: result.toolCalls,
|
|
435
|
+
tokenUsage: result.tokenUsage
|
|
436
|
+
};
|
|
437
|
+
stationResults.push(stationResult);
|
|
438
|
+
totalTokens.inputTokens += result.tokenUsage.inputTokens;
|
|
439
|
+
totalTokens.outputTokens += result.tokenUsage.outputTokens;
|
|
440
|
+
callbacks.onStationComplete(station.index, station.name);
|
|
441
|
+
if (station.checkpoint) {
|
|
442
|
+
const checkpointResult = await callbacks.onCheckpoint(
|
|
443
|
+
station.checkpoint,
|
|
444
|
+
result.output,
|
|
445
|
+
station.checkpointDescription
|
|
446
|
+
);
|
|
447
|
+
if (checkpointResult.action === "modify" && checkpointResult.feedback) {
|
|
448
|
+
const modifyPrompt = `\u7528\u6237\u5BF9\u4F60\u7684\u4EA7\u51FA\u7ED9\u4E86\u4EE5\u4E0B\u53CD\u9988\uFF0C\u8BF7\u636E\u6B64\u4FEE\u6539\uFF1A
|
|
449
|
+
|
|
450
|
+
${checkpointResult.feedback}
|
|
451
|
+
|
|
452
|
+
\u4F60\u4E4B\u524D\u7684\u4EA7\u51FA\uFF1A
|
|
453
|
+
${result.output}`;
|
|
454
|
+
const modifyResult = await this.invokeLLM(
|
|
455
|
+
{
|
|
456
|
+
systemPrompt,
|
|
457
|
+
userPrompt: modifyPrompt,
|
|
458
|
+
tools: this.tools,
|
|
459
|
+
model: stationModel,
|
|
460
|
+
onText: (text) => callbacks.onStationText(text),
|
|
461
|
+
onToolCall: (name, input) => callbacks.onToolCall(name, input),
|
|
462
|
+
onToolCallDone: callbacks.onToolCallDone ? (name, dur) => callbacks.onToolCallDone(name, dur) : void 0,
|
|
463
|
+
onThinking: callbacks.onThinking ? (text) => callbacks.onThinking(text) : void 0
|
|
464
|
+
},
|
|
465
|
+
stationSdkType,
|
|
466
|
+
stationBaseURL,
|
|
467
|
+
stationApiKey !== this.config.modelConfig.apiKey ? stationApiKey : void 0
|
|
468
|
+
);
|
|
469
|
+
stationResult.output = modifyResult.output;
|
|
470
|
+
totalTokens.inputTokens += modifyResult.tokenUsage.inputTokens;
|
|
471
|
+
totalTokens.outputTokens += modifyResult.tokenUsage.outputTokens;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
upstreamOutput = stationResult.output;
|
|
475
|
+
}
|
|
476
|
+
const finalOutput = stationResults[stationResults.length - 1]?.output || "";
|
|
477
|
+
const outputDir = join2(this.config.outputDir);
|
|
478
|
+
await mkdir2(outputDir, { recursive: true });
|
|
479
|
+
const endTime = /* @__PURE__ */ new Date();
|
|
480
|
+
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
481
|
+
const sanitizedName = lineName.replace(/[^\w\u4e00-\u9fff-]/g, "_");
|
|
482
|
+
const outputPath = join2(outputDir, `${date}-${sanitizedName}.md`);
|
|
483
|
+
const durationMin = ((endTime.getTime() - startTime.getTime()) / 6e4).toFixed(1);
|
|
484
|
+
const totalTokenCount = totalTokens.inputTokens + totalTokens.outputTokens;
|
|
485
|
+
const frontmatter = [
|
|
486
|
+
"---",
|
|
487
|
+
`line: ${lineName}`,
|
|
488
|
+
`date: ${startTime.toISOString()}`,
|
|
489
|
+
`model: ${this.config.modelConfig.model}`,
|
|
490
|
+
`tokens: ${totalTokenCount}`,
|
|
491
|
+
`duration: ${durationMin}min`,
|
|
492
|
+
`stations: ${line.stations.length}`,
|
|
493
|
+
"---",
|
|
494
|
+
""
|
|
495
|
+
].join("\n");
|
|
496
|
+
await writeFile2(outputPath, frontmatter + finalOutput, "utf-8");
|
|
497
|
+
const runMeta = {
|
|
498
|
+
lineName,
|
|
499
|
+
startTime: startTime.toISOString(),
|
|
500
|
+
endTime: endTime.toISOString(),
|
|
501
|
+
model: this.config.modelConfig.model,
|
|
502
|
+
userInputs,
|
|
503
|
+
totalTokens,
|
|
504
|
+
stations: stationResults.map((s) => ({
|
|
505
|
+
index: s.stationIndex,
|
|
506
|
+
name: s.stationName,
|
|
507
|
+
agent: s.agentName,
|
|
508
|
+
output: s.output,
|
|
509
|
+
toolCalls: s.toolCalls,
|
|
510
|
+
tokens: s.tokenUsage
|
|
511
|
+
}))
|
|
512
|
+
};
|
|
513
|
+
const jsonPath = outputPath.replace(/\.md$/, ".run.json");
|
|
514
|
+
await writeFile2(jsonPath, JSON.stringify(runMeta, null, 2), "utf-8");
|
|
515
|
+
const runResult = {
|
|
516
|
+
lineName,
|
|
517
|
+
stationResults,
|
|
518
|
+
finalOutput,
|
|
519
|
+
totalTokens,
|
|
520
|
+
outputPath,
|
|
521
|
+
startTime,
|
|
522
|
+
endTime
|
|
523
|
+
};
|
|
524
|
+
callbacks.onComplete(runResult);
|
|
525
|
+
return runResult;
|
|
526
|
+
}
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
export {
|
|
530
|
+
HYPERCORE_DIR,
|
|
531
|
+
initializeWorkspace,
|
|
532
|
+
Engine
|
|
533
|
+
};
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import {
|
|
2
|
+
listItems
|
|
3
|
+
} from "./chunk-MGLJ53QN.js";
|
|
4
|
+
|
|
5
|
+
// src/admin/roadmap.ts
|
|
6
|
+
import { join } from "path";
|
|
7
|
+
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
8
|
+
import { existsSync } from "fs";
|
|
9
|
+
var HYPERCORE_DIR = join(process.env.HOME || "~", ".hypercore");
|
|
10
|
+
var ADMIN_DIR = join(HYPERCORE_DIR, "admin");
|
|
11
|
+
var MILESTONES_FILE = join(ADMIN_DIR, "milestones.json");
|
|
12
|
+
async function ensureDir() {
|
|
13
|
+
if (!existsSync(ADMIN_DIR)) {
|
|
14
|
+
await mkdir(ADMIN_DIR, { recursive: true });
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
async function loadStore() {
|
|
18
|
+
await ensureDir();
|
|
19
|
+
if (!existsSync(MILESTONES_FILE)) {
|
|
20
|
+
return { milestones: [] };
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
const raw = await readFile(MILESTONES_FILE, "utf-8");
|
|
24
|
+
return JSON.parse(raw);
|
|
25
|
+
} catch {
|
|
26
|
+
return { milestones: [] };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
async function saveStore(store) {
|
|
30
|
+
await ensureDir();
|
|
31
|
+
await writeFile(MILESTONES_FILE, JSON.stringify(store, null, 2), "utf-8");
|
|
32
|
+
}
|
|
33
|
+
async function addMilestone(version, name, description) {
|
|
34
|
+
const store = await loadStore();
|
|
35
|
+
if (store.milestones.find((m) => m.version === version)) {
|
|
36
|
+
throw new Error(`\u91CC\u7A0B\u7891 ${version} \u5DF2\u5B58\u5728`);
|
|
37
|
+
}
|
|
38
|
+
const milestone = {
|
|
39
|
+
version,
|
|
40
|
+
name,
|
|
41
|
+
description: description || "",
|
|
42
|
+
status: "planning",
|
|
43
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
44
|
+
doneAt: null
|
|
45
|
+
};
|
|
46
|
+
store.milestones.push(milestone);
|
|
47
|
+
await saveStore(store);
|
|
48
|
+
return milestone;
|
|
49
|
+
}
|
|
50
|
+
async function doneMilestone(version) {
|
|
51
|
+
const store = await loadStore();
|
|
52
|
+
const ms = store.milestones.find((m) => m.version === version);
|
|
53
|
+
if (!ms) return null;
|
|
54
|
+
ms.status = "done";
|
|
55
|
+
ms.doneAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
56
|
+
await saveStore(store);
|
|
57
|
+
return ms;
|
|
58
|
+
}
|
|
59
|
+
async function activateMilestone(version) {
|
|
60
|
+
const store = await loadStore();
|
|
61
|
+
const ms = store.milestones.find((m) => m.version === version);
|
|
62
|
+
if (!ms) return null;
|
|
63
|
+
ms.status = "active";
|
|
64
|
+
await saveStore(store);
|
|
65
|
+
return ms;
|
|
66
|
+
}
|
|
67
|
+
async function listMilestones() {
|
|
68
|
+
const store = await loadStore();
|
|
69
|
+
return store.milestones;
|
|
70
|
+
}
|
|
71
|
+
async function getMilestone(version) {
|
|
72
|
+
const store = await loadStore();
|
|
73
|
+
return store.milestones.find((m) => m.version === version) || null;
|
|
74
|
+
}
|
|
75
|
+
async function getRoadmap() {
|
|
76
|
+
const allItems = await listItems();
|
|
77
|
+
const milestones = await listMilestones();
|
|
78
|
+
const grouped = {};
|
|
79
|
+
const unversioned = [];
|
|
80
|
+
for (const item of allItems) {
|
|
81
|
+
if (item.targetVersion) {
|
|
82
|
+
if (!grouped[item.targetVersion]) grouped[item.targetVersion] = [];
|
|
83
|
+
grouped[item.targetVersion].push(item);
|
|
84
|
+
} else {
|
|
85
|
+
unversioned.push(item);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
for (const ms of milestones) {
|
|
89
|
+
if (!grouped[ms.version]) grouped[ms.version] = [];
|
|
90
|
+
}
|
|
91
|
+
const versions = Object.keys(grouped).sort(compareVersions);
|
|
92
|
+
const roadmap = versions.map((ver) => {
|
|
93
|
+
const items = grouped[ver];
|
|
94
|
+
const milestone = milestones.find((m) => m.version === ver) || null;
|
|
95
|
+
const done = items.filter((i) => i.status === "done").length;
|
|
96
|
+
const developing = items.filter((i) => i.status === "developing").length;
|
|
97
|
+
const planned = items.filter((i) => i.status === "planned").length;
|
|
98
|
+
const idea = items.filter((i) => i.status === "idea").length;
|
|
99
|
+
const total = items.length;
|
|
100
|
+
return {
|
|
101
|
+
version: ver,
|
|
102
|
+
milestone,
|
|
103
|
+
items,
|
|
104
|
+
stats: {
|
|
105
|
+
total,
|
|
106
|
+
done,
|
|
107
|
+
developing,
|
|
108
|
+
planned,
|
|
109
|
+
idea,
|
|
110
|
+
progress: total > 0 ? Math.round(done / total * 100) : 0
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
});
|
|
114
|
+
if (unversioned.length > 0) {
|
|
115
|
+
const done = unversioned.filter((i) => i.status === "done").length;
|
|
116
|
+
roadmap.push({
|
|
117
|
+
version: "(\u672A\u5206\u914D)",
|
|
118
|
+
milestone: null,
|
|
119
|
+
items: unversioned,
|
|
120
|
+
stats: {
|
|
121
|
+
total: unversioned.length,
|
|
122
|
+
done,
|
|
123
|
+
developing: unversioned.filter((i) => i.status === "developing").length,
|
|
124
|
+
planned: unversioned.filter((i) => i.status === "planned").length,
|
|
125
|
+
idea: unversioned.filter((i) => i.status === "idea").length,
|
|
126
|
+
progress: unversioned.length > 0 ? Math.round(done / unversioned.length * 100) : 0
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
return roadmap;
|
|
131
|
+
}
|
|
132
|
+
function compareVersions(a, b) {
|
|
133
|
+
const normalize = (v) => v.replace(/^v/, "").split(".").map((n) => parseInt(n) || 0);
|
|
134
|
+
const aParts = normalize(a);
|
|
135
|
+
const bParts = normalize(b);
|
|
136
|
+
for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {
|
|
137
|
+
const diff = (aParts[i] || 0) - (bParts[i] || 0);
|
|
138
|
+
if (diff !== 0) return diff;
|
|
139
|
+
}
|
|
140
|
+
return 0;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export {
|
|
144
|
+
addMilestone,
|
|
145
|
+
doneMilestone,
|
|
146
|
+
activateMilestone,
|
|
147
|
+
listMilestones,
|
|
148
|
+
getMilestone,
|
|
149
|
+
getRoadmap
|
|
150
|
+
};
|