agent-method 1.5.12 → 1.5.13
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/bin/wwa.js +1 -1
- package/lib/cli/upgrade.js +131 -0
- package/package.json +1 -1
package/bin/wwa.js
CHANGED
package/lib/cli/upgrade.js
CHANGED
|
@@ -206,6 +206,66 @@ export function register(program) {
|
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
+
// 6. Non-destructive template/schema upgrades (versioned files + backlog)
|
|
210
|
+
//
|
|
211
|
+
// When templates or schemas change, we never overwrite existing project files.
|
|
212
|
+
// Instead we:
|
|
213
|
+
// - Write a versioned file alongside the original (e.g. CLAUDE.v2.md, doc-tokens.v2.yaml)
|
|
214
|
+
// - Add a backlog entry pointing to the new file so the user/agent can migrate.
|
|
215
|
+
|
|
216
|
+
// 6a. Entry point templates (CLAUDE.md / .cursorrules / AGENT.md)
|
|
217
|
+
if (ep) {
|
|
218
|
+
const entryName = basename_of(ep); // e.g. CLAUDE.md
|
|
219
|
+
const templatePath = join(srcDir, entryName);
|
|
220
|
+
if (existsSync(templatePath)) {
|
|
221
|
+
const change = classifyMarkdownChange(templatePath, ep);
|
|
222
|
+
if (change === "present_diverged_user") {
|
|
223
|
+
const v2Path = nextVersionedPath(ep);
|
|
224
|
+
const relV2 = v2Path.replace(d, "").replace(/^[\\/]/, "");
|
|
225
|
+
if (!existsSync(v2Path)) {
|
|
226
|
+
actions.push(`Write versioned entry point template ${relV2}`);
|
|
227
|
+
if (!opts.dryRun) {
|
|
228
|
+
mkdirSync(dirname(v2Path), { recursive: true });
|
|
229
|
+
safeCopyFile(templatePath, v2Path);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
ensureBacklogEntry(
|
|
233
|
+
d,
|
|
234
|
+
relV2,
|
|
235
|
+
`- [ ] **Review new entry point template** — A new version of ${relV2} is available. Review differences and migrate conventions when convenient.`
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// 6b. Registry/doc-tokens schema (YAML)
|
|
242
|
+
const projectTokensPath = join(d, "registry", "doc-tokens.yaml");
|
|
243
|
+
const templateTokensPath = join(
|
|
244
|
+
packageRoot,
|
|
245
|
+
"docs",
|
|
246
|
+
"internal",
|
|
247
|
+
"doc-tokens.yaml"
|
|
248
|
+
);
|
|
249
|
+
if (existsSync(projectTokensPath) && existsSync(templateTokensPath)) {
|
|
250
|
+
const change = classifyYamlChange(templateTokensPath, projectTokensPath);
|
|
251
|
+
if (change === "schema_changed" || change === "present_diverged_user") {
|
|
252
|
+
const v2Path = nextVersionedPath(projectTokensPath);
|
|
253
|
+
const relV2 = v2Path.replace(d, "").replace(/^[\\/]/, "");
|
|
254
|
+
if (!existsSync(v2Path)) {
|
|
255
|
+
actions.push(`Write versioned schema ${relV2}`);
|
|
256
|
+
if (!opts.dryRun) {
|
|
257
|
+
mkdirSync(dirname(v2Path), { recursive: true });
|
|
258
|
+
safeCopyFile(templateTokensPath, v2Path);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
ensureBacklogEntry(
|
|
262
|
+
d,
|
|
263
|
+
relV2,
|
|
264
|
+
`- [ ] **Migrate doc-tokens schema** — New schema written to ${relV2}. Plan migration and update tooling as needed.`
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
209
269
|
// Report
|
|
210
270
|
if (actions.length === 0) {
|
|
211
271
|
console.log(`Project at ${directory} is up to date (v${pkg.version}).`);
|
|
@@ -220,3 +280,74 @@ export function register(program) {
|
|
|
220
280
|
}
|
|
221
281
|
});
|
|
222
282
|
}
|
|
283
|
+
|
|
284
|
+
// ---------------------------------------------------------------------------
|
|
285
|
+
// Helper functions — change classification, versioned paths, backlog entries
|
|
286
|
+
// ---------------------------------------------------------------------------
|
|
287
|
+
|
|
288
|
+
function classifyMarkdownChange(templatePath, projectPath) {
|
|
289
|
+
if (!existsSync(projectPath) || !existsSync(templatePath)) return "missing";
|
|
290
|
+
const tmpl = readFileSync(templatePath, "utf-8");
|
|
291
|
+
const proj = readFileSync(projectPath, "utf-8");
|
|
292
|
+
if (tmpl === proj) return "present_identical";
|
|
293
|
+
return "present_diverged_user";
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function classifyYamlChange(templatePath, projectPath) {
|
|
297
|
+
if (!existsSync(projectPath) || !existsSync(templatePath)) return "missing";
|
|
298
|
+
const tmpl = readFileSync(templatePath, "utf-8");
|
|
299
|
+
const proj = readFileSync(projectPath, "utf-8");
|
|
300
|
+
if (tmpl === proj) return "present_identical";
|
|
301
|
+
// Treat any content difference as a schema-level change for now; this is
|
|
302
|
+
// conservative but guarantees we keep the original file intact.
|
|
303
|
+
return "schema_changed";
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function nextVersionedPath(projectPath) {
|
|
307
|
+
const match = projectPath.match(/^(.*)(\.[^./\\]+)$/);
|
|
308
|
+
const stem = match ? match[1] : projectPath;
|
|
309
|
+
const ext = match ? match[2] : "";
|
|
310
|
+
let counter = 2;
|
|
311
|
+
// Generate stem.v2.ext, stem.v3.ext, ... until we find a free path
|
|
312
|
+
// (e.g. CLAUDE.v2.md, doc-tokens.v2.yaml).
|
|
313
|
+
// eslint-disable-next-line no-constant-condition
|
|
314
|
+
while (true) {
|
|
315
|
+
const candidate = `${stem}.v${counter}${ext}`;
|
|
316
|
+
if (!existsSync(candidate)) return candidate;
|
|
317
|
+
counter += 1;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function ensureBacklogEntry(projectDir, markerPath, line) {
|
|
322
|
+
const backlogCandidates = [
|
|
323
|
+
join(projectDir, "todos", "backlog.md"),
|
|
324
|
+
join(projectDir, "backlog.md"),
|
|
325
|
+
];
|
|
326
|
+
|
|
327
|
+
let targetPath = null;
|
|
328
|
+
let content = "";
|
|
329
|
+
|
|
330
|
+
for (const p of backlogCandidates) {
|
|
331
|
+
if (existsSync(p)) {
|
|
332
|
+
const existing = readFileSync(p, "utf-8");
|
|
333
|
+
if (existing.includes(markerPath)) {
|
|
334
|
+
return; // entry already present
|
|
335
|
+
}
|
|
336
|
+
targetPath = p;
|
|
337
|
+
content = existing;
|
|
338
|
+
break;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
if (!targetPath) {
|
|
343
|
+
targetPath = backlogCandidates[0];
|
|
344
|
+
mkdirSync(dirname(targetPath), { recursive: true });
|
|
345
|
+
content = "# Backlog\n\n";
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
if (content && !content.endsWith("\n")) {
|
|
349
|
+
content += "\n";
|
|
350
|
+
}
|
|
351
|
+
content += `${line}\n`;
|
|
352
|
+
safeWriteFile(targetPath, content, "utf-8");
|
|
353
|
+
}
|
package/package.json
CHANGED