@namewta/speculo 0.7.0 → 0.7.1

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.
@@ -0,0 +1,470 @@
1
+ import { createHash } from "node:crypto";
2
+ import { cp, lstat, mkdir, readFile, readdir, readlink, rm, writeFile, } from "node:fs/promises";
3
+ import { dirname, join, relative, sep } from "node:path";
4
+ import { pathExists } from "./utils.js";
5
+ const BACKUP_RELATIVE = ".speculo/back";
6
+ const INSTALL_RELATIVE = ".speculo/install.json";
7
+ const MIGRATION_RELATIVE = ".speculo/migration.json";
8
+ const SNAPSHOT_DIR = ".migration-snapshot";
9
+ const MANAGED_STATE_ENTRIES = new Set([
10
+ "README.md",
11
+ "workspace.json",
12
+ "install.json",
13
+ "migration.json",
14
+ "back",
15
+ ]);
16
+ function toPosix(path) {
17
+ return path.split(sep).join("/");
18
+ }
19
+ async function readJson(path) {
20
+ return JSON.parse(await readFile(path, "utf8"));
21
+ }
22
+ async function readTargetVersion(packageRoot) {
23
+ const manifest = await readJson(join(packageRoot, "package.json"));
24
+ if (typeof manifest.version !== "string" || !/^\d+\.\d+\.\d+(?:[-+].+)?$/.test(manifest.version)) {
25
+ throw new Error("package.json has no valid semantic version");
26
+ }
27
+ return manifest.version;
28
+ }
29
+ function versionBefore07(version) {
30
+ const match = /^(\d+)\.(\d+)\.(\d+)/.exec(version);
31
+ if (!match)
32
+ return true;
33
+ const major = Number(match[1]);
34
+ const minor = Number(match[2]);
35
+ return major === 0 && minor < 7;
36
+ }
37
+ async function sourceVersion(snapshotState) {
38
+ const installPath = join(snapshotState, "install.json");
39
+ if (!(await pathExists(installPath)))
40
+ return { version: "0.7.0-unversioned", blockers: [] };
41
+ try {
42
+ const install = await readJson(installPath);
43
+ if (install.schema_version !== 1 || typeof install.package_version !== "string") {
44
+ return {
45
+ version: null,
46
+ blockers: [{ code: "invalid-install-manifest", path: ".speculo/install.json", message: "install manifest must use schema v1 and contain package_version" }],
47
+ };
48
+ }
49
+ return { version: install.package_version, blockers: [] };
50
+ }
51
+ catch (error) {
52
+ return {
53
+ version: null,
54
+ blockers: [{ code: "invalid-json", path: ".speculo/install.json", message: String(error) }],
55
+ };
56
+ }
57
+ }
58
+ async function copySnapshot(previousRoot, snapshotRoot) {
59
+ await mkdir(snapshotRoot, { recursive: true });
60
+ const configPath = join(previousRoot, "config.json");
61
+ if (await pathExists(configPath))
62
+ await cp(configPath, join(snapshotRoot, "config.json"), { force: true });
63
+ const previousState = join(previousRoot, ".speculo");
64
+ if (!(await pathExists(previousState)))
65
+ return;
66
+ await cp(previousState, join(snapshotRoot, "state"), {
67
+ recursive: true,
68
+ force: true,
69
+ filter: (source) => {
70
+ const item = toPosix(relative(previousState, source));
71
+ return item !== "back" && !item.startsWith("back/") && item !== "migration.json";
72
+ },
73
+ });
74
+ }
75
+ async function collectBackupEntries(root, current = root) {
76
+ if (!(await pathExists(current)))
77
+ return [];
78
+ const entries = [];
79
+ for (const entry of await readdir(current, { withFileTypes: true })) {
80
+ const path = join(current, entry.name);
81
+ if (entry.isDirectory()) {
82
+ entries.push(...await collectBackupEntries(root, path));
83
+ continue;
84
+ }
85
+ const itemPath = toPosix(relative(root, path));
86
+ if (entry.isSymbolicLink()) {
87
+ entries.push({ path: itemPath, type: "symlink", target: await readlink(path) });
88
+ continue;
89
+ }
90
+ if (!entry.isFile())
91
+ continue;
92
+ const content = await readFile(path);
93
+ entries.push({
94
+ path: itemPath,
95
+ type: "file",
96
+ bytes: content.byteLength,
97
+ sha256: createHash("sha256").update(content).digest("hex"),
98
+ });
99
+ }
100
+ return entries.sort((left, right) => left.path.localeCompare(right.path));
101
+ }
102
+ async function writeBackup(snapshotRoot, stagedRoot, source, target) {
103
+ const backupRoot = join(stagedRoot, BACKUP_RELATIVE);
104
+ await rm(backupRoot, { recursive: true, force: true });
105
+ await mkdir(backupRoot, { recursive: true });
106
+ const snapshotConfig = join(snapshotRoot, "config.json");
107
+ const snapshotState = join(snapshotRoot, "state");
108
+ if (await pathExists(snapshotConfig))
109
+ await cp(snapshotConfig, join(backupRoot, "config.json"), { force: true });
110
+ if (await pathExists(snapshotState))
111
+ await cp(snapshotState, join(backupRoot, "state"), { recursive: true, force: true });
112
+ const files = await collectBackupEntries(backupRoot);
113
+ await writeFile(join(backupRoot, "manifest.json"), JSON.stringify({
114
+ schema_version: 1,
115
+ source_version: source,
116
+ target_version: target,
117
+ created_at: new Date().toISOString(),
118
+ files,
119
+ }, null, 2) + "\n", "utf8");
120
+ }
121
+ async function inspectJsonTree(root) {
122
+ if (!(await pathExists(root)))
123
+ return [];
124
+ const blockers = [];
125
+ async function visit(current) {
126
+ for (const entry of await readdir(current, { withFileTypes: true })) {
127
+ const path = join(current, entry.name);
128
+ const label = toPosix(relative(dirname(root), path));
129
+ if (entry.isDirectory()) {
130
+ await visit(path);
131
+ }
132
+ else if (entry.isSymbolicLink()) {
133
+ blockers.push({ code: "state-symlink", path: label, message: "runtime state symlinks require manual migration review" });
134
+ }
135
+ else if (entry.isFile() && entry.name.endsWith(".json")) {
136
+ try {
137
+ JSON.parse(await readFile(path, "utf8"));
138
+ }
139
+ catch (error) {
140
+ blockers.push({ code: "invalid-json", path: label, message: String(error) });
141
+ }
142
+ }
143
+ }
144
+ }
145
+ await visit(root);
146
+ return blockers;
147
+ }
148
+ function expectArray(value) {
149
+ return Array.isArray(value);
150
+ }
151
+ async function inspectSpecdevState(stateRoot) {
152
+ const blockers = [];
153
+ const statusPath = join(stateRoot, "specdev", "status.json");
154
+ if (!(await pathExists(statusPath)))
155
+ return blockers;
156
+ let status;
157
+ try {
158
+ status = await readJson(statusPath);
159
+ }
160
+ catch {
161
+ return blockers;
162
+ }
163
+ if (status.schema_version !== 4 || status.workflow !== "specdev" || !expectArray(status.active) || !expectArray(status.archived)) {
164
+ blockers.push({ code: "unsupported-specdev-status", path: ".speculo/specdev/status.json", message: "automatic migration supports SpecDev global status schema v4 only" });
165
+ return blockers;
166
+ }
167
+ const activeNames = new Set();
168
+ for (const item of status.active) {
169
+ if (!item || typeof item !== "object" || typeof item.change !== "string") {
170
+ blockers.push({ code: "invalid-active-entry", path: ".speculo/specdev/status.json", message: "active entries must contain a change name" });
171
+ continue;
172
+ }
173
+ const name = item.change;
174
+ if (activeNames.has(name)) {
175
+ blockers.push({ code: "duplicate-active-change", path: ".speculo/specdev/status.json", message: `${name} appears more than once in active` });
176
+ }
177
+ activeNames.add(name);
178
+ const changeStatusPath = join(stateRoot, "specdev", "changes", name, ".status.json");
179
+ if (!(await pathExists(changeStatusPath))) {
180
+ blockers.push({ code: "missing-active-change", path: `.speculo/specdev/changes/${name}/.status.json`, message: "active status entry has no matching change state" });
181
+ }
182
+ else {
183
+ try {
184
+ const changeStatus = await readJson(changeStatusPath);
185
+ if (changeStatus.schema_version !== 3 ||
186
+ changeStatus.artifact !== "change-status" ||
187
+ changeStatus.change !== name ||
188
+ !new Set(["active", "blocked", "completed"]).has(String(changeStatus.change_status))) {
189
+ blockers.push({ code: "unsupported-change-status", path: `.speculo/specdev/changes/${name}/.status.json`, message: "active change state must use schema v3 and match its index entry" });
190
+ }
191
+ }
192
+ catch {
193
+ // The JSON tree check reports the parse failure with the precise path.
194
+ }
195
+ }
196
+ }
197
+ const archivedNames = new Set();
198
+ for (const item of status.archived) {
199
+ if (typeof item !== "string") {
200
+ blockers.push({ code: "invalid-archived-entry", path: ".speculo/specdev/status.json", message: "archived entries must be change names" });
201
+ continue;
202
+ }
203
+ if (archivedNames.has(item))
204
+ blockers.push({ code: "duplicate-archived-change", path: ".speculo/specdev/status.json", message: `${item} appears more than once in archived` });
205
+ archivedNames.add(item);
206
+ if (activeNames.has(item))
207
+ blockers.push({ code: "status-overlap", path: ".speculo/specdev/status.json", message: `${item} appears in both active and archived` });
208
+ const month = item.slice(0, 7);
209
+ const archivedStatusPath = join(stateRoot, "specdev", "archive", month, item, ".status.json");
210
+ if (!(await pathExists(archivedStatusPath))) {
211
+ blockers.push({ code: "missing-archived-change", path: `.speculo/specdev/archive/${month}/${item}/.status.json`, message: "archived status entry has no matching archived change state" });
212
+ }
213
+ else {
214
+ try {
215
+ const archivedStatus = await readJson(archivedStatusPath);
216
+ if (archivedStatus.schema_version !== 3 ||
217
+ archivedStatus.artifact !== "change-status" ||
218
+ archivedStatus.change !== item ||
219
+ archivedStatus.change_status !== "archived") {
220
+ blockers.push({ code: "unsupported-archived-status", path: `.speculo/specdev/archive/${month}/${item}/.status.json`, message: "archived change state must use schema v3 and match its index entry" });
221
+ }
222
+ }
223
+ catch {
224
+ // The JSON tree check reports the parse failure with the precise path.
225
+ }
226
+ }
227
+ }
228
+ const changesRoot = join(stateRoot, "specdev", "changes");
229
+ if (await pathExists(changesRoot)) {
230
+ for (const entry of await readdir(changesRoot, { withFileTypes: true })) {
231
+ if (!entry.isDirectory())
232
+ continue;
233
+ const changeStatusPath = join(changesRoot, entry.name, ".status.json");
234
+ if (!(await pathExists(changeStatusPath))) {
235
+ blockers.push({ code: "missing-change-status", path: `.speculo/specdev/changes/${entry.name}/.status.json`, message: "change directory has no status file" });
236
+ }
237
+ else if (!activeNames.has(entry.name)) {
238
+ blockers.push({ code: "unindexed-active-change", path: `.speculo/specdev/changes/${entry.name}`, message: "change directory is missing from the active index" });
239
+ }
240
+ }
241
+ }
242
+ const archiveRoot = join(stateRoot, "specdev", "archive");
243
+ if (await pathExists(archiveRoot)) {
244
+ for (const monthEntry of await readdir(archiveRoot, { withFileTypes: true })) {
245
+ if (!monthEntry.isDirectory())
246
+ continue;
247
+ const monthRoot = join(archiveRoot, monthEntry.name);
248
+ for (const changeEntry of await readdir(monthRoot, { withFileTypes: true })) {
249
+ if (!changeEntry.isDirectory())
250
+ continue;
251
+ const archivedStatusPath = join(monthRoot, changeEntry.name, ".status.json");
252
+ if (!(await pathExists(archivedStatusPath))) {
253
+ blockers.push({ code: "missing-archived-status", path: `.speculo/specdev/archive/${monthEntry.name}/${changeEntry.name}/.status.json`, message: "archived change directory has no status file" });
254
+ }
255
+ else if (!archivedNames.has(changeEntry.name)) {
256
+ blockers.push({ code: "unindexed-archived-change", path: `.speculo/specdev/archive/${monthEntry.name}/${changeEntry.name}`, message: "archived change directory is missing from the archived index" });
257
+ }
258
+ }
259
+ }
260
+ }
261
+ const configPath = join(stateRoot, "specdev", "config.json");
262
+ if (await pathExists(configPath)) {
263
+ try {
264
+ const config = await readJson(configPath);
265
+ if (config.schema_version !== 3)
266
+ blockers.push({ code: "unsupported-specdev-config", path: ".speculo/specdev/config.json", message: "automatic migration supports SpecDev config schema v3 only" });
267
+ }
268
+ catch {
269
+ // The JSON tree check reports the parse failure with the precise path.
270
+ }
271
+ }
272
+ return blockers;
273
+ }
274
+ async function inspectCommandState(stateRoot) {
275
+ const commandsRoot = join(stateRoot, "commands");
276
+ if (!(await pathExists(commandsRoot)))
277
+ return [];
278
+ const blockers = [];
279
+ for (const entry of await readdir(commandsRoot, { withFileTypes: true })) {
280
+ if (!entry.isDirectory())
281
+ continue;
282
+ const statePath = join(commandsRoot, entry.name, "state.json");
283
+ if (!(await pathExists(statePath)))
284
+ continue;
285
+ if (entry.name !== "docs-sync") {
286
+ blockers.push({ code: "unknown-command-state", path: `.speculo/commands/${entry.name}/state.json`, message: "command state has no current migration contract" });
287
+ continue;
288
+ }
289
+ try {
290
+ const state = await readJson(statePath);
291
+ if (state.schema_version !== 4 || state.command !== "docs-sync") {
292
+ blockers.push({ code: "unsupported-command-state", path: ".speculo/commands/docs-sync/state.json", message: "automatic migration supports docs-sync state schema v4 only" });
293
+ }
294
+ }
295
+ catch {
296
+ // The JSON tree check reports the parse failure with the precise path.
297
+ }
298
+ }
299
+ return blockers;
300
+ }
301
+ async function inspectPersonState(stateRoot) {
302
+ const statusPath = join(stateRoot, "person", "status.json");
303
+ if (!(await pathExists(statusPath)))
304
+ return [];
305
+ try {
306
+ const status = await readJson(statusPath);
307
+ if (status.schema_version !== 1 || status.workflow !== "person" || !expectArray(status.active)) {
308
+ return [{ code: "unsupported-person-status", path: ".speculo/person/status.json", message: "automatic migration supports person status schema v1 only" }];
309
+ }
310
+ }
311
+ catch {
312
+ // The JSON tree check reports the parse failure with the precise path.
313
+ }
314
+ return [];
315
+ }
316
+ async function inspectSnapshot(snapshotRoot, source) {
317
+ const blockers = [];
318
+ const configPath = join(snapshotRoot, "config.json");
319
+ if (!(await pathExists(configPath))) {
320
+ blockers.push({ code: "missing-config", path: "config.json", message: "existing installation has no project configuration" });
321
+ }
322
+ else if ((await lstat(configPath)).isSymbolicLink()) {
323
+ blockers.push({ code: "state-symlink", path: "config.json", message: "project configuration symlinks require manual migration review" });
324
+ }
325
+ else {
326
+ try {
327
+ const config = await readJson(configPath);
328
+ if (config.schema_version !== 1)
329
+ blockers.push({ code: "unsupported-config", path: "config.json", message: "automatic migration supports project config schema v1 only" });
330
+ }
331
+ catch (error) {
332
+ blockers.push({ code: "invalid-json", path: "config.json", message: String(error) });
333
+ }
334
+ }
335
+ const stateRoot = join(snapshotRoot, "state");
336
+ const stateRootIsSymlink = await pathExists(stateRoot) && (await lstat(stateRoot)).isSymbolicLink();
337
+ if (stateRootIsSymlink) {
338
+ blockers.push({ code: "state-symlink", path: ".speculo", message: "runtime state root symlinks require manual migration review" });
339
+ }
340
+ const workspacePath = join(stateRoot, "workspace.json");
341
+ if (!stateRootIsSymlink && !(await pathExists(workspacePath))) {
342
+ blockers.push({ code: "missing-workspace", path: ".speculo/workspace.json", message: "existing installation has no workspace root manifest" });
343
+ }
344
+ else if (!stateRootIsSymlink) {
345
+ try {
346
+ const workspace = await readJson(workspacePath);
347
+ const roots = workspace.roots;
348
+ if (workspace.schema_version !== 1 || workspace.path_base !== "project-root" ||
349
+ !roots || typeof roots !== "object" ||
350
+ ["config", "speculo", "state", "commands", "skills", "workflows"].some((key) => typeof roots[key] !== "string")) {
351
+ blockers.push({ code: "unsupported-workspace", path: ".speculo/workspace.json", message: "automatic migration supports workspace schema v1 with project-root aliases only" });
352
+ }
353
+ }
354
+ catch {
355
+ // The JSON tree check reports the parse failure with the precise path.
356
+ }
357
+ }
358
+ if (source === null || versionBefore07(source)) {
359
+ blockers.push({ code: "unsupported-source-version", path: ".speculo/install.json", message: "automatic migration supports v0.7 and newer installations only" });
360
+ }
361
+ if (!stateRootIsSymlink) {
362
+ blockers.push(...await inspectJsonTree(stateRoot));
363
+ blockers.push(...await inspectSpecdevState(stateRoot));
364
+ blockers.push(...await inspectPersonState(stateRoot));
365
+ blockers.push(...await inspectCommandState(stateRoot));
366
+ }
367
+ return blockers;
368
+ }
369
+ function mergeDefaults(defaults, previous) {
370
+ if (defaults && typeof defaults === "object" && !Array.isArray(defaults) &&
371
+ previous && typeof previous === "object" && !Array.isArray(previous)) {
372
+ const merged = { ...defaults };
373
+ for (const [key, value] of Object.entries(previous)) {
374
+ merged[key] = key in merged ? mergeDefaults(merged[key], value) : value;
375
+ }
376
+ return merged;
377
+ }
378
+ return previous;
379
+ }
380
+ async function restoreCompatibleState(snapshotRoot, stagedRoot) {
381
+ const snapshotState = join(snapshotRoot, "state");
382
+ const stagedState = join(stagedRoot, ".speculo");
383
+ if (await pathExists(snapshotState)) {
384
+ for (const entry of await readdir(snapshotState, { withFileTypes: true })) {
385
+ if (MANAGED_STATE_ENTRIES.has(entry.name))
386
+ continue;
387
+ await cp(join(snapshotState, entry.name), join(stagedState, entry.name), {
388
+ recursive: entry.isDirectory(),
389
+ force: true,
390
+ });
391
+ }
392
+ }
393
+ const previousConfig = join(snapshotRoot, "config.json");
394
+ if (await pathExists(previousConfig)) {
395
+ const defaults = await readJson(join(stagedRoot, "config.json"));
396
+ const previous = await readJson(previousConfig);
397
+ await writeFile(join(stagedRoot, "config.json"), JSON.stringify(mergeDefaults(defaults, previous), null, 2) + "\n", "utf8");
398
+ }
399
+ }
400
+ async function restoreUnselectedState(snapshotRoot, stagedRoot, workflowIds) {
401
+ for (const workflowId of workflowIds) {
402
+ const source = join(snapshotRoot, "state", workflowId);
403
+ if (await pathExists(source))
404
+ await cp(source, join(stagedRoot, ".speculo", workflowId), { recursive: true, force: true });
405
+ }
406
+ }
407
+ async function writeInstallManifest(stagedRoot, targetVersion, workflowIds) {
408
+ await writeFile(join(stagedRoot, INSTALL_RELATIVE), JSON.stringify({
409
+ schema_version: 1,
410
+ package_version: targetVersion,
411
+ workflows: [...new Set(workflowIds)].sort(),
412
+ }, null, 2) + "\n", "utf8");
413
+ }
414
+ async function writePendingMarker(stagedRoot, source, target, blockers) {
415
+ await writeFile(join(stagedRoot, MIGRATION_RELATIVE), JSON.stringify({
416
+ schema_version: 1,
417
+ status: "pending",
418
+ source_version: source,
419
+ target_version: target,
420
+ backup_root: "speculo/.speculo/back",
421
+ created_at: new Date().toISOString(),
422
+ blockers,
423
+ }, null, 2) + "\n", "utf8");
424
+ }
425
+ export async function assertNoPendingMigration(previousRoot) {
426
+ const marker = join(previousRoot, MIGRATION_RELATIVE);
427
+ if (!(await pathExists(marker)))
428
+ return;
429
+ throw new Error("Speculo runtime migration is pending. Run the migrate-runtime-state command before speculo init.");
430
+ }
431
+ export async function migrateRuntimeState(options) {
432
+ const targetVersion = await readTargetVersion(options.packageRoot);
433
+ const snapshotRoot = join(options.stagedRoot, SNAPSHOT_DIR);
434
+ await copySnapshot(options.previousRoot, snapshotRoot);
435
+ const snapshotState = join(snapshotRoot, "state");
436
+ const snapshotStateIsSymlink = await pathExists(snapshotState) && (await lstat(snapshotState)).isSymbolicLink();
437
+ const versionResult = snapshotStateIsSymlink
438
+ ? { version: null, blockers: [] }
439
+ : await sourceVersion(snapshotState);
440
+ const blockers = [...versionResult.blockers, ...await inspectSnapshot(snapshotRoot, versionResult.version)];
441
+ await writeBackup(snapshotRoot, options.stagedRoot, versionResult.version, targetVersion);
442
+ if (blockers.length === 0) {
443
+ await restoreCompatibleState(snapshotRoot, options.stagedRoot);
444
+ }
445
+ else {
446
+ await restoreUnselectedState(snapshotRoot, options.stagedRoot, options.unselectedWorkflowIds);
447
+ await writePendingMarker(options.stagedRoot, versionResult.version, targetVersion, blockers);
448
+ }
449
+ await writeInstallManifest(options.stagedRoot, targetVersion, [...options.selectedWorkflowIds, ...options.unselectedWorkflowIds]);
450
+ await rm(snapshotRoot, { recursive: true, force: true });
451
+ return {
452
+ status: blockers.length === 0 ? "migrated" : "pending",
453
+ sourceVersion: versionResult.version,
454
+ targetVersion,
455
+ backupPath: "speculo/.speculo/back",
456
+ blockers,
457
+ };
458
+ }
459
+ export async function initializeRuntimeManifest(packageRoot, stagedRoot, workflowIds) {
460
+ const targetVersion = await readTargetVersion(packageRoot);
461
+ await writeInstallManifest(stagedRoot, targetVersion, workflowIds);
462
+ return {
463
+ status: "not-required",
464
+ sourceVersion: null,
465
+ targetVersion,
466
+ backupPath: null,
467
+ blockers: [],
468
+ };
469
+ }
470
+ //# sourceMappingURL=migrations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrations.js","sourceRoot":"","sources":["../../src/migrations.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@namewta/speculo",
3
- "version": "0.7.0",
4
- "description": "Workflow-packaged specification-driven development assets with direct refresh tooling.",
3
+ "version": "0.7.1",
4
+ "description": "Workflow-packaged specification-driven development assets with state-safe refresh tooling.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "speculo": "./dist/src/cli.js"
@@ -4,16 +4,21 @@
4
4
 
