agent-method 1.5.5 → 1.5.6

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 (62) hide show
  1. package/README.md +68 -40
  2. package/bin/wwa.js +35 -9
  3. package/docs/internal/doc-tokens.yaml +452 -0
  4. package/docs/internal/feature-registry.yaml +13 -1
  5. package/lib/cli/casestudy.js +691 -0
  6. package/lib/cli/check.js +1 -1
  7. package/lib/cli/close.js +446 -0
  8. package/lib/cli/completion.js +639 -0
  9. package/lib/cli/digest.js +66 -0
  10. package/lib/cli/docs.js +207 -0
  11. package/lib/cli/helpers.js +49 -2
  12. package/lib/cli/implement.js +159 -0
  13. package/lib/cli/init.js +25 -6
  14. package/lib/cli/plan.js +128 -0
  15. package/lib/cli/refine.js +4 -4
  16. package/lib/cli/review.js +68 -0
  17. package/lib/cli/scan.js +2 -2
  18. package/lib/cli/status.js +1 -1
  19. package/lib/cli/upgrade.js +8 -7
  20. package/lib/init.js +205 -23
  21. package/package.json +10 -3
  22. package/templates/README.md +70 -22
  23. package/templates/entry-points/.cursorrules +142 -13
  24. package/templates/entry-points/AGENT.md +142 -13
  25. package/templates/entry-points/CLAUDE.md +142 -13
  26. package/templates/extensions/analytical-system.md +1 -1
  27. package/templates/extensions/code-project.md +1 -1
  28. package/templates/extensions/data-exploration.md +1 -1
  29. package/templates/full/.context/BASE.md +33 -0
  30. package/templates/full/.context/METHODOLOGY.md +62 -5
  31. package/templates/full/.cursorrules +127 -17
  32. package/templates/full/AGENT.md +127 -17
  33. package/templates/full/CLAUDE.md +127 -17
  34. package/templates/full/Management/DIGEST.md +23 -0
  35. package/templates/full/Management/STATUS.md +46 -0
  36. package/templates/full/PROJECT.md +34 -0
  37. package/templates/full/Reviews/INDEX.md +41 -0
  38. package/templates/full/Reviews/backlog.md +52 -0
  39. package/templates/full/Reviews/plan.md +43 -0
  40. package/templates/full/Reviews/project.md +41 -0
  41. package/templates/full/Reviews/requirements.md +42 -0
  42. package/templates/full/Reviews/roadmap.md +41 -0
  43. package/templates/full/Reviews/state.md +56 -0
  44. package/templates/full/SUMMARY.md +7 -4
  45. package/templates/full/agentWorkflows/INDEX.md +42 -0
  46. package/templates/full/agentWorkflows/observations.md +65 -0
  47. package/templates/full/agentWorkflows/patterns.md +68 -0
  48. package/templates/full/agentWorkflows/sessions.md +92 -0
  49. package/templates/full/intro/README.md +39 -0
  50. package/templates/starter/.context/BASE.md +35 -0
  51. package/templates/starter/.context/METHODOLOGY.md +59 -5
  52. package/templates/starter/.cursorrules +134 -12
  53. package/templates/starter/AGENT.md +134 -12
  54. package/templates/starter/CLAUDE.md +134 -12
  55. package/templates/starter/Management/DIGEST.md +23 -0
  56. package/templates/starter/Management/STATUS.md +46 -0
  57. package/templates/starter/PROJECT.md +34 -0
  58. package/templates/starter/Reviews/INDEX.md +75 -0
  59. package/templates/starter/SUMMARY.md +27 -0
  60. package/templates/starter/agentWorkflows/INDEX.md +61 -0
  61. package/templates/starter/intro/README.md +37 -0
  62. package/templates/full/docs/index.md +0 -46
package/lib/cli/refine.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /** wwa refine — extract refinement report from session history. */
2
2
 
3
- import { readFileSync, existsSync, writeFileSync } from "node:fs";
4
- import { findSessionLog } from "./helpers.js";
3
+ import { readFileSync, existsSync } from "node:fs";
4
+ import { findSessionLog, safeWriteFile } from "./helpers.js";
5
5
 
