@namewta/speculo 0.7.0 → 0.7.2
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 +9 -6
- package/dist/src/cli.js +12 -0
- package/dist/src/cli.js.map +1 -1
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +56 -58
- package/dist/src/index.js.map +1 -1
- package/dist/src/migrations.d.ts +23 -0
- package/dist/src/migrations.js +470 -0
- package/dist/src/migrations.js.map +1 -0
- package/package.json +2 -2
- package/template/.speculo/README.md +13 -6
- package/template/canonical/canonical-specdev-engineering-cognitive-mentor.md +178 -0
- package/template/canonical/canonical-specdev-goal-plan.md +386 -74
- package/template/canonical/canonical-specdev-grill-with-docs.md +178 -0
- package/template/canonical/canonical-specdev-spec.md +178 -0
- package/template/canonical/canonical-specdev-tickets.md +247 -21
- package/template/canonical/canonical-specdev-wayfinder.md +178 -0
- package/template/commands/migrate-runtime-state.md +43 -0
- package/template/skills/github-npm-ops/references/preflight-checklist.md +1 -1
- package/template/skills/migrate-runtime-state/SKILL.md +93 -0
- package/template/skills/migrate-runtime-state/references/migration-contract.md +58 -0
- package/template/skills/migrate-runtime-state/scripts/migrate-runtime-state.mjs +545 -0
- package/template/skills/optimize-codex-config/SKILL.md +81 -0
- package/template/skills/optimize-codex-config/references/configuration-contract.md +103 -0
- package/template/skills/optimize-codex-config/references/troubleshooting.md +79 -0
- package/template/skills/optimize-codex-config/scripts/audit-codex-config.mjs +747 -0
- package/template/workflows/specdev/I-implement/I-implement.md +11 -10
- package/template/workflows/specdev/I-implement/delegated-evidence-template.md +2 -1
- package/template/workflows/specdev/I-implement/execution-preflight.md +5 -3
- package/template/workflows/specdev/I-implement/merge-conflict-protocol.md +6 -5
- package/template/workflows/specdev/I-init-setup/I-init-setup.md +1 -1
- package/template/workflows/specdev/INDEX.md +13 -9
- package/template/workflows/specdev/P-goal-plan/P-goal-plan.md +27 -18
- package/template/workflows/specdev/P-goal-plan/completion-control.md +3 -3
- package/template/workflows/specdev/P-goal-plan/delegated-execution-template.md +6 -4
- package/template/workflows/specdev/P-goal-plan/delegated-execution.md +13 -7
- package/template/workflows/specdev/P-goal-plan/goal-plan-template.md +11 -2
- package/template/workflows/specdev/P-goal-plan/orchestration-protocol.md +7 -3
- package/template/workflows/specdev/P-goal-plan/planning-modes.md +23 -8
- package/template/workflows/specdev/P-goal-plan/workspace-execution-template.md +24 -0
- package/template/workflows/specdev/common/README.md +2 -2
- package/template/workflows/specdev/common/rules/change-completion.md +3 -2
- package/template/workflows/specdev/common/rules/path-ownership.md +2 -2
- package/template/workflows/specdev/common/schemas/change-status.schema.json +178 -0
- package/template/workflows/specdev/common/schemas/goal-plan.schema.json +10 -0
- package/template/workflows/specdev/common/skills/dev-worktree/SKILL.md +11 -11
- package/template/workflows/specdev/common/skills/dev-worktree/references/create.md +19 -4
- package/template/workflows/specdev/common/skills/dev-worktree/references/finalize.md +12 -5
- package/template/workflows/specdev/common/skills/subagent-delivery/SKILL.md +4 -3
- package/template/workflows/specdev/common/skills/subagent-delivery/references/external-web-subagent.md +1 -1
- package/template/workflows/specdev/common/skills/subagent-delivery/references/native-subagent.md +2 -3
- package/template/workflows/specdev/common/tools/validate-specdev.mjs +218 -5
|
@@ -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.
|
|
4
|
-
"description": "Workflow-packaged specification-driven development assets with
|
|
3
|
+
"version": "0.7.2",
|
|
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`
|
|
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.
|
|
13
|
-
3.
|
|
14
|
-
4.
|
|
15
|
-
5.
|
|
16
|
-
6.
|
|
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 不得创建、修改或删除。
|