superlab 0.1.7 → 0.1.9

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 (71) hide show
  1. package/README.md +65 -17
  2. package/README.zh-CN.md +64 -15
  3. package/bin/superlab.cjs +232 -1
  4. package/lib/context.cjs +337 -0
  5. package/lib/i18n.cjs +693 -41
  6. package/lib/install.cjs +253 -53
  7. package/package-assets/claude/commands/lab/framing.md +11 -0
  8. package/package-assets/claude/commands/lab/idea.md +2 -1
  9. package/package-assets/claude/commands/lab/iterate.md +2 -1
  10. package/package-assets/claude/commands/lab/report.md +2 -1
  11. package/package-assets/claude/commands/lab/review.md +2 -1
  12. package/package-assets/claude/commands/lab/run.md +2 -1
  13. package/package-assets/claude/commands/lab/spec.md +2 -1
  14. package/package-assets/claude/commands/lab/write.md +2 -1
  15. package/package-assets/claude/commands/lab.md +48 -0
  16. package/package-assets/codex/prompts/lab-framing.md +9 -0
  17. package/package-assets/codex/prompts/lab-idea.md +2 -1
  18. package/package-assets/codex/prompts/lab-iterate.md +2 -1
  19. package/package-assets/codex/prompts/lab-report.md +2 -1
  20. package/package-assets/codex/prompts/lab-review.md +2 -1
  21. package/package-assets/codex/prompts/lab-run.md +2 -1
  22. package/package-assets/codex/prompts/lab-spec.md +2 -1
  23. package/package-assets/codex/prompts/lab-write.md +2 -1
  24. package/package-assets/codex/prompts/lab.md +46 -0
  25. package/package-assets/shared/{templates → lab/.managed/templates}/design.md +3 -3
  26. package/package-assets/shared/lab/.managed/templates/framing.md +68 -0
  27. package/package-assets/shared/{templates → lab/.managed/templates}/paper-plan.md +1 -0
  28. package/package-assets/shared/{templates → lab/.managed/templates}/proposal.md +1 -1
  29. package/package-assets/shared/{templates → lab/.managed/templates}/spec.md +2 -2
  30. package/package-assets/shared/{templates → lab/.managed/templates}/tasks.md +2 -2
  31. package/package-assets/shared/{templates → lab/.managed/templates}/write-iteration.md +1 -0
  32. package/package-assets/shared/lab/changes/README.md +10 -0
  33. package/package-assets/shared/lab/config/workflow.json +6 -0
  34. package/package-assets/shared/lab/context/next-action.md +19 -0
  35. package/package-assets/shared/lab/context/session-brief.md +30 -0
  36. package/package-assets/shared/lab/context/summary.md +21 -0
  37. package/package-assets/shared/lab/context/terminology-lock.md +28 -0
  38. package/package-assets/shared/lab/system/core.md +41 -0
  39. package/package-assets/shared/skills/lab/SKILL.md +54 -37
  40. package/package-assets/shared/skills/lab/references/paper-writing/abstract.md +2 -17
  41. package/package-assets/shared/skills/lab/references/paper-writing/introduction.md +3 -63
  42. package/package-assets/shared/skills/lab/references/paper-writing/method.md +4 -34
  43. package/package-assets/shared/skills/lab/references/workflow.md +4 -4
  44. package/package-assets/shared/skills/lab/stages/framing.md +72 -0
  45. package/package-assets/shared/skills/lab/stages/idea.md +5 -5
  46. package/package-assets/shared/skills/lab/stages/iterate.md +8 -8
  47. package/package-assets/shared/skills/lab/stages/report.md +7 -6
  48. package/package-assets/shared/skills/lab/stages/review.md +6 -5
  49. package/package-assets/shared/skills/lab/stages/run.md +4 -4
  50. package/package-assets/shared/skills/lab/stages/spec.md +11 -11
  51. package/package-assets/shared/skills/lab/stages/write.md +14 -10
  52. package/package.json +1 -1
  53. package/package-assets/shared/changes/README.md +0 -10
  54. package/package-assets/shared/config/workflow.json +0 -5
  55. package/package-assets/shared/examples/minimal-uplift-workflow.md +0 -73
  56. /package/package-assets/shared/{scripts → lab/.managed/scripts}/eval_report.py +0 -0
  57. /package/package-assets/shared/{scripts → lab/.managed/scripts}/register_run.py +0 -0
  58. /package/package-assets/shared/{scripts → lab/.managed/scripts}/summarize_iterations.py +0 -0
  59. /package/package-assets/shared/{scripts → lab/.managed/scripts}/validate_results.py +0 -0
  60. /package/package-assets/shared/{templates → lab/.managed/templates}/final-report.md +0 -0
  61. /package/package-assets/shared/{templates → lab/.managed/templates}/idea.md +0 -0
  62. /package/package-assets/shared/{templates → lab/.managed/templates}/iteration-report.md +0 -0
  63. /package/package-assets/shared/{templates → lab/.managed/templates}/paper-section.md +0 -0
  64. /package/package-assets/shared/{templates → lab/.managed/templates}/paper-section.tex +0 -0
  65. /package/package-assets/shared/{templates → lab/.managed/templates}/paper.tex +0 -0
  66. /package/package-assets/shared/{templates → lab/.managed/templates}/review-checklist.md +0 -0
  67. /package/package-assets/shared/{context → lab/context}/decisions.md +0 -0
  68. /package/package-assets/shared/{context → lab/context}/evidence-index.md +0 -0
  69. /package/package-assets/shared/{context → lab/context}/mission.md +0 -0
  70. /package/package-assets/shared/{context → lab/context}/open-questions.md +0 -0
  71. /package/package-assets/shared/{context → lab/context}/state.md +0 -0