6
6
  export function register(program) {
7
7
  program
@@ -15,7 +15,7 @@ export function register(program) {
15
15
  if (!sessionLog) {
16
16
  console.error(
17
17
  "No SESSION-LOG.md found in current directory.\n" +
18
- "Specify a path: npx agent-method refine path/to/SESSION-LOG.md"
18
+ "Specify a path: wwa refine path/to/SESSION-LOG.md"
19
19
  );
20
20
  process.exit(1);
21
21
  }
@@ -37,7 +37,7 @@ export function register(program) {
37
37
  }
38
38
 
39
39
  if (opts.output) {
40
- writeFileSync(opts.output, result, "utf-8");
40
+ safeWriteFile(opts.output, result, "utf-8");
41
41
  console.log(
42
42
  `Refinement report written to ${opts.output} (${parsed.entries.length} sessions)`
43
43
  );
@@ -0,0 +1,68 @@
1
+ /** wwa review — display project review dashboard. */
2
+
3
+ import { readFileSync, existsSync } from "node:fs";
4
+ import { resolve, join } from "node:path";
5
+
6
+ export function register(program) {
7
+ program
8
+ .command("review [directory]")
9
+ .description("Display project review dashboard from Reviews/INDEX.md")
10
+ .option("--json", "Output as JSON")
11
+ .action(async (directory, opts) => {
12
+ directory = directory || ".";
13
+ const d = resolve(directory);
14
+
15
+ const reviewIndex = join(d, "Reviews", "INDEX.md");
16
+ const hasReviews = existsSync(reviewIndex);
17
+
18
+ // Fallback: synthesize from intelligence layer files
19
+ const sources = {
20
+ roadmap: join(d, "ROADMAP.md"),
21
+ plan: join(d, "PLAN.md"),
22
+ state: join(d, "STATE.md"),
23
+ requirements: join(d, "REQUIREMENTS.md"),
24
+ backlog: join(d, "todos", "backlog.md"),
25
+ };
26
+
27
+ const available = {};
28
+ for (const [key, path] of Object.entries(sources)) {
29
+ available[key] = existsSync(path);
30
+ }
31
+
32
+ if (opts.json) {
33
+ const data = { hasReviewsDir: hasReviews, available };
34
+ if (hasReviews) {
35
+ data.indexContent = readFileSync(reviewIndex, "utf-8");
36
+ }
37
+ console.log(JSON.stringify(data, null, 2));
38
+ return;
39
+ }
40
+
41
+ if (hasReviews) {
42
+ // Display Reviews/INDEX.md content
43
+ const content = readFileSync(reviewIndex, "utf-8");
44
+ console.log(content);
45
+ return;
46
+ }
47
+
48
+ // Synthesize a quick review from available files
49
+ console.log("\n Project Review Dashboard\n");
50
+ console.log(" No Reviews/ directory found. Showing available sources:\n");
51
+
52
+ for (const [key, path] of Object.entries(sources)) {
53
+ if (available[key]) {
54
+ const content = readFileSync(path, "utf-8");
55
+ const lines = content.split("\n").length;
56
+ const title = content.match(/^#\s+(.+)$/m)?.[1] || key;
57
+ console.log(` [+] ${key.padEnd(14)} ${title} (${lines} lines)`);
58
+ } else {
59
+ console.log(` [ ] ${key.padEnd(14)} not found`);
60
+ }
61
+ }
62
+
63
+ console.log(
64
+ "\n To get full reviews, use the full template tier:" +
65
+ "\n wwa init <type> --tier full\n"
66
+ );
67
+ });
68
+ }
package/lib/cli/scan.js CHANGED
@@ -17,9 +17,9 @@ export function register(program) {
17
17
  const friendlyMap = { analytical: "context", mixed: "mix" };
18
18
  if (ptype in friendlyMap) {
19
19
  result.friendly_name = friendlyMap[ptype];
20
- result.init_command = `npx agent-method init ${friendlyMap[ptype]}`;
20
+ result.init_command = `wwa init ${friendlyMap[ptype]}`;
21
21
  } else {
22
- result.init_command = `npx agent-method init ${ptype}`;
22
+ result.init_command = `wwa init ${ptype}`;
23
23
  }
24
24
 
25
25
  console.log(`Scanning: ${directory}`);
package/lib/cli/status.js CHANGED
@@ -38,7 +38,7 @@ export function register(program) {
38
38
  message =
39
39
  `Entry point ${basename_of(ep)} is outdated ` +
40
40
  `(method_version: ${epVersion}, installed: ${installed}). ` +
41
- `Run \`npx agent-method upgrade ${directory}\` to update.`;
41
+ `Run \`wwa upgrade ${directory}\` to update.`;
42
42
  }
43
43
 
44
44
  if (opts.json) {
@@ -1,11 +1,12 @@
1
1
  /** wwa upgrade — brownfield-safe methodology update. */
2
2
 
3
3
  import {
4
- readFileSync, existsSync, copyFileSync, mkdirSync, writeFileSync,
4
+ readFileSync, existsSync, mkdirSync,
5
5
  } from "node:fs";
6
6
  import { resolve, join, dirname } from "node:path";
7
7
  import {
8
8
  findEntryPoint, readMethodVersion, basename_of, pkg, packageRoot,
9
+ safeWriteFile, safeCopyFile,
9
10
  } from "./helpers.js";
10
11
 
11
12
  export function register(program) {
@@ -55,7 +56,7 @@ export function register(program) {
55
56
  );
56
57
  if (!opts.dryRun) {
57
58
  content = content.replace(/(method_version:\s*)\S+/, `$1${newVer}`);
58
- writeFileSync(ep, content, "utf-8");
59
+ safeWriteFile(ep, content, "utf-8");
59
60
  }
60
61
  } else if (!currentVer) {
61
62
  actions.push(`Add method_version: ${newVer} to ${basename_of(ep)}`);
@@ -65,9 +66,9 @@ export function register(program) {
65
66
  `## Method version\n\n` +
66
67
  `method_version: ${newVer}\n` +
67
68
  `<!-- Tracks which methodology version generated this entry point -->\n` +
68
- `<!-- Use \`npx agent-method status\` to compare against latest -->\n\n`;
69
+ `<!-- Use \`wwa status\` to compare against latest -->\n\n`;
69
70
  content = content.replace("## Conventions", insert + "## Conventions");
70
- writeFileSync(ep, content, "utf-8");
71
+ safeWriteFile(ep, content, "utf-8");
71
72
  }
72
73
  }
73
74
  }
@@ -86,7 +87,7 @@ export function register(program) {
86
87
  actions.push(`Create ${fname} (new)`);
87
88
  if (!opts.dryRun) {
88
89
  mkdirSync(dirname(dst), { recursive: true });
89
- copyFileSync(src, dst);
90
+ safeCopyFile(src, dst);
90
91
  }
91
92
  }
92
93
  }
@@ -104,7 +105,7 @@ export function register(program) {
104
105
  " \u2014 effort, ambiguity, context level, tokens, time, user response, refinement delta, workflow, features, cascades, friction, findings) " +
105
106
  "|\n\n<!-- INSTRUCTION: Add project-specific cascade"
106
107
  );
107
- writeFileSync(ep, content, "utf-8");
108
+ safeWriteFile(ep, content, "utf-8");
108
109
  }
109
110
  }
110
111
  }
@@ -127,7 +128,7 @@ export function register(program) {
127
128
  "previous entries during normal work\n\n" +
128
129
  "## Do not"
129
130
  );
130
- writeFileSync(ep, content, "utf-8");
131
+ safeWriteFile(ep, content, "utf-8");
131
132
  }
