superlab 0.1.6 → 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.
Files changed (69) hide show
  1. package/README.md +90 -16
  2. package/README.zh-CN.md +89 -14
  3. package/bin/superlab.cjs +242 -1
  4. package/lib/context.cjs +337 -0
  5. package/lib/i18n.cjs +673 -41
  6. package/lib/install.cjs +249 -51
  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/codex/prompts/lab-framing.md +9 -0
  16. package/package-assets/codex/prompts/lab-idea.md +2 -1
  17. package/package-assets/codex/prompts/lab-iterate.md +2 -1
  18. package/package-assets/codex/prompts/lab-report.md +2 -1
  19. package/package-assets/codex/prompts/lab-review.md +2 -1
  20. package/package-assets/codex/prompts/lab-run.md +2 -1
  21. package/package-assets/codex/prompts/lab-spec.md +2 -1
  22. package/package-assets/codex/prompts/lab-write.md +2 -1
  23. package/package-assets/shared/{templates → lab/.managed/templates}/design.md +3 -3
  24. package/package-assets/shared/lab/.managed/templates/framing.md +66 -0
  25. package/package-assets/shared/{templates → lab/.managed/templates}/paper-plan.md +1 -0
  26. package/package-assets/shared/{templates → lab/.managed/templates}/proposal.md +1 -1
  27. package/package-assets/shared/{templates → lab/.managed/templates}/spec.md +2 -2
  28. package/package-assets/shared/{templates → lab/.managed/templates}/tasks.md +2 -2
  29. package/package-assets/shared/{templates → lab/.managed/templates}/write-iteration.md +1 -0
  30. package/package-assets/shared/lab/changes/README.md +10 -0
  31. package/package-assets/shared/lab/config/workflow.json +6 -0
  32. package/package-assets/shared/lab/context/next-action.md +19 -0
  33. package/package-assets/shared/lab/context/session-brief.md +30 -0
  34. package/package-assets/shared/lab/context/summary.md +21 -0
  35. package/package-assets/shared/lab/context/terminology-lock.md +27 -0
  36. package/package-assets/shared/lab/system/core.md +41 -0
  37. package/package-assets/shared/skills/lab/SKILL.md +54 -37
  38. package/package-assets/shared/skills/lab/references/paper-writing/abstract.md +2 -17
  39. package/package-assets/shared/skills/lab/references/paper-writing/introduction.md +3 -63
  40. package/package-assets/shared/skills/lab/references/paper-writing/method.md +4 -34
  41. package/package-assets/shared/skills/lab/references/workflow.md +4 -4
  42. package/package-assets/shared/skills/lab/stages/framing.md +70 -0
  43. package/package-assets/shared/skills/lab/stages/idea.md +5 -5
  44. package/package-assets/shared/skills/lab/stages/iterate.md +8 -8
  45. package/package-assets/shared/skills/lab/stages/report.md +7 -6
  46. package/package-assets/shared/skills/lab/stages/review.md +6 -5
  47. package/package-assets/shared/skills/lab/stages/run.md +4 -4
  48. package/package-assets/shared/skills/lab/stages/spec.md +11 -11
  49. package/package-assets/shared/skills/lab/stages/write.md +14 -10
  50. package/package.json +1 -1
  51. package/package-assets/shared/changes/README.md +0 -10
  52. package/package-assets/shared/config/workflow.json +0 -5
  53. package/package-assets/shared/examples/minimal-uplift-workflow.md +0 -73
  54. /package/package-assets/shared/{scripts → lab/.managed/scripts}/eval_report.py +0 -0
  55. /package/package-assets/shared/{scripts → lab/.managed/scripts}/register_run.py +0 -0
  56. /package/package-assets/shared/{scripts → lab/.managed/scripts}/summarize_iterations.py +0 -0
  57. /package/package-assets/shared/{scripts → lab/.managed/scripts}/validate_results.py +0 -0
  58. /package/package-assets/shared/{templates → lab/.managed/templates}/final-report.md +0 -0
  59. /package/package-assets/shared/{templates → lab/.managed/templates}/idea.md +0 -0
  60. /package/package-assets/shared/{templates → lab/.managed/templates}/iteration-report.md +0 -0
  61. /package/package-assets/shared/{templates → lab/.managed/templates}/paper-section.md +0 -0
  62. /package/package-assets/shared/{templates → lab/.managed/templates}/paper-section.tex +0 -0
  63. /package/package-assets/shared/{templates → lab/.managed/templates}/paper.tex +0 -0
  64. /package/package-assets/shared/{templates → lab/.managed/templates}/review-checklist.md +0 -0
  65. /package/package-assets/shared/{context → lab/context}/decisions.md +0 -0
  66. /package/package-assets/shared/{context → lab/context}/evidence-index.md +0 -0
  67. /package/package-assets/shared/{context → lab/context}/mission.md +0 -0
  68. /package/package-assets/shared/{context → lab/context}/open-questions.md +0 -0
  69. /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 `.superlab/changes/`
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
 