5
5
  ## 刷新契约
6
6
 
7
- 重新运行 `speculo init` 会直接以当前模板刷新 Speculo 管理的配置与静态资产,不执行旧状态迁移或兼容。对本次选中的 workflow,刷新只保留 `changes/` `archive/` 历史;workflow 配置、sidecar、未知运行文件与 command `state.json` 会被删除。Command Markdown 报告保留作审计记录,但不保证旧工件可被新 workflow 恢复。
7
+ 重新运行 `speculo init` 会以当前模板刷新 commands、skills 与选中的 workflow 静态资产,并对 v0.7+ 运行时执行兼容检查。兼容时递归合并项目配置的当前默认值,并完整保留 workflow 配置、状态索引、`changes/`、`archive/`、永久知识、sidecar、command 报告和具有当前合同的 command `state.json`。
8
+
9
+ 每次刷新先把旧 `config.json` 和旧 `.speculo/` 快照写入 `back/`,排除上一份 `back/` 与旧 pending marker,因此只保留最近一次刷新前备份。`install.json` 记录当前包版本和已安装 workflows;`back/manifest.json` 记录来源/目标版本及每个备份文件的 hash 和大小。
10
+
11
+ 若来源版本、核心 schema、JSON、符号链接、command state owner 或 workflow 索引无法证明兼容,刷新安装当前干净模板状态并创建 `migration.json`,其 `status` 为 `pending`。此时所有 workflow 读取和状态写入都必须停止;只能运行 `migrate-runtime-state` command,基于只读 `back/` 逐项对账、确认并原子迁移。再次运行 `speculo init` 会在任何修改前阻塞。
8
12
 