132
133
  }
133
134
  }
package/lib/init.js CHANGED
@@ -5,9 +5,23 @@
5
5
  * prompts for project configuration.
6
6
  */
7
7
 
8
- import { existsSync, mkdirSync, copyFileSync, readFileSync, writeFileSync, readdirSync, unlinkSync } from "node:fs";
8
+ import { existsSync, mkdirSync, readFileSync, readdirSync, unlinkSync, copyFileSync, writeFileSync } from "node:fs";
9
9
  import { resolve, join, dirname, basename, relative } from "node:path";
10
10
  import { fileURLToPath } from "node:url";
11
+ import { safeCopyFile, safeWriteFile } from "./cli/helpers.js";
12
+
13
+ /** Entry point filenames that bypass the extension-based safety check. */
14
+ const ENTRY_POINT_NAMES = new Set(["CLAUDE.md", ".cursorrules", "AGENT.md"]);
15
+
16
+ /** Write file — allows entry points (e.g. .cursorrules) plus safe extensions. */
17
+ function writeInitFile(filePath, content, encoding = "utf-8") {
18
+ const name = basename(filePath);
19
+ if (ENTRY_POINT_NAMES.has(name)) {
20
+ writeFileSync(filePath, content, encoding);
21
+ } else {
22
+ safeWriteFile(filePath, content, encoding);
23
+ }
24
+ }
11
25
 