@@ -22,6 +22,8 @@ cd your-project
22
22
  superlab init
23
23
  ```
24
24
 
25
+ After `init` or `update`, start a new Codex or Claude session. If the new `/lab:*` commands still do not show up, restart the app.
26
+
25
27
  If the package has not been published yet, install from GitHub instead:
26
28
 
27
29
  ```bash
@@ -45,11 +47,14 @@ This writes:
45
47
  - `.codex/skills/lab/`
46
48
  - `.claude/commands/lab/*.md`
47
49
  - `.claude/skills/lab/`
48
- - `.superlab/config/workflow.json`
49
- - `.superlab/changes/`
50
- - `.superlab/templates/`
51
- - `.superlab/scripts/`
52
- - `.superlab/examples/`
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/`
53
58
 
54
59
  If you prefer non-interactive use:
55
60
 
@@ -88,7 +93,70 @@ Refresh every registered project initialized from this user account:
88
93
  superlab update --all-projects
89
94
  ```
90
95
 
91
- `superlab init` writes `.superlab/install.json` inside each project and registers the project in the user-level registry so `update --all-projects` knows what to refresh.
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.
97
+
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/`
138
+
139
+ ## Version
140
+
141
+ Show the CLI version and the current project asset version:
142
+
143
+ ```bash
144
+ superlab version
145
+ ```
146
+
147
+ Show only the current project asset version:
148
+
149
+ ```bash
150
+ superlab version --project
151
+ ```
152
+
153
+ Show a specific project:
154
+
155
+ ```bash
156
+ superlab version --target /path/to/project
157
+ ```
158
+
159
+ If a project still uses an older pre-metadata installation, `superlab version` reports `project: legacy` until you run `superlab update`.
92
160
 
93
161
  ## Language
94
162
 
@@ -101,11 +169,12 @@ superlab init --lang zh
101
169
  superlab init --lang en
102
170
  ```
103
171
 
104
- This installer also writes `.superlab/config/workflow.json`, which is the global contract for:
172
+ This installer also writes `.lab/config/workflow.json`, which is the global contract for:
105
173
 
106
174
  - `workflow_language`
107
175
  - `paper_language`
108
176
  - `paper_format`
177
+ - `deliverables_root`
109
178
 
110
179
  Stages should follow that file rather than guess language locally.
111
180
 
@@ -120,12 +189,14 @@ Stages should follow that file rather than guess language locally.
120
189
  ## Command Set
121
190
 
122
191
  - `/lab:idea` researches an idea, critiques it, and writes the initial research framing.
123
- - `/lab:spec` converts the approved idea into one `.superlab/changes/<change-id>/` directory.
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.
124
194
  - `/lab:run` executes a small-scale validation run and establishes the evaluation pipeline.
125
195
  - `/lab:iterate` runs bounded experiment loops with fixed mission, explicit thresholds, and per-round reports.
126
196
  - `/lab:review` audits documents and results in reviewer mode.
127
197
  - `/lab:report` produces the final report from accumulated artifacts.
128
198
  - `/lab:write` converts stable report artifacts into paper sections through small writing rounds.
199
+ It requires an approved `/lab:framing` artifact before drafting.
129
200
  It reads vendored section references derived from `Research-Paper-Writing-Skills`.
130
201
 