9
13
  ## 读取顺序
10
14
 
11
15
  1. 读取 `workspace.json`,以当前打开项目为 `project_root` 解析公共 roots。
12
- 2. `../workflows/<workflow>/INDEX.md` 进入 workflow,再通过 `<Path>` 指针进入具体 work 入口文件。
13
- 3. 读取 `<workflow>/status.json`,再读取 `changes/<change>/.status.json` 和当前 work 产物。
14
- 4. 历史 change 只从 `<workflow>/archive/YYYY-MM/<change>/` 读取。
15
- 5. Command 报告位于 `commands/<command>/*.md`,command state 位于 `commands/<command>/state.json`。
16
- 6. 首次 docs-sync 确认后读取 `<workflow>/docs-sync.json`;它分列该 workflow 的项目文档和私有 state 更新范围。
16
+ 2. 检查 `migration.json`;存在 pending 时停止,仅路由到 `migrate-runtime-state` command。
17
+ 3. `../workflows/<workflow>/INDEX.md` 进入 workflow,再通过 `<Path>` 指针进入具体 work 入口文件。
18
+ 4. 读取 `<workflow>/status.json`,再读取 `changes/<change>/.status.json` 和当前 work 产物。
19
+ 5. 历史 change 只从 `<workflow>/archive/YYYY-MM/<change>/` 读取。
20
+ 6. Command 报告位于 `commands/<command>/*.md`,command state 位于 `commands/<command>/state.json`。
21
+ 7. 首次 docs-sync 确认后读取 `<workflow>/docs-sync.json`;它分列该 workflow 的项目文档和私有 state 更新范围。
17
22
 