12
26
  const __filename = fileURLToPath(import.meta.url);
13
27
  const __dirname = dirname(__filename);
@@ -36,7 +50,7 @@ const RUNTIME_ENTRY_POINTS = {
36
50
  * Set up a new project with methodology templates.
37
51
  */
38
52
  export async function initProject(projectType, directory, opts = {}) {
39
- const { tier = "starter", runtime = "all", profile = "standard", registryPath } = opts;
53
+ const { tier = "starter", runtime = "all", profile = "standard", onboarding = "auto", registryPath } = opts;
40
54
  const targetDir = resolve(directory);
41
55
  const methodRoot = resolve(__dirname, "..");
42
56
 
@@ -47,16 +61,25 @@ export async function initProject(projectType, directory, opts = {}) {
47
61
  }
48
62
 
49
63
  console.log(`\nSetting up ${FRIENDLY_NAMES[projectType] || projectType} project`);
50
- console.log(` Template: ${tier}`);
51
- console.log(` Profile: ${profile}`);
52
- console.log(` Runtime: ${runtime}`);
53
- console.log(` Target: ${targetDir}\n`);
64
+ console.log(` Template: ${tier}`);
65
+ console.log(` Profile: ${profile}`);
66
+ console.log(` Runtime: ${runtime}`);
67
+ console.log(` Onboarding: ${onboarding}`);
68
+ console.log(` Target: ${targetDir}\n`);
69
+
70
+ // Determine brownfield mode from user selection or auto-detection
71
+ let isBrownfield;
72
+ if (onboarding === "brownfield") {
73
+ isBrownfield = true;
74
+ } else if (onboarding === "greenfield") {
75
+ isBrownfield = false;
76
+ } else {
77
+ // auto — detect from existing files
78
+ isBrownfield = detectBrownfield(targetDir);
79
+ }
54
80
 
55
- // Detect brownfield (existing project with methodology files)
56
- const isBrownfield = detectBrownfield(targetDir);
57
81
  if (isBrownfield) {
58
- console.log(" Detected existing methodology files (brownfield mode)");
59
- console.log(" Will append to existing entry points, not overwrite.\n");
82
+ console.log(" Brownfield mode — will append to existing entry points, not overwrite.\n");
60
83
  }
61
84
 
62
85
  // Create target directory
@@ -65,7 +88,7 @@ export async function initProject(projectType, directory, opts = {}) {
65
88
  // Copy template files
66
89
  const copied = [];
67
90
  const skipped = [];
68
- copyTemplateDir(templateDir, targetDir, copied, skipped, isBrownfield);
91
+ copyTemplateDir(templateDir, targetDir, copied, skipped, isBrownfield, runtime);
69
92
 
70
93
  // Apply extensions based on project type
71
94
  const extensions = getExtensions(projectType);
@@ -77,12 +100,21 @@ export async function initProject(projectType, directory, opts = {}) {
77
100
  }
78
101
  }
79
102
 
103
+ // Copy feature-registry.yaml to user project (populated, from package)
104
+ copyFeatureRegistry(methodRoot, targetDir, copied);
105
+
106
+ // Create project-specific doc-tokens.yaml with initial values
107
+ createProjectTokens(targetDir, projectType, tier, profile, onboarding, copied);
108
+
80
109
  // Replace placeholders in entry points
81
110
  replacePlaceholders(targetDir, projectType, tier);
82
111
 
83
112
  // Set integration profile in entry points
84
113
  setProfile(targetDir, profile);
85
114
 
115
+ // Set onboarding scenario in PROJECT-PROFILE.md
116
+ setOnboardingScenario(targetDir, onboarding, isBrownfield, projectType);
117
+
86
118
  // Remove unused entry points based on runtime choice
87
119
  const removed = removeUnusedEntryPoints(targetDir, runtime, isBrownfield);
88
120
 
@@ -104,14 +136,21 @@ export async function initProject(projectType, directory, opts = {}) {
104
136
  : "CLAUDE.md / .cursorrules / AGENT.md";
105
137
 
106
138
  console.log(`\nNext steps:`);
107
- console.log(` 1. cd ${relative(process.cwd(), targetDir) || "."}`);
108
- console.log(` 2. Fill in PROJECT.md with your project vision`);
139
+ let step = 1;
140
+ console.log(` ${step++}. cd ${relative(process.cwd(), targetDir) || "."}`);
109
141
  if (runtime === "all") {
110
- console.log(` 3. Delete the two entry point files you don't use`);
142
+ console.log(` ${step++}. Delete the two entry point files you don't use`);
111
143
  console.log(` (keep CLAUDE.md, .cursorrules, or AGENT.md)`);
112
144
  }
113
- console.log(` ${runtime === "all" ? "4" : "3"}. Start a conversation the agent reads ${keptEntry} automatically`);
114
- console.log(`\nVerify: npx agent-method check`);
145
+ console.log(` ${step++}. Start a conversation with your agent — it reads ${keptEntry} automatically`);
146
+ if (isBrownfield) {
147
+ console.log(` The agent will scan your codebase and walk you through 5 onboarding stages`);
148
+ console.log(` (scan → clarify → map → organize → starting state)`);
149
+ } else {
150
+ console.log(` The agent will walk you through 4 onboarding stages`);
151
+ console.log(` (vision → architecture → goals → starting state)`);
152
+ }
153
+ console.log(`\nVerify: wwa check`);
115
154
  }
116
155
 
117
156
  function detectBrownfield(dir) {
@@ -124,7 +163,7 @@ function detectBrownfield(dir) {
124
163
  return count >= 2;
125
164
  }
126
165
 
127
- function copyTemplateDir(src, dst, copied, skipped, isBrownfield) {
166
+ function copyTemplateDir(src, dst, copied, skipped, isBrownfield, runtime) {
128
167
  if (!existsSync(src)) return;
129
168
  mkdirSync(dst, { recursive: true });
130
169
 
@@ -133,11 +172,24 @@ function copyTemplateDir(src, dst, copied, skipped, isBrownfield) {
133
172
  const dstPath = join(dst, entry.name);
134
173
 
135
174
  if (entry.isDirectory()) {
136
- copyTemplateDir(srcPath, dstPath, copied, skipped, isBrownfield);
175
+ copyTemplateDir(srcPath, dstPath, copied, skipped, isBrownfield, runtime);
137
176
  } else {
138
177
  // Entry points: special handling in brownfield
139
178
  const isEntryPoint = ["CLAUDE.md", ".cursorrules", "AGENT.md"].includes(entry.name);
140
179
 
180
+ // Skip entry points that won't be kept (avoids safety invariant issue with .cursorrules)
181
+ if (isEntryPoint && runtime !== "all" && !isBrownfield) {
182
+ const keep = RUNTIME_ENTRY_POINTS[runtime];
183
+ if (keep && entry.name !== keep) continue;
184
+ }
185
+
186
+ // Defer heavy infrastructure files in brownfield to reduce first-session load
187
+ const isDeferredInBrownfield = isBrownfield && entry.name === "REGISTRY.md";
188
+ if (isDeferredInBrownfield) {
189
+ skipped.push(`${relative(dst, dstPath)} (deferred — created on first file split)`);
190
+ continue;
191
+ }
192
+
141
193
  if (existsSync(dstPath)) {
142
194
  if (isEntryPoint && isBrownfield) {
143
195
  // Append methodology sections to existing entry point
@@ -146,9 +198,13 @@ function copyTemplateDir(src, dst, copied, skipped, isBrownfield) {
146
198
  } else {
147
199
  skipped.push(relative(dst, dstPath));
148
200
  }
149
- } else {
201
+ } else if (isEntryPoint) {
202
+ // Entry points bypass safeCopyFile (e.g. .cursorrules has no .md extension)
150
203
  copyFileSync(srcPath, dstPath);
151
204
  copied.push(relative(dst, dstPath));
205
+ } else {
206
+ safeCopyFile(srcPath, dstPath);
207
+ copied.push(relative(dst, dstPath));
152
208
  }
153
209
  }
154
210
  }
@@ -176,7 +232,7 @@ function appendToEntryPoint(srcPath, dstPath) {
176
232
  }
177
233
  }
178
234
 
179
- writeFileSync(dstPath, dstContent, "utf-8");
235
+ writeInitFile(dstPath, dstContent, "utf-8");
180
236
  }
181
237
 
182
238
  function getExtensions(projectType) {
@@ -242,7 +298,7 @@ function mergeExtension(extFile, targetDir, isBrownfield) {
242
298
  }
243
299
  }
244
300
 
245
- writeFileSync(epPath, epContent, "utf-8");
301
+ writeInitFile(epPath, epContent, "utf-8");
246
302
  }
247
303
  }
248
304
 
@@ -260,7 +316,7 @@ function replacePlaceholders(targetDir, projectType, tier) {
260
316
  // Set template tier
261
317
  content = content.replace(/template_tier:\s*\S+/, `template_tier: ${tier}`);
262
318
 
263
- writeFileSync(epPath, content, "utf-8");
319
+ writeInitFile(epPath, content, "utf-8");
264
320
  }
265
321
  }
266
322
 
@@ -271,10 +327,136 @@ function setProfile(targetDir, profile) {
271
327
 
272
328
  let content = readFileSync(epPath, "utf-8");
273
329
  content = content.replace(/tier:\s*(lite|standard|full)/, `tier: ${profile}`);
274
- writeFileSync(epPath, content, "utf-8");
330
+ writeInitFile(epPath, content, "utf-8");
275
331
  }
276
332
  }