131
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/`.
@@ -139,7 +210,7 @@ See the source command docs in [commands/codex/lab.md](/Users/zhouhao119/coding/
139
210
  - `scripts/` contains reproducibility helpers.
140
211
  - `tests/` contains minimal regression coverage for the helper scripts.
141
212
  - `examples/` contains a minimal end-to-end usage example.
142
- - `docs/` contains the design spec and generated reports.
213
+ - `docs/` contains the design spec and release notes.
143
214
 
144
215
  ## Typical Flow
145
216
 
@@ -149,17 +220,20 @@ See the source command docs in [commands/codex/lab.md](/Users/zhouhao119/coding/
149
220
  4. Run `/lab:iterate` to improve against fixed targets using bounded iterations.
150
221
  5. Run `/lab:review` whenever you need reviewer-grade critique.
151
222
  6. Run `/lab:report` to synthesize the final report.
152
- 7. Run `/lab:write` to draft paper sections from stable report evidence.
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.
153
225
 
154
- `/lab:write` writes final manuscript output to:
226
+ `/lab:write` writes final manuscript output under the configured `deliverables_root` (default: `docs/research`):
155
227
 
156
- - `docs/paper/paper.tex`
157
- - `docs/paper/sections/*.tex`
228
+ - `docs/research/report.md`
229
+ - `docs/research/paper/main.tex`
230
+ - `docs/research/paper/sections/*.tex`
158
231
 
159
232
  Internal writing-control artifacts stay under:
160
233
 
161
- - `.superlab/write/plan.md`
162
- - `.superlab/write/iterations/*.md`
234
+ - `.lab/writing/framing.md`
235
+ - `.lab/writing/plan.md`
236
+ - `.lab/writing/iterations/*.md`
163
237
 
164
238
  ## Helper Scripts
165
239
 
package/README.zh-CN.md CHANGED
@@ -20,6 +20,8 @@ cd your-project
20
20
  superlab init
21
21
  ```
22
22
 
23
+ 执行完 `init` 或 `update` 后,请新开一个 Codex 或 Claude 会话;如果新的 `/lab:*` 命令仍未生效,再重启应用。
24
+
23
25
  如果 npm 还没发布,也可以直接从 GitHub 安装:
24
26
 
25
27
  ```bash
@@ -43,11 +45,14 @@ npx github:zhouhaoUCAS/superlab init
43
45
  - `.codex/skills/lab/`
44
46
  - `.claude/commands/lab/*.md`
45
47
  - `.claude/skills/lab/`
46
- - `.superlab/config/workflow.json`
47
- - `.superlab/changes/`
48
- - `.superlab/templates/`
49
- - `.superlab/scripts/`
50
- - `.superlab/examples/`
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/`
51
56
 
52
57
  如果你更喜欢非交互方式,也可以直接传参:
53
58
 
@@ -86,7 +91,70 @@ superlab update --target /path/to/project
86
91
  superlab update --all-projects
87
92
  ```
88
93
 
89
- `superlab init` 会在项目内写入 `.superlab/install.json`,并在用户级 registry 里登记项目路径,所以 `update --all-projects` 才知道要刷新哪些项目。
94
+ `superlab init` 会在项目内写入 `.lab/.managed/install.json`,并在用户级 registry 里登记项目路径,所以 `update --all-projects` 才知道要刷新哪些项目。
95
+
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 输出约束
136
+
137
+ ## 版本查询
138
+
139
+ 查看当前 CLI 版本和当前目录项目的资产版本:
140
+
141
+ ```bash
142
+ superlab version
143
+ ```
144
+
145
+ 只看当前项目资产版本:
146
+
147
+ ```bash
148
+ superlab version --project
149
+ ```
150
+
151
+ 查看指定项目:
152
+
153
+ ```bash
154
+ superlab version --target /path/to/project
155
+ ```
156
+
157
+ 如果项目还是旧的 pre-metadata 安装,`superlab version` 会显示 `project: legacy`;执行一次 `superlab update` 后就会切换到正式版本号。
90
158
 
91
159
  ## 语言
92
160
 
@@ -99,11 +167,12 @@ superlab init --lang zh
99
167
  superlab init --lang en
100
168
  ```
101
169
 
102
- 安装器还会写入 `.superlab/config/workflow.json`。这个文件是全局约束,至少控制:
170
+ 安装器还会写入 `.lab/config/workflow.json`。这个文件是全局约束,至少控制:
103
171
 
104
172
  - `workflow_language`
105
173
  - `paper_language`
106
174
  - `paper_format`
175
+ - `deliverables_root`
107
176
 
108
177
  后续 stage 应该按这个配置决定语言和论文格式,而不是各模板自己猜。
109
178
 
@@ -118,12 +187,14 @@ superlab init --lang en
118
187
  ## 命令集合
119
188
 
120
189
  - `/lab:idea` 调研 idea、文献、数据集、指标和 baseline,并输出初始方案。
121
- - `/lab:spec` 把批准后的方案转换成一个统一的 `.superlab/changes/<change-id>/` 目录。
190
+ - `/lab:framing` 在正式写作前收紧方法名、模块名、论文题目和 contribution wording。
191
+ - `/lab:spec` 把批准后的方案转换成一个统一的 `.lab/changes/<change-id>/` 目录。
122
192
  - `/lab:run` 执行最小可运行实验,并建立首版评估链路。
123
193
  - `/lab:iterate` 以固定 mission、固定阈值和最大轮次做有边界的实验迭代。
124
194
  - `/lab:review` 以审稿人模式检查方法、对照、公平性、泄漏和统计问题。
125
195
  - `/lab:report` 根据累积工件生成最终实验报告。
126
196
  - `/lab:write` 把稳定的 report 工件转成论文 section,并按小步方式逐轮修改。
197
+ 它要求先有一个经批准的 `/lab:framing` 工件。
127
198
  它会读取随 `lab` 一起安装的 vendored 章节参考,这些参考来源于 `Research-Paper-Writing-Skills`。
128
199
 
129
200
  ## 使用流程
@@ -135,17 +206,20 @@ superlab init --lang en
135
206
  5. 用 `/lab:iterate` 进行多轮迭代。
136
207
  6. 在关键节点运行 `/lab:review`。
137
208
  7. 最后用 `/lab:report` 产出总报告。
138
- 8. 用 `/lab:write` 把稳定结果写成论文各 section
209
+ 8. 用 `/lab:framing` 收紧题目、命名和 contribution wording
210
+ 9. 用 `/lab:write` 把稳定结果写成论文各 section。
139
211
 
140
- `/lab:write` 最终只把论文写入:
212
+ `/lab:write` 会把最终可交付物写到 `deliverables_root` 指定的目录,默认是 `docs/research`:
141
213
 
142
- - `docs/paper/paper.tex`
143
- - `docs/paper/sections/*.tex`
214
+ - `docs/research/report.md`
215
+ - `docs/research/paper/main.tex`
216
+ - `docs/research/paper/sections/*.tex`
144
217
 
145
218
  内部写作控制工件放在:
146
219
 
147
- - `.superlab/write/plan.md`
148
- - `.superlab/write/iterations/*.md`
220
+ - `.lab/writing/framing.md`
221
+ - `.lab/writing/plan.md`
222
+ - `.lab/writing/iterations/*.md`
149
223
 
150
224
  ## 仓库内容
151
225
 
@@ -156,6 +230,7 @@ superlab init --lang en
156
230
  - `scripts/` 是运行登记、评估汇总和结果校验脚本。
157
231
  - `tests/` 是脚本与安装器测试。
158
232
  - `examples/` 是最小端到端示例。
233
+ - `docs/` 存放设计文档和发布说明。
159
234
  - `docs/release.md` 是发布到 npm 的操作说明。
160
235
  - `.github/workflows/ci.yml` 会在 `main` 和 PR 上自动执行 `npm run release:check`。
161
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,8 +10,20 @@ 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
 
20
+ function restartReminder(lang) {
21
+ if (lang === "zh") {
22
+ return "项目资产已更新。请新开一个 Codex/Claude 会话;如果仍未生效,再重启应用。";
23
+ }
24
+ return "Project assets updated. Start a new Codex/Claude session; if changes still do not appear, restart the app.";
25
+ }
26
+
14
27
  function printHelp() {
15
28
  console.log(`superlab
16
29
 
@@ -20,12 +33,20 @@ Usage:
20
33
  superlab update [--target <dir>]
21
34
  superlab update --all-projects
22
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>]
23
41
 
24
42
  Commands:
25
43
  init Initialize /lab commands, skills, templates, and scripts in a target
26
44
  install Backward-compatible alias for init
27
45
  update Refresh an initialized project or all registered projects
28
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
29
50
  help Show this help message
30
51
  `);
31
52
  }
@@ -121,6 +142,35 @@ function parseVersionArgs(argv) {
121
142
  return options;
122
143
  }
123
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
+
124
174
  function printVersion(options) {
125
175
  const lines = [];
126
176
  if (!options.projectOnly) {
@@ -143,6 +193,167 @@ function printVersion(options) {
143
193
  console.log(lines.join("\n"));
144
194
  }
145
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
+
146
357
  function shouldUseInteractiveInit(options) {
147
358
  if (options.lang && options.platform) {
148
359
  return false;
@@ -194,7 +405,7 @@ async function main() {
194
405
  return;
195
406
  }
196
407
 
197
- if (!["init", "install", "update", "version"].includes(command)) {
408
+ if (!["init", "install", "update", "version", "handoff", "doctor", "context"].includes(command)) {
198
409
  throw new Error(`Unknown command: ${command}`);
199
410
  }
200
411
 
@@ -203,6 +414,33 @@ async function main() {
203
414
  return;
204
415
  }
205
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
+
206
444
  if (command === "update") {
207
445
  const options = parseUpdateArgs(rest);
208
446
  if (options.allProjects) {
@@ -214,6 +452,7 @@ async function main() {
214
452
  for (const project of result.skipped) {
215
453
  console.log(`skipped: ${project.path} (${project.reason})`);
216
454
  }
455
+ console.log(restartReminder(detectLanguage()));
217
456
  return;
218
457
  }
219
458
 
@@ -224,6 +463,7 @@ async function main() {
224
463
  if (metadata.migration) {
225
464
  console.log(`migration: ${metadata.migration}`);
226
465
  }
466
+ console.log(restartReminder(metadata.lang));
227
467
  return;
228
468
  }
229
469
 
@@ -236,6 +476,7 @@ async function main() {
236
476
  console.log(`superlab installed into ${options.targetDir}`);
237
477
  console.log(`platform: ${options.platform}`);
238
478
  console.log(`language: ${options.lang}`);
479
+ console.log(restartReminder(options.lang));
239
480
  }
240
481
 
241
482
  main().catch((error) => {