superlab 0.1.7 → 0.1.8
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 +65 -17
- package/README.zh-CN.md +64 -15
- package/bin/superlab.cjs +232 -1
- package/lib/context.cjs +337 -0
- package/lib/i18n.cjs +673 -41
- package/lib/install.cjs +249 -51
- package/package-assets/claude/commands/lab/framing.md +11 -0
- package/package-assets/claude/commands/lab/idea.md +2 -1
- package/package-assets/claude/commands/lab/iterate.md +2 -1
- package/package-assets/claude/commands/lab/report.md +2 -1
- package/package-assets/claude/commands/lab/review.md +2 -1
- package/package-assets/claude/commands/lab/run.md +2 -1
- package/package-assets/claude/commands/lab/spec.md +2 -1
- package/package-assets/claude/commands/lab/write.md +2 -1
- package/package-assets/codex/prompts/lab-framing.md +9 -0
- package/package-assets/codex/prompts/lab-idea.md +2 -1
- package/package-assets/codex/prompts/lab-iterate.md +2 -1
- package/package-assets/codex/prompts/lab-report.md +2 -1
- package/package-assets/codex/prompts/lab-review.md +2 -1
- package/package-assets/codex/prompts/lab-run.md +2 -1
- package/package-assets/codex/prompts/lab-spec.md +2 -1
- package/package-assets/codex/prompts/lab-write.md +2 -1
- package/package-assets/shared/{templates → lab/.managed/templates}/design.md +3 -3
- package/package-assets/shared/lab/.managed/templates/framing.md +66 -0
- package/package-assets/shared/{templates → lab/.managed/templates}/paper-plan.md +1 -0
- package/package-assets/shared/{templates → lab/.managed/templates}/proposal.md +1 -1
- package/package-assets/shared/{templates → lab/.managed/templates}/spec.md +2 -2
- package/package-assets/shared/{templates → lab/.managed/templates}/tasks.md +2 -2
- package/package-assets/shared/{templates → lab/.managed/templates}/write-iteration.md +1 -0
- package/package-assets/shared/lab/changes/README.md +10 -0
- package/package-assets/shared/lab/config/workflow.json +6 -0
- package/package-assets/shared/lab/context/next-action.md +19 -0
- package/package-assets/shared/lab/context/session-brief.md +30 -0
- package/package-assets/shared/lab/context/summary.md +21 -0
- package/package-assets/shared/lab/context/terminology-lock.md +27 -0
- package/package-assets/shared/lab/system/core.md +41 -0
- package/package-assets/shared/skills/lab/SKILL.md +54 -37
- package/package-assets/shared/skills/lab/references/paper-writing/abstract.md +2 -17
- package/package-assets/shared/skills/lab/references/paper-writing/introduction.md +3 -63
- package/package-assets/shared/skills/lab/references/paper-writing/method.md +4 -34
- package/package-assets/shared/skills/lab/references/workflow.md +4 -4
- package/package-assets/shared/skills/lab/stages/framing.md +70 -0
- package/package-assets/shared/skills/lab/stages/idea.md +5 -5
- package/package-assets/shared/skills/lab/stages/iterate.md +8 -8
- package/package-assets/shared/skills/lab/stages/report.md +7 -6
- package/package-assets/shared/skills/lab/stages/review.md +6 -5
- package/package-assets/shared/skills/lab/stages/run.md +4 -4
- package/package-assets/shared/skills/lab/stages/spec.md +11 -11
- package/package-assets/shared/skills/lab/stages/write.md +14 -10
- package/package.json +1 -1
- package/package-assets/shared/changes/README.md +0 -10
- package/package-assets/shared/config/workflow.json +0 -5
- package/package-assets/shared/examples/minimal-uplift-workflow.md +0 -73
- /package/package-assets/shared/{scripts → lab/.managed/scripts}/eval_report.py +0 -0
- /package/package-assets/shared/{scripts → lab/.managed/scripts}/register_run.py +0 -0
- /package/package-assets/shared/{scripts → lab/.managed/scripts}/summarize_iterations.py +0 -0
- /package/package-assets/shared/{scripts → lab/.managed/scripts}/validate_results.py +0 -0
- /package/package-assets/shared/{templates → lab/.managed/templates}/final-report.md +0 -0
- /package/package-assets/shared/{templates → lab/.managed/templates}/idea.md +0 -0
- /package/package-assets/shared/{templates → lab/.managed/templates}/iteration-report.md +0 -0
- /package/package-assets/shared/{templates → lab/.managed/templates}/paper-section.md +0 -0
- /package/package-assets/shared/{templates → lab/.managed/templates}/paper-section.tex +0 -0
- /package/package-assets/shared/{templates → lab/.managed/templates}/paper.tex +0 -0
- /package/package-assets/shared/{templates → lab/.managed/templates}/review-checklist.md +0 -0
- /package/package-assets/shared/{context → lab/context}/decisions.md +0 -0
- /package/package-assets/shared/{context → lab/context}/evidence-index.md +0 -0
- /package/package-assets/shared/{context → lab/context}/mission.md +0 -0
- /package/package-assets/shared/{context → lab/context}/open-questions.md +0 -0
- /package/package-assets/shared/{context → lab/context}/state.md +0 -0
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ It combines:
|
|
|
8
8
|
|
|
9
9
|
- command adapters for Codex and Claude
|
|
10
10
|
- a shared `/lab` skill with stage-specific rules
|
|
11
|
-
- lab-native change artifacts under `.
|
|
11
|
+
- lab-native change artifacts under `.lab/changes/`
|
|
12
12
|
- bounded Ralph Wiggum style iteration for experiments
|
|
13
13
|
- helper scripts for run registration and evaluation summaries
|
|
14
14
|
|
|
@@ -47,11 +47,14 @@ This writes:
|
|
|
47
47
|
- `.codex/skills/lab/`
|
|
48
48
|
- `.claude/commands/lab/*.md`
|
|
49
49
|
- `.claude/skills/lab/`
|
|
50
|
-
-
|
|
51
|
-
-
|
|
52
|
-
- `.
|
|
53
|
-
- `.
|
|
54
|
-
- `.
|
|
50
|
+
- `AGENTS.md`
|
|
51
|
+
- `CLAUDE.md`
|
|
52
|
+
- `.lab/system/core.md`
|
|
53
|
+
- `.lab/config/workflow.json`
|
|
54
|
+
- `.lab/context/`
|
|
55
|
+
- `.lab/changes/`
|
|
56
|
+
- `.lab/.managed/templates/`
|
|
57
|
+
- `.lab/.managed/scripts/`
|
|
55
58
|
|
|
56
59
|
If you prefer non-interactive use:
|
|
57
60
|
|
|
@@ -90,9 +93,48 @@ Refresh every registered project initialized from this user account:
|
|
|
90
93
|
superlab update --all-projects
|
|
91
94
|
```
|
|
92
95
|
|
|
93
|
-
`superlab init` writes `.
|
|
96
|
+
`superlab init` writes `.lab/.managed/install.json` inside each project and registers the project in the user-level registry so `update --all-projects` knows what to refresh.
|
|
94
97
|
|
|
95
|
-
Legacy projects from older `superlab` versions may already contain `.codex/`, `.claude/`, or `.superlab/` assets without `.
|
|
98
|
+
Legacy projects from older `superlab` versions may already contain `.codex/`, `.claude/`, or `.superlab/` assets without `.lab/.managed/install.json`. `superlab update` now reconstructs that metadata and upgrades the project in place.
|
|
99
|
+
|
|
100
|
+
## Context Tools
|
|
101
|
+
|
|
102
|
+
Refresh the compressed handoff layer from live project context:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
superlab context refresh
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Prune resolved or stale active-context entries:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
superlab context prune
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Archive cold iteration and writing history:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
superlab context archive
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Print the minimal handoff bundle for a new AI session:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
superlab handoff
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Check that the managed `.lab` layout is healthy:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
superlab doctor
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
`doctor` validates:
|
|
133
|
+
|
|
134
|
+
- required `.lab` files
|
|
135
|
+
- `workflow.json` schema
|
|
136
|
+
- `deliverables_root` placement
|
|
137
|
+
- LaTeX-first paper output layout under `<deliverables_root>/paper/`
|
|
96
138
|
|
|
97
139
|
## Version
|
|
98
140
|
|
|
@@ -127,11 +169,12 @@ superlab init --lang zh
|
|
|
127
169
|
superlab init --lang en
|
|
128
170
|
```
|
|
129
171
|
|
|
130
|
-
This installer also writes `.
|
|
172
|
+
This installer also writes `.lab/config/workflow.json`, which is the global contract for:
|
|
131
173
|
|
|
132
174
|
- `workflow_language`
|
|
133
175
|
- `paper_language`
|
|
134
176
|
- `paper_format`
|
|
177
|
+
- `deliverables_root`
|
|
135
178
|
|
|
136
179
|
Stages should follow that file rather than guess language locally.
|
|
137
180
|
|
|
@@ -146,12 +189,14 @@ Stages should follow that file rather than guess language locally.
|
|
|
146
189
|
## Command Set
|
|
147
190
|
|
|
148
191
|
- `/lab:idea` researches an idea, critiques it, and writes the initial research framing.
|
|
149
|
-
- `/lab:
|
|
192
|
+
- `/lab:framing` locks paper-facing method names, module names, titles, and contribution wording before drafting.
|
|
193
|
+
- `/lab:spec` converts the approved idea into one `.lab/changes/<change-id>/` directory.
|
|
150
194
|
- `/lab:run` executes a small-scale validation run and establishes the evaluation pipeline.
|
|
151
195
|
- `/lab:iterate` runs bounded experiment loops with fixed mission, explicit thresholds, and per-round reports.
|
|
152
196
|
- `/lab:review` audits documents and results in reviewer mode.
|
|
153
197
|
- `/lab:report` produces the final report from accumulated artifacts.
|
|
154
198
|
- `/lab:write` converts stable report artifacts into paper sections through small writing rounds.
|
|
199
|
+
It requires an approved `/lab:framing` artifact before drafting.
|
|
155
200
|
It reads vendored section references derived from `Research-Paper-Writing-Skills`.
|
|
156
201
|
|
|
157
202
|
See the source command docs in [commands/codex/lab.md](/Users/zhouhao119/coding/write/commands/codex/lab.md) and [commands/claude/lab.md](/Users/zhouhao119/coding/write/commands/claude/lab.md). The npm package installs real command assets from `package-assets/`.
|
|
@@ -165,7 +210,7 @@ See the source command docs in [commands/codex/lab.md](/Users/zhouhao119/coding/
|
|
|
165
210
|
- `scripts/` contains reproducibility helpers.
|
|
166
211
|
- `tests/` contains minimal regression coverage for the helper scripts.
|
|
167
212
|
- `examples/` contains a minimal end-to-end usage example.
|
|
168
|
-
- `docs/` contains the design spec and
|
|
213
|
+
- `docs/` contains the design spec and release notes.
|
|
169
214
|
|
|
170
215
|
## Typical Flow
|
|
171
216
|
|
|
@@ -175,17 +220,20 @@ See the source command docs in [commands/codex/lab.md](/Users/zhouhao119/coding/
|
|
|
175
220
|
4. Run `/lab:iterate` to improve against fixed targets using bounded iterations.
|
|
176
221
|
5. Run `/lab:review` whenever you need reviewer-grade critique.
|
|
177
222
|
6. Run `/lab:report` to synthesize the final report.
|
|
178
|
-
7. Run `/lab:
|
|
223
|
+
7. Run `/lab:framing` to lock naming, title, and contribution wording.
|
|
224
|
+
8. Run `/lab:write` to draft paper sections from stable report evidence.
|
|
179
225
|
|
|
180
|
-
`/lab:write` writes final manuscript output
|
|
226
|
+
`/lab:write` writes final manuscript output under the configured `deliverables_root` (default: `docs/research`):
|
|
181
227
|
|
|
182
|
-
- `docs/
|
|
183
|
-
- `docs/paper/
|
|
228
|
+
- `docs/research/report.md`
|
|
229
|
+
- `docs/research/paper/main.tex`
|
|
230
|
+
- `docs/research/paper/sections/*.tex`
|
|
184
231
|
|
|
185
232
|
Internal writing-control artifacts stay under:
|
|
186
233
|
|
|
187
|
-
- `.
|
|
188
|
-
- `.
|
|
234
|
+
- `.lab/writing/framing.md`
|
|
235
|
+
- `.lab/writing/plan.md`
|
|
236
|
+
- `.lab/writing/iterations/*.md`
|
|
189
237
|
|
|
190
238
|
## Helper Scripts
|
|
191
239
|
|
package/README.zh-CN.md
CHANGED
|
@@ -45,11 +45,14 @@ npx github:zhouhaoUCAS/superlab init
|
|
|
45
45
|
- `.codex/skills/lab/`
|
|
46
46
|
- `.claude/commands/lab/*.md`
|
|
47
47
|
- `.claude/skills/lab/`
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
- `.
|
|
51
|
-
- `.
|
|
52
|
-
- `.
|
|
48
|
+
- `AGENTS.md`
|
|
49
|
+
- `CLAUDE.md`
|
|
50
|
+
- `.lab/system/core.md`
|
|
51
|
+
- `.lab/config/workflow.json`
|
|
52
|
+
- `.lab/context/`
|
|
53
|
+
- `.lab/changes/`
|
|
54
|
+
- `.lab/.managed/templates/`
|
|
55
|
+
- `.lab/.managed/scripts/`
|
|
53
56
|
|
|
54
57
|
如果你更喜欢非交互方式,也可以直接传参:
|
|
55
58
|
|
|
@@ -88,9 +91,48 @@ superlab update --target /path/to/project
|
|
|
88
91
|
superlab update --all-projects
|
|
89
92
|
```
|
|
90
93
|
|
|
91
|
-
`superlab init` 会在项目内写入 `.
|
|
94
|
+
`superlab init` 会在项目内写入 `.lab/.managed/install.json`,并在用户级 registry 里登记项目路径,所以 `update --all-projects` 才知道要刷新哪些项目。
|
|
92
95
|
|
|
93
|
-
较老版本的 `superlab` 项目可能已经有 `.codex/`、`.claude/` 或 `.superlab/` 资产,但还没有 `.
|
|
96
|
+
较老版本的 `superlab` 项目可能已经有 `.codex/`、`.claude/` 或 `.superlab/` 资产,但还没有 `.lab/.managed/install.json`。现在 `superlab update` 会自动重建这份 metadata,然后原地升级该项目。
|
|
97
|
+
|
|
98
|
+
## 上下文工具
|
|
99
|
+
|
|
100
|
+
根据当前项目上下文重建压缩后的 handoff 层:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
superlab context refresh
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
清理已解决或已过期的 active-context 内容:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
superlab context prune
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
把冷历史迭代和写作轮次归档出去:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
superlab context archive
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
输出新 AI 会话最小接手包:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
superlab handoff
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
检查当前 `.lab` 受管布局是否健康:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
superlab doctor
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
`doctor` 目前会校验:
|
|
131
|
+
|
|
132
|
+
- 必需的 `.lab` 文件是否存在
|
|
133
|
+
- `workflow.json` 结构是否合法
|
|
134
|
+
- `deliverables_root` 是否放在合理位置
|
|
135
|
+
- `<deliverables_root>/paper/` 下是否仍然满足 LaTeX-first 输出约束
|
|
94
136
|
|
|
95
137
|
## 版本查询
|
|
96
138
|
|
|
@@ -125,11 +167,12 @@ superlab init --lang zh
|
|
|
125
167
|
superlab init --lang en
|
|
126
168
|
```
|
|
127
169
|
|
|
128
|
-
安装器还会写入 `.
|
|
170
|
+
安装器还会写入 `.lab/config/workflow.json`。这个文件是全局约束,至少控制:
|
|
129
171
|
|
|
130
172
|
- `workflow_language`
|
|
131
173
|
- `paper_language`
|
|
132
174
|
- `paper_format`
|
|
175
|
+
- `deliverables_root`
|
|
133
176
|
|
|
134
177
|
后续 stage 应该按这个配置决定语言和论文格式,而不是各模板自己猜。
|
|
135
178
|
|
|
@@ -144,12 +187,14 @@ superlab init --lang en
|
|
|
144
187
|
## 命令集合
|
|
145
188
|
|
|
146
189
|
- `/lab:idea` 调研 idea、文献、数据集、指标和 baseline,并输出初始方案。
|
|
147
|
-
- `/lab:
|
|
190
|
+
- `/lab:framing` 在正式写作前收紧方法名、模块名、论文题目和 contribution wording。
|
|
191
|
+
- `/lab:spec` 把批准后的方案转换成一个统一的 `.lab/changes/<change-id>/` 目录。
|
|
148
192
|
- `/lab:run` 执行最小可运行实验,并建立首版评估链路。
|
|
149
193
|
- `/lab:iterate` 以固定 mission、固定阈值和最大轮次做有边界的实验迭代。
|
|
150
194
|
- `/lab:review` 以审稿人模式检查方法、对照、公平性、泄漏和统计问题。
|
|
151
195
|
- `/lab:report` 根据累积工件生成最终实验报告。
|
|
152
196
|
- `/lab:write` 把稳定的 report 工件转成论文 section,并按小步方式逐轮修改。
|
|
197
|
+
它要求先有一个经批准的 `/lab:framing` 工件。
|
|
153
198
|
它会读取随 `lab` 一起安装的 vendored 章节参考,这些参考来源于 `Research-Paper-Writing-Skills`。
|
|
154
199
|
|
|
155
200
|
## 使用流程
|
|
@@ -161,17 +206,20 @@ superlab init --lang en
|
|
|
161
206
|
5. 用 `/lab:iterate` 进行多轮迭代。
|
|
162
207
|
6. 在关键节点运行 `/lab:review`。
|
|
163
208
|
7. 最后用 `/lab:report` 产出总报告。
|
|
164
|
-
8. 用 `/lab:
|
|
209
|
+
8. 用 `/lab:framing` 收紧题目、命名和 contribution wording。
|
|
210
|
+
9. 用 `/lab:write` 把稳定结果写成论文各 section。
|
|
165
211
|
|
|
166
|
-
`/lab:write`
|
|
212
|
+
`/lab:write` 会把最终可交付物写到 `deliverables_root` 指定的目录,默认是 `docs/research`:
|
|
167
213
|
|
|
168
|
-
- `docs/
|
|
169
|
-
- `docs/paper/
|
|
214
|
+
- `docs/research/report.md`
|
|
215
|
+
- `docs/research/paper/main.tex`
|
|
216
|
+
- `docs/research/paper/sections/*.tex`
|
|
170
217
|
|
|
171
218
|
内部写作控制工件放在:
|
|
172
219
|
|
|
173
|
-
- `.
|
|
174
|
-
- `.
|
|
220
|
+
- `.lab/writing/framing.md`
|
|
221
|
+
- `.lab/writing/plan.md`
|
|
222
|
+
- `.lab/writing/iterations/*.md`
|
|
175
223
|
|
|
176
224
|
## 仓库内容
|
|
177
225
|
|
|
@@ -182,6 +230,7 @@ superlab init --lang en
|
|
|
182
230
|
- `scripts/` 是运行登记、评估汇总和结果校验脚本。
|
|
183
231
|
- `tests/` 是脚本与安装器测试。
|
|
184
232
|
- `examples/` 是最小端到端示例。
|
|
233
|
+
- `docs/` 存放设计文档和发布说明。
|
|
185
234
|
- `docs/release.md` 是发布到 npm 的操作说明。
|
|
186
235
|
- `.github/workflows/ci.yml` 会在 `main` 和 PR 上自动执行 `npm run release:check`。
|
|
187
236
|
- `.github/workflows/publish.yml` 支持在配置好 `NPM_TOKEN` 后手动从 GitHub Actions 发布到 npm。
|
package/bin/superlab.cjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
const fs = require("node:fs");
|
|
3
4
|
const path = require("node:path");
|
|
4
5
|
const {
|
|
5
6
|
PACKAGE_VERSION,
|
|
@@ -9,6 +10,11 @@ const {
|
|
|
9
10
|
updateAllProjects,
|
|
10
11
|
updateSuperlabProject,
|
|
11
12
|
} = require("../lib/install.cjs");
|
|
13
|
+
const {
|
|
14
|
+
archiveContext,
|
|
15
|
+
pruneContext,
|
|
16
|
+
refreshContext,
|
|
17
|
+
} = require("../lib/context.cjs");
|
|
12
18
|
const { promptSelect } = require("../lib/init_tui.cjs");
|
|
13
19
|
|
|
14
20
|
function restartReminder(lang) {
|
|
@@ -27,12 +33,20 @@ Usage:
|
|
|
27
33
|
superlab update [--target <dir>]
|
|
28
34
|
superlab update --all-projects
|
|
29
35
|
superlab version [--target <dir>] [--global|--project]
|
|
36
|
+
superlab handoff [--target <dir>]
|
|
37
|
+
superlab doctor [--target <dir>]
|
|
38
|
+
superlab context refresh [--target <dir>]
|
|
39
|
+
superlab context prune [--target <dir>]
|
|
40
|
+
superlab context archive [--target <dir>]
|
|
30
41
|
|
|
31
42
|
Commands:
|
|
32
43
|
init Initialize /lab commands, skills, templates, and scripts in a target
|
|
33
44
|
install Backward-compatible alias for init
|
|
34
45
|
update Refresh an initialized project or all registered projects
|
|
35
46
|
version Show installed CLI version and project asset version
|
|
47
|
+
handoff Print the minimal context handoff bundle for a project
|
|
48
|
+
doctor Check project health for the managed .lab layout
|
|
49
|
+
context Maintain project context summaries and archives
|
|
36
50
|
help Show this help message
|
|
37
51
|
`);
|
|
38
52
|
}
|
|
@@ -128,6 +142,35 @@ function parseVersionArgs(argv) {
|
|
|
128
142
|
return options;
|
|
129
143
|
}
|
|
130
144
|
|
|
145
|
+
function parseTargetOnlyArgs(argv) {
|
|
146
|
+
const options = {
|
|
147
|
+
targetDir: process.cwd(),
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
151
|
+
const value = argv[index];
|
|
152
|
+
if (value === "--target") {
|
|
153
|
+
options.targetDir = path.resolve(argv[index + 1]);
|
|
154
|
+
index += 1;
|
|
155
|
+
} else {
|
|
156
|
+
throw new Error(`Unknown option: ${value}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return options;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function parseContextArgs(argv) {
|
|
164
|
+
const [action, ...rest] = argv;
|
|
165
|
+
if (!["refresh", "prune", "archive"].includes(action || "")) {
|
|
166
|
+
throw new Error(`Unknown context action: ${action || "(missing)"}`);
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
action,
|
|
170
|
+
...parseTargetOnlyArgs(rest),
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
131
174
|
function printVersion(options) {
|
|
132
175
|
const lines = [];
|
|
133
176
|
if (!options.projectOnly) {
|
|
@@ -150,6 +193,167 @@ function printVersion(options) {
|
|
|
150
193
|
console.log(lines.join("\n"));
|
|
151
194
|
}
|
|
152
195
|
|
|
196
|
+
function printHandoff(options) {
|
|
197
|
+
const handoffFiles = [
|
|
198
|
+
".lab/context/session-brief.md",
|
|
199
|
+
".lab/context/mission.md",
|
|
200
|
+
".lab/context/state.md",
|
|
201
|
+
".lab/context/evidence-index.md",
|
|
202
|
+
];
|
|
203
|
+
const sessionBriefPath = path.join(options.targetDir, handoffFiles[0]);
|
|
204
|
+
if (!fs.existsSync(sessionBriefPath)) {
|
|
205
|
+
throw new Error(`No handoff brief found in ${options.targetDir}. Run 'superlab init' first.`);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const sessionBrief = fs.readFileSync(sessionBriefPath, "utf8").trimEnd();
|
|
209
|
+
console.log(`target: ${options.targetDir}`);
|
|
210
|
+
console.log("read-order:");
|
|
211
|
+
for (const filePath of handoffFiles) {
|
|
212
|
+
console.log(`- ${filePath}`);
|
|
213
|
+
}
|
|
214
|
+
console.log("");
|
|
215
|
+
console.log(sessionBrief);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function listFilesRecursive(dir) {
|
|
219
|
+
if (!fs.existsSync(dir)) {
|
|
220
|
+
return [];
|
|
221
|
+
}
|
|
222
|
+
const files = [];
|
|
223
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
224
|
+
const fullPath = path.join(dir, entry.name);
|
|
225
|
+
if (entry.isDirectory()) {
|
|
226
|
+
files.push(...listFilesRecursive(fullPath));
|
|
227
|
+
} else {
|
|
228
|
+
files.push(fullPath);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return files;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function readWorkflowConfig(targetDir) {
|
|
235
|
+
const configPath = path.join(targetDir, ".lab", "config", "workflow.json");
|
|
236
|
+
try {
|
|
237
|
+
return {
|
|
238
|
+
config: JSON.parse(fs.readFileSync(configPath, "utf8")),
|
|
239
|
+
issues: [],
|
|
240
|
+
};
|
|
241
|
+
} catch (error) {
|
|
242
|
+
return {
|
|
243
|
+
config: null,
|
|
244
|
+
issues: [`invalid workflow.json: ${error.message}`],
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function validateWorkflowConfig(config) {
|
|
250
|
+
const issues = [];
|
|
251
|
+
if (!config || typeof config !== "object") {
|
|
252
|
+
return issues;
|
|
253
|
+
}
|
|
254
|
+
if (!["en", "zh"].includes(config.workflow_language)) {
|
|
255
|
+
issues.push("invalid workflow_language");
|
|
256
|
+
}
|
|
257
|
+
if (!["en", "zh"].includes(config.paper_language)) {
|
|
258
|
+
issues.push("invalid paper_language");
|
|
259
|
+
}
|
|
260
|
+
if (config.paper_format !== "latex") {
|
|
261
|
+
issues.push("unsupported paper_format");
|
|
262
|
+
}
|
|
263
|
+
if (typeof config.deliverables_root !== "string" || config.deliverables_root.trim() === "") {
|
|
264
|
+
issues.push("invalid deliverables_root");
|
|
265
|
+
} else {
|
|
266
|
+
const normalized = config.deliverables_root.replace(/\\/g, "/");
|
|
267
|
+
if (normalized === ".lab" || normalized.startsWith(".lab/")) {
|
|
268
|
+
issues.push("deliverables_root must not point inside .lab");
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return issues;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function validateDeliverables(targetDir, config) {
|
|
275
|
+
const issues = [];
|
|
276
|
+
if (!config || typeof config.deliverables_root !== "string" || config.deliverables_root.trim() === "") {
|
|
277
|
+
return issues;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const deliverablesRoot = path.join(targetDir, config.deliverables_root);
|
|
281
|
+
const paperDir = path.join(deliverablesRoot, "paper");
|
|
282
|
+
const mainTexPath = path.join(paperDir, "main.tex");
|
|
283
|
+
const mainMdPath = path.join(paperDir, "main.md");
|
|
284
|
+
const sectionsDir = path.join(paperDir, "sections");
|
|
285
|
+
|
|
286
|
+
if (fs.existsSync(mainMdPath)) {
|
|
287
|
+
issues.push("paper main manuscript must be main.tex");
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (fs.existsSync(paperDir) && !fs.existsSync(mainTexPath)) {
|
|
291
|
+
issues.push("paper output is missing paper/main.tex");
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (fs.existsSync(sectionsDir)) {
|
|
295
|
+
const nonTexFiles = listFilesRecursive(sectionsDir)
|
|
296
|
+
.filter((filePath) => path.extname(filePath) !== ".tex")
|
|
297
|
+
.map((filePath) => path.relative(targetDir, filePath));
|
|
298
|
+
if (nonTexFiles.length > 0) {
|
|
299
|
+
issues.push(`paper sections must be .tex files: ${nonTexFiles.join(", ")}`);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return issues;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function printDoctor(options) {
|
|
307
|
+
const projectInfo = getProjectVersionInfo({ targetDir: options.targetDir });
|
|
308
|
+
const requiredPaths = [
|
|
309
|
+
".lab/system/core.md",
|
|
310
|
+
".lab/config/workflow.json",
|
|
311
|
+
".lab/context/mission.md",
|
|
312
|
+
".lab/context/state.md",
|
|
313
|
+
".lab/context/decisions.md",
|
|
314
|
+
".lab/context/evidence-index.md",
|
|
315
|
+
".lab/context/open-questions.md",
|
|
316
|
+
".lab/context/terminology-lock.md",
|
|
317
|
+
".lab/context/summary.md",
|
|
318
|
+
".lab/context/next-action.md",
|
|
319
|
+
".lab/context/session-brief.md",
|
|
320
|
+
".lab/.managed/install.json",
|
|
321
|
+
];
|
|
322
|
+
const missing = requiredPaths.filter((relativePath) => !fs.existsSync(path.join(options.targetDir, relativePath)));
|
|
323
|
+
const { config, issues: configReadIssues } = readWorkflowConfig(options.targetDir);
|
|
324
|
+
const configIssues = configReadIssues.concat(validateWorkflowConfig(config));
|
|
325
|
+
const deliverableIssues = validateDeliverables(options.targetDir, config);
|
|
326
|
+
|
|
327
|
+
if (projectInfo.status === "missing") {
|
|
328
|
+
console.log("status: missing");
|
|
329
|
+
console.log(`target: ${options.targetDir}`);
|
|
330
|
+
console.log("project: not initialized");
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if (missing.length > 0 || configIssues.length > 0 || deliverableIssues.length > 0) {
|
|
335
|
+
console.log("status: degraded");
|
|
336
|
+
console.log(`target: ${options.targetDir}`);
|
|
337
|
+
console.log(`project: ${projectInfo.package_version}`);
|
|
338
|
+
console.log(`platform: ${projectInfo.platform}`);
|
|
339
|
+
console.log(`language: ${projectInfo.lang}`);
|
|
340
|
+
console.log(`missing: ${missing.length > 0 ? missing.join(", ") : "none"}`);
|
|
341
|
+
console.log(`config: ${configIssues.length > 0 ? configIssues.join(" | ") : "none"}`);
|
|
342
|
+
console.log(`outputs: ${deliverableIssues.length > 0 ? deliverableIssues.join(" | ") : "none"}`);
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
console.log("status: ok");
|
|
347
|
+
console.log(`target: ${options.targetDir}`);
|
|
348
|
+
console.log(`cli: ${PACKAGE_VERSION}`);
|
|
349
|
+
console.log(`project: ${projectInfo.package_version}`);
|
|
350
|
+
console.log(`platform: ${projectInfo.platform}`);
|
|
351
|
+
console.log(`language: ${projectInfo.lang}`);
|
|
352
|
+
console.log("missing: none");
|
|
353
|
+
console.log("config: none");
|
|
354
|
+
console.log("outputs: none");
|
|
355
|
+
}
|
|
356
|
+
|
|
153
357
|
function shouldUseInteractiveInit(options) {
|
|
154
358
|
if (options.lang && options.platform) {
|
|
155
359
|
return false;
|
|
@@ -201,7 +405,7 @@ async function main() {
|
|
|
201
405
|
return;
|
|
202
406
|
}
|
|
203
407
|
|
|
204
|
-
if (!["init", "install", "update", "version"].includes(command)) {
|
|
408
|
+
if (!["init", "install", "update", "version", "handoff", "doctor", "context"].includes(command)) {
|
|
205
409
|
throw new Error(`Unknown command: ${command}`);
|
|
206
410
|
}
|
|
207
411
|
|
|
@@ -210,6 +414,33 @@ async function main() {
|
|
|
210
414
|
return;
|
|
211
415
|
}
|
|
212
416
|
|
|
417
|
+
if (command === "handoff") {
|
|
418
|
+
printHandoff(parseTargetOnlyArgs(rest));
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
if (command === "doctor") {
|
|
423
|
+
printDoctor(parseTargetOnlyArgs(rest));
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
if (command === "context") {
|
|
428
|
+
const options = parseContextArgs(rest);
|
|
429
|
+
if (options.action === "refresh") {
|
|
430
|
+
refreshContext({ targetDir: options.targetDir });
|
|
431
|
+
console.log(`context refreshed in ${options.targetDir}`);
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
if (options.action === "prune") {
|
|
435
|
+
pruneContext({ targetDir: options.targetDir });
|
|
436
|
+
console.log(`context pruned in ${options.targetDir}`);
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
const result = archiveContext({ targetDir: options.targetDir });
|
|
440
|
+
console.log(`context archived in ${result.archivePath}`);
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
|
|
213
444
|
if (command === "update") {
|
|
214
445
|
const options = parseUpdateArgs(rest);
|
|
215
446
|
if (options.allProjects) {
|