277
333
 
334
+ function setOnboardingScenario(targetDir, onboarding, isBrownfield, projectType) {
335
+ const profilePath = join(targetDir, "PROJECT-PROFILE.md");
336
+ if (!existsSync(profilePath)) return;
337
+
338
+ let content = readFileSync(profilePath, "utf-8");
339
+
340
+ // Set lifecycle stage based on scenario
341
+ const stage = isBrownfield ? "discovery" : "design";
342
+ content = content.replace(/\*\*Stage\*\*:\s*\{stage\}/, `**Stage**: ${stage}`);
343
+ content = content.replace(/\*\*Maturity\*\*:\s*\{maturity\}/, `**Maturity**: new`);
344
+
345
+ const today = new Date().toISOString().slice(0, 10);
346
+ content = content.replace(
347
+ /\*\*Last transition\*\*:\s*\{date\}.*$/m,
348
+ `**Last transition**: ${today} (setup -> ${stage})`
349
+ );
350
+
351
+ // Set project type
352
+ content = content.replace(/\[{project-type}\]/, `[${projectType}]`);
353
+
354
+ // Set onboarding hint so the agent knows which first-session flow
355
+ const scenario = onboarding === "auto"
356
+ ? (isBrownfield ? "brownfield (auto-detected)" : "greenfield (auto-detected)")
357
+ : onboarding;
358
+
359
+ // Add onboarding scenario after lifecycle section
360
+ if (!content.includes("**Onboarding**")) {
361
+ content = content.replace(
362
+ /(\*\*Last transition\*\*:.*$)/m,
363
+ `$1\n- **Onboarding**: ${scenario}`
364
+ );
365
+ }
366
+
367
+ // Set extension stack
368
+ const extensions = getExtensions(projectType);
369
+ const extNames = extensions.map(e => e.replace(".md", ""));
370
+ content = content.replace(/\[{extensions-applied}\]/, `[${extNames.join(", ") || "none"}]`);
371
+
372
+ for (const ext of ["code-project", "data-exploration", "analytical-system"]) {
373
+ const isActive = extNames.includes(ext) ? "yes" : "no";
374
+ const source = extNames.includes(ext) ? "wwa init" : "—";
375
+ content = content.replace(
376
+ new RegExp(`\\| ${ext} \\| \\{yes/no\\} \\| \\{setup\\.sh / manual\\} \\|`),
377
+ `| ${ext} | ${isActive} | ${source} |`
378
+ );
379
+ }
380
+
381
+ safeWriteFile(profilePath, content, "utf-8");
382
+ }
383
+
384
+ function createProjectTokens(targetDir, projectType, tier, profile, onboarding, copied) {
385
+ const ctxDir = join(targetDir, ".context");
386
+ mkdirSync(ctxDir, { recursive: true });
387
+ const dst = join(ctxDir, "doc-tokens.yaml");
388
+ if (existsSync(dst)) return; // don't overwrite
389
+
390
+ const today = new Date().toISOString().slice(0, 10);
391
+
392
+ // Count files that were actually created
393
+ const mdFiles = [];
394
+ const countMdFiles = (dir) => {
395
+ if (!existsSync(dir)) return;
396
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
397
+ const p = join(dir, entry.name);
398
+ if (entry.isDirectory()) countMdFiles(p);
399
+ else if (entry.name.endsWith(".md") || entry.name.endsWith(".yaml") || entry.name.endsWith(".yml")) {
400
+ mdFiles.push(relative(targetDir, p).replace(/\\/g, "/"));
401
+ }
402
+ }
403
+ };
404
+ countMdFiles(targetDir);
405
+
406
+ const content = [
407
+ "# Project Token Registry",
408
+ "# Computed by wwa init. Updated by wwa close.",
409
+ "# Used by wwa casestudy for methodology reference data.",
410
+ "#",
411
+ "# Agent: read this before writing docs. Check values are current.",
412
+ "",
413
+ "tokens:",
414
+ "",
415
+ " # --- Project identity ---",
416
+ ` project_type: ${projectType}`,
417
+ ` template_tier: ${tier}`,
418
+ ` integration_profile: ${profile}`,
419
+ ` onboarding: ${onboarding}`,
420
+ ` created: "${today}"`,
421
+ ` last_close: "${today}"`,
422
+ "",
423
+ " # --- File counts (updated at close) ---",
424
+ ` methodology_file_count: ${mdFiles.length}`,
425
+ " docs_file_count: 0",
426
+ " context_file_count: 0",
427
+ "",
428
+ " # --- Session metrics (updated at close) ---",
429
+ " session_count: 0",
430
+ " decision_count: 0",
431
+ " total_features_referenced: 0",
432
+ "",
433
+ " # --- Scale indicators (updated at close) ---",
434
+ " files_near_threshold: 0 # files with 250+ lines",
435
+ " files_over_threshold: 0 # files with 300+ lines (need splitting)",
436
+ "",
437
+ " # --- Docs coverage (updated at close) ---",
438
+ " docs_inventory_count: 0",
439
+ " docs_on_disk: 0",
440
+ " docs_missing: 0",
441
+ " component_mappings: 0",
442
+ "",
443
+ ].join("\n");
444
+
445
+ safeWriteFile(dst, content, "utf-8");
446
+ copied.push(".context/doc-tokens.yaml");
447
+ }
448
+
449
+ function copyFeatureRegistry(methodRoot, targetDir, copied) {
450
+ const src = join(methodRoot, "docs", "internal", "feature-registry.yaml");
451
+ if (!existsSync(src)) return;
452
+ const ctxDir = join(targetDir, ".context");
453
+ mkdirSync(ctxDir, { recursive: true });
454
+ const dst = join(ctxDir, "feature-registry.yaml");
455
+ if (existsSync(dst)) return; // don't overwrite existing
456
+ safeCopyFile(src, dst);
457
+ copied.push(".context/feature-registry.yaml");
458
+ }
459
+
278
460
  function removeUnusedEntryPoints(targetDir, runtime, isBrownfield) {
279
461
  if (runtime === "all" || isBrownfield) return [];
280
462
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-method",
3
- "version": "1.5.5",
3
+ "version": "1.5.6",
4
4
  "description": "CLI tools for the wwa methodology — registry-driven routing, validation, and project setup for AI-agent-assisted development",
5
5
  "keywords": [
6
6
  "ai-agents",
@@ -8,7 +8,13 @@
8
8
  "context-engineering",
9
9
  "methodology",
10
10
  "developer-tools",
11
- "cli"
11
+ "cli",
12
+ "claude-code",
13
+ "cursor",
14
+ "gemini",
15
+ "codex",
16
+ "mcp",
17
+ "agent-framework"
12
18
  ],
13
19
  "type": "module",
14
20
  "license": "MIT",
@@ -21,7 +27,8 @@
21
27
  "bin/",
22
28
  "lib/",
23
29
  "templates/",
24
- "docs/internal/feature-registry.yaml"
30
+ "docs/internal/feature-registry.yaml",
31
+ "docs/internal/doc-tokens.yaml"
25
32
  ],
26
33
  "main": "lib/registry.js",
27
34
  "engines": {