18
23
  ## 写入边界
19
24
 
@@ -21,3 +26,5 @@
21
26
  - `docs-sync.json` 是 docs-sync command 拥有的延迟 sidecar,不进入 `_state`,也不授予越过 workflow 确认规则的权限。
22
27
  - `.config` 不是标准目录;只有 workflow 声明时才可使用。
23
28
  - Command 报告命名为 `<YYYY-MM-DD>-<scope>-<topic>[-NN].md`,禁止覆盖。
29
+ - `back/` 由 `speculo init` 单一写入,迁移 command 只读;workflow 和其他 commands 不得修改。
30
+ - `install.json` 与 `migration.json` 由 CLI/迁移脚本拥有,workflow 不得创建、修改或删除。
@@ -0,0 +1,43 @@
1
+ ---
2
+ id: migrate-runtime-state
3
+ type: command
4
+ name: Migrate Runtime State
5
+ description: 盘点 pending Speculo 运行时备份,生成可确认迁移计划,并在明确授权后原子修复配置与持久状态。
6
+ keywords: [runtime-migration, pending, back, 状态迁移, 配置修复]
7
+ ---
8
+
9
+ # Migrate Runtime State 命令
10
+
11
+ 本命令只处理 `speculo init` 已标记为 pending 的运行时迁移。它不替代 `speculo init`,不迁移静态 commands、skills 或 workflow 包,也不修改 `<Path>{roots.state}/back/</Path>`。
12
+
13
+ ## 报告
14
+
15
+ 写入:`<Path>{roots.state}/commands/migrate-runtime-state/<YYYY-MM-DD>-workspace-runtime-state[-NN].md</Path>`。
16
+
17
+ 报告记录 command id、生成时间、project root、源/目标版本、pending blockers、备份 manifest hash 结论、逐路径动作、冲突决策、确认状态、执行结果、回滚结果和残余风险。同名报告从 `-01` 选择最小未占用编号,禁止覆盖。
18
+
19
+ ## 执行
20
+
21
+ 1. 从当前目录向上解析唯一 `speculo/.speculo/workspace.json`,读取 `speculo/.speculo/migration.json`、`speculo/.speculo/back/manifest.json`、`speculo/config.json` 和已安装 workflow INDEX。缺少 pending marker 或 marker 不为 `status: pending` 时停止,不创建可执行计划。
22
+ 2. 读取 `<Path>{roots.skills}/migrate-runtime-state/SKILL.md</Path>`,传入 project root、state root、backup root、pending marker、允许写入的 `speculo/config.json` 与 runtime state 边界,以及本 command 的报告路径。
23
+ 3. 先调用 skill 的 inspect/dry-run 分支,穷尽备份中的每个文件并生成 `restore | merge-json | replace-json | keep-current | remove-current | unresolved` 映射。任何 `unresolved` 都阻塞执行;可执行 plan 的 `source_decisions` 必须恰好覆盖 backup manifest,且锁定 manifest sha256。
24
+ 4. 把完整映射、覆盖/删除动作、验证命令和预期副作用写入报告并展示摘要。初始“修复迁移”请求不算执行确认。
25
+ 5. 只有用户明确批准当前计划后,把同一计划以 `confirmed` 模式交回 skill。执行前必须重验 marker、manifest hashes、每个 action 的 `expected_target` 和计划内容未漂移。
26
+ 6. skill 返回后重读 `speculo/config.json`、`<Path>{roots.state}/install.json</Path>`、pending marker、所有迁移目标和备份 manifest;运行已安装 workflow 的包级校验。pending marker 仍存在或任一验证失败时报告 blocked,不宣称完成。
27
+ 7. 将执行结果和 rollback 状态追加到原报告。成功时返回报告路径、保留的 backup 路径和已迁移 namespace;失败时返回原 active 安装是否恢复、未完成动作与恢复条件。
28
+
29
+ ## 确认边界
30
+
31
+ - Dry-run 只允许创建本 command 的 Markdown 报告和进程外临时 plan;不得修改配置、workflow state、command state 或备份。
32
+ - `replace-json`、`remove-current` 和任何覆盖动作必须在计划中逐项列出并取得确认。
33
+ - 备份 hash 不一致、路径越界、目标漂移、未知 owner、JSON 无法修复或验证失败时停止。
34
+ - `back/` 始终只读并保留为最近一次 rollback 来源;成功迁移不删除它。
35
+
36
+ ## 完成标准
37
+
38
+ - pending marker、backup manifest 和全部文件均有结论;
39
+ - 未确认路径除报告外无写入;
40
+ - 已确认执行通过 staging、原子替换和失败回滚;
41
+ - 配置与所有已安装 workflow 状态满足当前合同;
42
+ - pending marker 已清除,最近备份仍完整;
43
+ - 报告不覆盖且足以重建每个决策与动作。
@@ -16,7 +16,7 @@
16
16
  | 7 | 包管理器 | `pnpm --version` (或 `npm` / `yarn`) | 版本 ≥ 仓库 lockfile 隐含版本 | 安装匹配版本;不要随意切换包管理器 |
