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.
Files changed (84) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +110 -0
  3. package/dist/api-XGC7D5AW.js +162 -0
  4. package/dist/auth-DNQWYQKT.js +21 -0
  5. package/dist/background-2EGCAAQH.js +14 -0
  6. package/dist/backlog-Q2NZCLNY.js +24 -0
  7. package/dist/chunk-2CMSCWQW.js +162 -0
  8. package/dist/chunk-2LJ2DVEB.js +167 -0
  9. package/dist/chunk-3RPFCQKJ.js +288 -0
  10. package/dist/chunk-43OLRXM5.js +263 -0
  11. package/dist/chunk-4DVYJAJL.js +57 -0
  12. package/dist/chunk-6OL3GA3P.js +173 -0
  13. package/dist/chunk-AUHU7ALH.js +2023 -0
  14. package/dist/chunk-B6A2AKLN.js +139 -0
  15. package/dist/chunk-BE46C7JW.js +46 -0
  16. package/dist/chunk-CUVAUOXL.js +58 -0
  17. package/dist/chunk-GH7E2OJE.js +223 -0
  18. package/dist/chunk-GOOTEPBK.js +271 -0
  19. package/dist/chunk-GPPMJYSM.js +133 -0
  20. package/dist/chunk-GU2FZQ6A.js +69 -0
  21. package/dist/chunk-IOPKN5GD.js +190 -0
  22. package/dist/chunk-IXOIOGR5.js +1505 -0
  23. package/dist/chunk-KRPOPWGA.js +251 -0
  24. package/dist/chunk-MGLJ53QN.js +219 -0
  25. package/dist/chunk-MV4TTRYX.js +533 -0
  26. package/dist/chunk-OPZYEVYR.js +150 -0
  27. package/dist/chunk-QTSLP47C.js +166 -0
  28. package/dist/chunk-R3GPQC7I.js +393 -0
  29. package/dist/chunk-RKB2JOV2.js +43 -0
  30. package/dist/chunk-RNG3K465.js +80 -0
  31. package/dist/chunk-TGTYKBGC.js +86 -0
  32. package/dist/chunk-U5SGAIMM.js +681 -0
  33. package/dist/chunk-V5UHPPSY.js +140 -0
  34. package/dist/chunk-WHLVZCQY.js +245 -0
  35. package/dist/chunk-XDRCBMZZ.js +66 -0
  36. package/dist/chunk-XOS6HPEF.js +134 -0
  37. package/dist/chunk-ZSBHUGWR.js +262 -0
  38. package/dist/claude-NSQ442XD.js +12 -0
  39. package/dist/commands-CK3WFAGI.js +128 -0
  40. package/dist/commands-U63OEO5J.js +1044 -0
  41. package/dist/commands-ZE6GD3WC.js +232 -0
  42. package/dist/config-4EW42BSF.js +8 -0
  43. package/dist/config-loader-SXO674TF.js +24 -0
  44. package/dist/diagnose-AFW3ZTZ4.js +12 -0
  45. package/dist/display-IIUBEYWN.js +58 -0
  46. package/dist/extractor-QV53W2YJ.js +129 -0
  47. package/dist/history-WMSCHERZ.js +180 -0
  48. package/dist/index.d.ts +1 -0
  49. package/dist/index.js +406 -0
  50. package/dist/instance-registry-YSIJXSO7.js +15 -0
  51. package/dist/keybindings-JAAMLH3G.js +15 -0
  52. package/dist/loader-WHNTZTLP.js +58 -0
  53. package/dist/network-MM6YWPGO.js +279 -0
  54. package/dist/notify-HPTALZDC.js +14 -0
  55. package/dist/openai-compat-UQWJXBEK.js +12 -0
  56. package/dist/permissions-JUKXMNDH.js +10 -0
  57. package/dist/prompt-QV45TXRL.js +166 -0
  58. package/dist/quality-ST7PPNFR.js +16 -0
  59. package/dist/repl-RT3AHL7M.js +3375 -0
  60. package/dist/roadmap-5OBEKROY.js +17 -0
  61. package/dist/server-PORT7OEG.js +57 -0
  62. package/dist/session-4VUNDWLH.js +21 -0
  63. package/dist/skills-V4A35XKG.js +175 -0
  64. package/dist/store-Y4LU5QTO.js +25 -0
  65. package/dist/team-HO7Z4SIM.js +385 -0
  66. package/dist/telemetry-6R4EIE6O.js +30 -0
  67. package/dist/test-runner-ZQH5Y6OJ.js +619 -0
  68. package/dist/theme-3SYJ3UQA.js +14 -0
  69. package/dist/upgrade-7TGI3SXO.js +83 -0
  70. package/dist/verify-JUDKTPKZ.js +14 -0
  71. package/dist/web/static/app.js +562 -0
  72. package/dist/web/static/index.html +132 -0
  73. package/dist/web/static/mirror.css +1001 -0
  74. package/dist/web/static/mirror.html +184 -0
  75. package/dist/web/static/mirror.js +1125 -0
  76. package/dist/web/static/onboard.css +302 -0
  77. package/dist/web/static/onboard.html +140 -0
  78. package/dist/web/static/onboard.js +260 -0
  79. package/dist/web/static/style.css +602 -0
  80. package/dist/web/static/workspace.css +1568 -0
  81. package/dist/web/static/workspace.html +408 -0
  82. package/dist/web/static/workspace.js +1683 -0
  83. package/dist/web-Z5HSCQHW.js +39 -0
  84. 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
+ };