@@ -0,0 +1,337 @@
1
+ const fs = require("node:fs");
2
+ const path = require("node:path");
3
+
4
+ function contextFile(targetDir, name) {
5
+ return path.join(targetDir, ".lab", "context", name);
6
+ }
7
+
8
+ function readFileIfExists(filePath) {
9
+ if (!fs.existsSync(filePath)) {
10
+ return "";
11
+ }
12
+ return fs.readFileSync(filePath, "utf8");
13
+ }
14
+
15
+ function readWorkflowLanguage(targetDir) {
16
+ const configPath = path.join(targetDir, ".lab", "config", "workflow.json");
17
+ if (!fs.existsSync(configPath)) {
18
+ return "en";
19
+ }
20
+ try {
21
+ const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
22
+ return config.workflow_language === "zh" ? "zh" : "en";
23
+ } catch {
24
+ return "en";
25
+ }
26
+ }
27
+
28
+ function extractValue(text, labels) {
29
+ for (const label of labels) {
30
+ const escaped = label.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
31
+ const regex = new RegExp(`^\\s*(?:[-\\d.]+\\s*)?${escaped}:\\s*(.+?)\\s*$`, "im");
32
+ const match = text.match(regex);
33
+ if (match && match[1]) {
34
+ return match[1].trim();
35
+ }
36
+ }
37
+ return "";
38
+ }
39
+
40
+ function extractOpenQuestion(text) {
41
+ const blocks = text
42
+ .split(/\n(?=\d+\.\s)/)
43
+ .map((block) => block.trim())
44
+ .filter(Boolean);
45
+ for (const block of blocks) {
46
+ if (!/Status:\s*(resolved|stale)/i.test(block)) {
47
+ const question = extractValue(block, ["Question", "问题"]);
48
+ if (question) {
49
+ return question;
50
+ }
51
+ }
52
+ }
53
+ return "";
54
+ }
55
+
56
+ function extractClaim(text) {
57
+ const blocks = text
58
+ .split(/\n(?=\d+\.\s)/)
59
+ .map((block) => block.trim())
60
+ .filter(Boolean);
61
+ for (const block of blocks) {
62
+ const claim = extractValue(block, ["Claim"]);
63
+ if (claim) {
64
+ return claim;
65
+ }
66
+ }
67
+ return "";
68
+ }
69
+
70
+ function renderSummary(lang, data) {
71
+ if (lang === "zh") {
72
+ return `# 研究摘要
73
+
74
+ ## 当前方向
75
+
76
+ - Mission: ${data.problem || "待补充"}
77
+ - Approved direction: ${data.direction || "待补充"}
78
+ - Active stage: ${data.stage || "待补充"}
79
+
80
+ ## 最强证据
81
+
82
+ - Claim: ${data.claim || "待补充"}
83
+
84
+ ## 最大风险
85
+
86
+ - Risk: ${data.risk || "待补充"}
87
+
88
+ ## 当前缺口
89
+
90
+ - Open question: ${data.question || "待补充"}
91
+ `;
92
+ }
93
+
94
+ return `# Research Summary
95
+
96
+ ## Current Direction
97
+
98
+ - Mission: ${data.problem || "TBD"}
99
+ - Approved direction: ${data.direction || "TBD"}
100
+ - Active stage: ${data.stage || "TBD"}
101
+
102
+ ## Strongest Evidence
103
+
104
+ - Claim: ${data.claim || "TBD"}
105
+
106
+ ## Largest Risk
107
+
108
+ - Risk: ${data.risk || "TBD"}
109
+
110
+ ## Current Gap
111
+
112
+ - Open question: ${data.question || "TBD"}
113
+ `;
114
+ }
115
+
116
+ function renderNextAction(lang, data) {
117
+ if (lang === "zh") {
118
+ return `# 下一步动作
119
+
120
+ ## 当前动作
121
+
122
+ - Action: ${data.immediateAction || "待补充"}
123
+ - Success signal: ${data.nextArtifact || data.threshold || "待补充"}
124
+
125
+ ## 如果成功
126
+
127
+ - Next action: ${data.successFollowup || "继续推进当前阶段"}
128
+
129
+ ## 如果失败
130
+
131
+ - Fallback action: ${data.blocker ? `先处理阻塞:${data.blocker}` : "回到 review 或 iterate"}
132
+
133
+ ## 是否需要人工决策
134
+
135
+ - Question: ${data.humanDecision || "无"}
136
+ - 为什么会阻塞:${data.blocker || "无"}
137
+ `;
138
+ }
139
+
140
+ return `# Next Action
141
+
142
+ ## Immediate Step
143
+
144
+ - Action: ${data.immediateAction || "TBD"}
145
+ - Success signal: ${data.nextArtifact || data.threshold || "TBD"}
146
+
147
+ ## If Success
148
+
149
+ - Next action: ${data.successFollowup || "Continue the active stage"}
150
+
151
+ ## If Failure
152
+
153
+ - Fallback action: ${data.blocker ? `Resolve blocker: ${data.blocker}` : "Route back to review or iterate"}
154
+
155
+ ## Human Decision Needed
156
+
157
+ - Question: ${data.humanDecision || "none"}
158
+ - Why it blocks progress: ${data.blocker || "none"}
159
+ `;
160
+ }
161
+
162
+ function renderSessionBrief(lang, data) {
163
+ if (lang === "zh") {
164
+ return `# 会话简报
165
+
166
+ ## 当前阶段
167
+
168
+ - Stage: ${data.stage || "待补充"}
169
+
170
+ ## 主线任务
171
+
172
+ ${data.problem || "待补充"}
173
+
174
+ ## 当前最优路径
175
+
176
+ - Approved direction: ${data.direction || "待补充"}
177
+ - Why this is the active path: ${data.why || "当前已批准方向"}
178
+
179
+ ## 主要风险
180
+
181
+ - Risk: ${data.risk || "待补充"}
182
+ - Evidence gap: ${data.question || "待补充"}
183
+
184
+ ## 先读这些文件
185
+
186
+ 1. \`.lab/context/mission.md\`
187
+ 2. \`.lab/context/state.md\`
188
+ 3. \`.lab/context/evidence-index.md\`
189
+
190
+ ## 不要静默修改
191
+
192
+ - Frozen boundary: ${data.boundary || "待补充"}
193
+ - Approval gate: ${data.direction || "变更 mission 前需确认"}
194
+ `;
195
+ }
196
+
197
+ return `# Session Brief
198
+
199
+ ## Active Stage
200
+
201
+ - Stage: ${data.stage || "TBD"}
202
+
203
+ ## Mission
204
+
205
+ ${data.problem || "TBD"}
206
+
207
+ ## Best Current Path
208
+
209
+ - Approved direction: ${data.direction || "TBD"}
210
+ - Why this is the active path: ${data.why || "This is the approved direction"}
211
+
212
+ ## Main Risk
213
+
214
+ - Risk: ${data.risk || "TBD"}
215
+ - Evidence gap: ${data.question || "TBD"}
216
+
217
+ ## Read First
218
+
219
+ 1. \`.lab/context/mission.md\`
220
+ 2. \`.lab/context/state.md\`
221
+ 3. \`.lab/context/evidence-index.md\`
222
+
223
+ ## Do Not Change Silently
224
+
225
+ - Frozen boundary: ${data.boundary || "TBD"}
226
+ - Approval gate: ${data.direction || "Ask before changing mission"}
227
+ `;
228
+ }
229
+
230
+ function buildContextSnapshot(targetDir) {
231
+ const mission = readFileIfExists(contextFile(targetDir, "mission.md"));
232
+ const state = readFileIfExists(contextFile(targetDir, "state.md"));
233
+ const evidence = readFileIfExists(contextFile(targetDir, "evidence-index.md"));
234
+ const questions = readFileIfExists(contextFile(targetDir, "open-questions.md"));
235
+
236
+ return {
237
+ problem: extractValue(mission, ["One-sentence problem", "一句话问题"]),
238
+ direction: extractValue(mission, ["Approved direction", "已批准方向"]),
239
+ stage: extractValue(state, ["Active stage", "当前阶段", "Stage"]),
240
+ nextArtifact: extractValue(state, ["Next required artifact", "下一项必要输出"]),
241
+ immediateAction: extractValue(state, ["Immediate action", "立即要做的动作"]),
242
+ blocker: extractValue(state, ["Current blocker", "当前阻塞"]),
243
+ humanDecision: extractValue(state, ["Human decision needed", "是否需要人工决策"]),
244
+ threshold: extractValue(mission, ["Success threshold", "成功阈值"]),
245
+ boundary: extractValue(mission, ["Hard constraints", "硬约束"]),
246
+ claim: extractClaim(evidence),
247
+ question: extractOpenQuestion(questions),
248
+ risk: extractValue(questions, ["Why it matters", "为什么重要"]) || extractValue(state, ["Current blocker", "当前阻塞"]),
249
+ };
250
+ }
251
+
252
+ function writeContextFile(targetDir, name, content) {
253
+ const filePath = contextFile(targetDir, name);
254
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
255
+ fs.writeFileSync(filePath, content.trimEnd() + "\n");
256
+ }
257
+
258
+ function refreshContext({ targetDir }) {
259
+ const lang = readWorkflowLanguage(targetDir);
260
+ const snapshot = buildContextSnapshot(targetDir);
261
+ writeContextFile(targetDir, "summary.md", renderSummary(lang, snapshot));
262
+ writeContextFile(targetDir, "next-action.md", renderNextAction(lang, snapshot));
263
+ writeContextFile(targetDir, "session-brief.md", renderSessionBrief(lang, snapshot));
264
+ return { targetDir };
265
+ }
266
+
267
+ function pruneQuestionBlocks(text) {
268
+ const chunks = text.split(/\n(?=\d+\.\s)/);
269
+ const kept = chunks.filter((chunk) => !/Status:\s*(resolved|stale)/i.test(chunk));
270
+ return kept.join("\n").replace(/\n{3,}/g, "\n\n").trimEnd() + "\n";
271
+ }
272
+
273
+ function pruneGenericText(text) {
274
+ return text
275
+ .split("\n")
276
+ .filter((line) => !/^\s*-\s*[^:]+:\s*$/.test(line))
277
+ .filter((line) => !/^\s*-\s*Status:\s*stale\s*$/i.test(line))
278
+ .join("\n")
279
+ .replace(/\n{3,}/g, "\n\n")
280
+ .trimEnd() + "\n";
281
+ }
282
+
283
+ function pruneContext({ targetDir }) {
284
+ const questionPath = contextFile(targetDir, "open-questions.md");
285
+ const nextActionPath = contextFile(targetDir, "next-action.md");
286
+ const summaryPath = contextFile(targetDir, "summary.md");
287
+
288
+ if (fs.existsSync(questionPath)) {
289
+ fs.writeFileSync(questionPath, pruneQuestionBlocks(fs.readFileSync(questionPath, "utf8")));
290
+ }
291
+ if (fs.existsSync(nextActionPath)) {
292
+ fs.writeFileSync(nextActionPath, pruneGenericText(fs.readFileSync(nextActionPath, "utf8")));
293
+ }
294
+ if (fs.existsSync(summaryPath)) {
295
+ fs.writeFileSync(summaryPath, pruneGenericText(fs.readFileSync(summaryPath, "utf8")));
296
+ }
297
+ return { targetDir };
298
+ }
299
+
300
+ function moveChildren(sourceDir, targetDir) {
301
+ if (!fs.existsSync(sourceDir)) {
302
+ return;
303
+ }
304
+ fs.mkdirSync(targetDir, { recursive: true });
305
+ for (const entry of fs.readdirSync(sourceDir)) {
306
+ fs.renameSync(path.join(sourceDir, entry), path.join(targetDir, entry));
307
+ }
308
+ }
309
+
310
+ function archiveContext({ targetDir, now = new Date() }) {
311
+ const stamp = now.toISOString().replace(/[-:]/g, "").replace(/\..+/, "");
312
+ const snapshotRoot = path.join(targetDir, ".lab", "archive", stamp);
313
+ fs.mkdirSync(snapshotRoot, { recursive: true });
314
+
315
+ const contextDir = path.join(snapshotRoot, "context");
316
+ fs.mkdirSync(contextDir, { recursive: true });
317
+ for (const fileName of ["summary.md", "next-action.md", "session-brief.md"]) {
318
+ const sourcePath = contextFile(targetDir, fileName);
319
+ if (fs.existsSync(sourcePath)) {
320
+ fs.copyFileSync(sourcePath, path.join(contextDir, fileName));
321
+ }
322
+ }
323
+
324
+ moveChildren(path.join(targetDir, ".lab", "iterations"), path.join(snapshotRoot, "iterations"));
325
+ moveChildren(
326
+ path.join(targetDir, ".lab", "writing", "iterations"),
327
+ path.join(snapshotRoot, "writing", "iterations")
328
+ );
329
+
330
+ return { archivePath: snapshotRoot };
331
+ }
332
+
333
+ module.exports = {
334
+ archiveContext,
335
+ pruneContext,
336
+ refreshContext,
337
+ };