17
17
  | 8 | release.yml 存在 | `test -f .github/workflows/release.yml` | 文件存在 | 转 `github-npm-ops` skill 的 `references/workflow-yaml-reference.md` 先落该文件 |
18
18
  | 9 | release.yml 形态 | 见 [publish-detection.md](publish-detection.md) | 输出 `PUBLISH_TO_NPM=true` 或 `false` | 见 publish-detection 文档的判定矩阵 |
19
- | 10 | docs-sync state | `test -f speculo/.speculo/commands/docs-sync/state.json && jq . speculo/.speculo/commands/docs-sync/state.json` | schema v4、scope 已确认,baseline 可解析 | 不存在/未确认 → 走 docs-sync command bootstrap;旧 schema 或损坏 → 重新运行 `speculo init` 刷新受管理状态后再确认范围 |
19
+ | 10 | docs-sync state | `test -f speculo/.speculo/commands/docs-sync/state.json && jq . speculo/.speculo/commands/docs-sync/state.json` | schema v4、scope 已确认,baseline 可解析 | 不存在/未确认 → 走 docs-sync command bootstrap;旧 schema 或损坏 → 运行 `speculo init` 建立 pending 备份,再以 `migrate-runtime-state` command 修复后确认范围 |
20
20
  | 11 | tag 名称冲突 | `git rev-parse vX.Y.Z 2>/dev/null` | 退出码非 0(tag 不存在) | 同 tag 已存在:先确认是否真的失败需要重发;若是则 `git tag -d` + `git push origin :refs/tags/vX.Y.Z`,否则 bump 到下一版本 |
21
21
 
22
22
  ## 失败处理总策略