agent-method 1.5.3 → 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.

Potentially problematic release.


This version of agent-method might be problematic. Click here for more details.

Files changed (64) hide show
  1. package/README.md +197 -57
  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 +71 -71
  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 +202 -202
  16. package/lib/cli/review.js +68 -0
  17. package/lib/cli/scan.js +28 -28
  18. package/lib/cli/status.js +61 -61
  19. package/lib/cli/upgrade.js +150 -147
  20. package/lib/init.js +478 -296
  21. package/package.json +12 -4
  22. package/templates/README.md +73 -25
  23. package/templates/entry-points/.cursorrules +143 -14
  24. package/templates/entry-points/AGENT.md +143 -14
  25. package/templates/entry-points/CLAUDE.md +143 -14
  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 +128 -18
  32. package/templates/full/AGENT.md +128 -18
  33. package/templates/full/CLAUDE.md +128 -18
  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/SESSION-LOG.md +29 -0
  45. package/templates/full/SUMMARY.md +7 -4
  46. package/templates/full/agentWorkflows/INDEX.md +42 -0
  47. package/templates/full/agentWorkflows/observations.md +65 -0
  48. package/templates/full/agentWorkflows/patterns.md +68 -0
  49. package/templates/full/agentWorkflows/sessions.md +92 -0
  50. package/templates/full/intro/README.md +39 -0
  51. package/templates/starter/.context/BASE.md +35 -0
  52. package/templates/starter/.context/METHODOLOGY.md +59 -5
  53. package/templates/starter/.cursorrules +135 -13
  54. package/templates/starter/AGENT.md +135 -13
  55. package/templates/starter/CLAUDE.md +135 -13
  56. package/templates/starter/Management/DIGEST.md +23 -0
  57. package/templates/starter/Management/STATUS.md +46 -0
  58. package/templates/starter/PROJECT.md +34 -0
  59. package/templates/starter/Reviews/INDEX.md +75 -0
  60. package/templates/starter/SESSION-LOG.md +29 -0
  61. package/templates/starter/SUMMARY.md +27 -0
  62. package/templates/starter/agentWorkflows/INDEX.md +61 -0
  63. package/templates/starter/intro/README.md +37 -0
  64. package/templates/full/docs/index.md +0 -46
package/lib/cli/refine.js CHANGED
@@ -1,202 +1,202 @@
1
- /** wwa refine — extract refinement report from session history. */
2
-
3
- import { readFileSync, existsSync, writeFileSync } from "node:fs";
4
- import { findSessionLog } from "./helpers.js";
5
-
6
- export function register(program) {
7
- program
8
- .command("refine [session-log]")
9
- .description("Extract a refinement report from session history")
10
- .option("-o, --output <path>", "Output file (default: stdout)")
11
- .option("--json", "Output as JSON")
12
- .action(async (sessionLog, opts) => {
13
- if (!sessionLog) {
14
- sessionLog = findSessionLog(".");
15
- if (!sessionLog) {
16
- console.error(
17
- "No SESSION-LOG.md found in current directory.\n" +
18
- "Specify a path: npx wwa refine path/to/SESSION-LOG.md"
19
- );
20
- process.exit(1);
21
- }
22
- }
23
-
24
- if (!existsSync(sessionLog)) {
25
- console.error(`File not found: ${sessionLog}`);
26
- process.exit(1);
27
- }
28
-
29
- const content = readFileSync(sessionLog, "utf-8");
30
- const parsed = parseSessionLog(content);
31
-
32
- let result;
33
- if (opts.json) {
34
- result = JSON.stringify(parsed, null, 2);
35
- } else {
36
- result = generateRefinementReport(parsed);
37
- }
38
-
39
- if (opts.output) {
40
- writeFileSync(opts.output, result, "utf-8");
41
- console.log(
42
- `Refinement report written to ${opts.output} (${parsed.entries.length} sessions)`
43
- );
44
- } else {
45
- console.log(result);
46
- }
47
- });
48
- }
49
-
50
- // ---------------------------------------------------------------------------
51
- // Session log parsing
52
- // ---------------------------------------------------------------------------
53
-
54
- function parseSessionLog(content) {
55
- const context = {};
56
- const ctxMatch = content.match(
57
- /## Project context\s*\n\s*\|[^\n]+\n\s*\|[-| ]+\n((?:\|[^\n]+\n)*)/
58
- );
59
- if (ctxMatch) {
60
- for (const row of ctxMatch[1].trim().split("\n")) {
61
- const cols = row
62
- .split("|")
63
- .map((c) => c.trim())
64
- .filter((c) => c);
65
- if (cols.length >= 2) {
66
- context[cols[0].toLowerCase()] = cols[1];
67
- }
68
- }
69
- }
70
-
71
- const entries = [];
72
- const entryPattern =
73
- /###\s+S(\d+)\s*(?:\u2014|--)\s*(\S+)\s*(?:\u2014|--)\s*(.+?)$(.*?)(?=###\s+S\d+|$)/gms;
74
- let m;
75
- while ((m = entryPattern.exec(content)) !== null) {
76
- const [, num, date, title, body] = m;
77
- const entry = { session: parseInt(num, 10), date, title: title.trim() };
78
-
79
- for (const line of body.split("\n")) {
80
- const trimmed = line.trim();
81
- if (!trimmed || trimmed.startsWith("#")) continue;
82
- const segments = trimmed.split("|").map((s) => s.trim());
83
- for (const seg of segments) {
84
- if (seg.includes(":")) {
85
- const idx = seg.indexOf(":");
86
- const key = seg.slice(0, idx).trim().toLowerCase();
87
- const val = seg.slice(idx + 1).trim();
88
- if (
89
- [
90
- "model", "profile", "workflow", "queries",
91
- "features", "cascades", "decisions", "friction", "finding",
92
- ].includes(key)
93
- ) {
94
- entry[key] = val;
95
- }
96
- }
97
- }
98
- }
99
- entries.push(entry);
100
- }
101
-
102
- return { context, entries };
103
- }
104
-
105
- function generateRefinementReport(parsed) {
106
- const ctx = parsed.context;
107
- const entries = parsed.entries;
108
-
109
- const project = ctx["project name"] || "Unknown";
110
- const ptype = ctx["project type"] || "unknown";
111
- const profile = ctx["integration profile"] || "unknown";
112
- const extensions = ctx["extension(s)"] || "none";
113
-
114
- const workflows = new Set();
115
- let totalFriction = 0;
116
- let totalFindings = 0;
117
- const findingsList = [];
118
- const frictionList = [];
119
-
120
- for (const e of entries) {
121
- if (e.workflow) workflows.add(e.workflow);
122
- const friction = e.friction || "none";
123
- if (friction.toLowerCase() !== "none" && friction) {
124
- totalFriction++;
125
- frictionList.push(`S${e.session} (${e.date}): ${friction}`);
126
- }
127
- const finding = e.finding || "none";
128
- if (finding.toLowerCase() !== "none" && finding) {
129
- totalFindings++;
130
- findingsList.push(`S${e.session} (${e.date}): ${finding}`);
131
- }
132
- }
133
-
134
- const wfSorted = [...workflows].sort().join(", ") || "none";
135
- const lines = [
136
- `# Refinement Report: ${project}`,
137
- "",
138
- "Auto-generated from SESSION-LOG.md by `wwa refine`.",
139
- "",
140
- "## Source",
141
- "",
142
- "| Field | Value |",
143
- "|-------|-------|",
144
- `| Project type | ${ptype} |`,
145
- `| Extension(s) | ${extensions} |`,
146
- `| Workflow(s) exercised | ${wfSorted} |`,
147
- `| Integration profile | ${profile} |`,
148
- `| Sessions | ${entries.length} |`,
149
- "",
150
- "## Session summary",
151
- "",
152
- "| # | Date | Title | Workflow | Friction | Finding |",
153
- "|---|------|-------|----------|----------|---------|",
154
- ];
155
-
156
- for (const e of entries) {
157
- const friction = e.friction || "none";
158
- const finding = e.finding || "none";
159
- const wf = e.workflow || "\u2014";
160
- lines.push(
161
- `| S${e.session} | ${e.date} | ${e.title} | ${wf} | ${friction} | ${finding} |`
162
- );
163
- }
164
-
165
- lines.push(
166
- "", "## Statistics", "",
167
- `- **Total sessions**: ${entries.length}`,
168
- `- **Workflows used**: ${wfSorted}`,
169
- `- **Sessions with friction**: ${totalFriction}`,
170
- `- **Sessions with findings**: ${totalFindings}`,
171
- ""
172
- );
173
-
174
- if (frictionList.length > 0) {
175
- lines.push("## Friction points", "");
176
- for (const f of frictionList) lines.push(`- ${f}`);
177
- lines.push("");
178
- }
179
-
180
- if (findingsList.length > 0) {
181
- lines.push("## Findings", "");
182
- for (const f of findingsList) lines.push(`- ${f}`);
183
- lines.push("");
184
- }
185
-
186
- lines.push(
187
- "## Dimension scores", "",
188
- "Fill in after reviewing the session data above:", "",
189
- "| Dimension | Score | One-line summary |",
190
- "|-----------|:-----:|-----------------|",
191
- "| Context quality | \u2014 | |",
192
- "| Decision preservation | \u2014 | |",
193
- "| Scope discipline | \u2014 | |",
194
- "| Cascade coverage | \u2014 | |",
195
- "| Audit completeness | \u2014 | |",
196
- "| Bootstrap speed | \u2014 | |",
197
- "| Lifecycle fit | \u2014 | |",
198
- "| Model adequacy | \u2014 | |"
199
- );
200
-
201
- return lines.join("\n") + "\n";
202
- }
1
+ /** wwa refine — extract refinement report from session history. */
2
+
3
+ import { readFileSync, existsSync } from "node:fs";
4
+ import { findSessionLog, safeWriteFile } from "./helpers.js";
5
+
6
+ export function register(program) {
7
+ program
8
+ .command("refine [session-log]")
9
+ .description("Extract a refinement report from session history")
10
+ .option("-o, --output <path>", "Output file (default: stdout)")
11
+ .option("--json", "Output as JSON")
12
+ .action(async (sessionLog, opts) => {
13
+ if (!sessionLog) {
14
+ sessionLog = findSessionLog(".");
15
+ if (!sessionLog) {
16
+ console.error(
17
+ "No SESSION-LOG.md found in current directory.\n" +
18
+ "Specify a path: wwa refine path/to/SESSION-LOG.md"
19
+ );
20
+ process.exit(1);
21
+ }
22
+ }
23
+
24
+ if (!existsSync(sessionLog)) {
25
+ console.error(`File not found: ${sessionLog}`);
26
+ process.exit(1);
27
+ }
28
+
29
+ const content = readFileSync(sessionLog, "utf-8");
30
+ const parsed = parseSessionLog(content);
31
+
32
+ let result;
33
+ if (opts.json) {
34
+ result = JSON.stringify(parsed, null, 2);
35
+ } else {
36
+ result = generateRefinementReport(parsed);
37
+ }
38
+
39
+ if (opts.output) {
40
+ safeWriteFile(opts.output, result, "utf-8");
41
+ console.log(
42
+ `Refinement report written to ${opts.output} (${parsed.entries.length} sessions)`
43
+ );
44
+ } else {
45
+ console.log(result);
46
+ }
47
+ });
48
+ }
49
+
50
+ // ---------------------------------------------------------------------------
51
+ // Session log parsing
52
+ // ---------------------------------------------------------------------------
53
+
54
+ function parseSessionLog(content) {
55
+ const context = {};
56
+ const ctxMatch = content.match(
57
+ /## Project context\s*\n\s*\|[^\n]+\n\s*\|[-| ]+\n((?:\|[^\n]+\n)*)/
58
+ );
59
+ if (ctxMatch) {
60
+ for (const row of ctxMatch[1].trim().split("\n")) {
61
+ const cols = row
62
+ .split("|")
63
+ .map((c) => c.trim())
64
+ .filter((c) => c);
65
+ if (cols.length >= 2) {
66
+ context[cols[0].toLowerCase()] = cols[1];
67
+ }
68
+ }
69
+ }
70
+
71
+ const entries = [];
72
+ const entryPattern =
73
+ /###\s+S(\d+)\s*(?:\u2014|--)\s*(\S+)\s*(?:\u2014|--)\s*(.+?)$(.*?)(?=###\s+S\d+|$)/gms;
74
+ let m;
75
+ while ((m = entryPattern.exec(content)) !== null) {
76
+ const [, num, date, title, body] = m;
77
+ const entry = { session: parseInt(num, 10), date, title: title.trim() };
78
+
79
+ for (const line of body.split("\n")) {
80
+ const trimmed = line.trim();
81
+ if (!trimmed || trimmed.startsWith("#")) continue;
82
+ const segments = trimmed.split("|").map((s) => s.trim());
83
+ for (const seg of segments) {
84
+ if (seg.includes(":")) {
85
+ const idx = seg.indexOf(":");
86
+ const key = seg.slice(0, idx).trim().toLowerCase();
87
+ const val = seg.slice(idx + 1).trim();
88
+ if (
89
+ [
90
+ "model", "profile", "workflow", "queries",
91
+ "features", "cascades", "decisions", "friction", "finding",
92
+ ].includes(key)
93
+ ) {
94
+ entry[key] = val;
95
+ }
96
+ }
97
+ }
98
+ }
99
+ entries.push(entry);
100
+ }
101
+
102
+ return { context, entries };
103
+ }
104
+
105
+ function generateRefinementReport(parsed) {
106
+ const ctx = parsed.context;
107
+ const entries = parsed.entries;
108
+
109
+ const project = ctx["project name"] || "Unknown";
110
+ const ptype = ctx["project type"] || "unknown";
111
+ const profile = ctx["integration profile"] || "unknown";
112
+ const extensions = ctx["extension(s)"] || "none";
113
+
114
+ const workflows = new Set();
115
+ let totalFriction = 0;
116
+ let totalFindings = 0;
117
+ const findingsList = [];
118
+ const frictionList = [];
119
+
120
+ for (const e of entries) {
121
+ if (e.workflow) workflows.add(e.workflow);
122
+ const friction = e.friction || "none";
123
+ if (friction.toLowerCase() !== "none" && friction) {
124
+ totalFriction++;
125
+ frictionList.push(`S${e.session} (${e.date}): ${friction}`);
126
+ }
127
+ const finding = e.finding || "none";
128
+ if (finding.toLowerCase() !== "none" && finding) {
129
+ totalFindings++;
130
+ findingsList.push(`S${e.session} (${e.date}): ${finding}`);
131
+ }
132
+ }
133
+
134
+ const wfSorted = [...workflows].sort().join(", ") || "none";
135
+ const lines = [
136
+ `# Refinement Report: ${project}`,
137
+ "",
138
+ "Auto-generated from SESSION-LOG.md by `wwa refine`.",
139
+ "",
140
+ "## Source",
141
+ "",
142
+ "| Field | Value |",
143
+ "|-------|-------|",
144
+ `| Project type | ${ptype} |`,
145
+ `| Extension(s) | ${extensions} |`,
146
+ `| Workflow(s) exercised | ${wfSorted} |`,
147
+ `| Integration profile | ${profile} |`,
148
+ `| Sessions | ${entries.length} |`,
149
+ "",
150
+ "## Session summary",
151
+ "",
152
+ "| # | Date | Title | Workflow | Friction | Finding |",
153
+ "|---|------|-------|----------|----------|---------|",
154
+ ];
155
+
156
+ for (const e of entries) {
157
+ const friction = e.friction || "none";
158
+ const finding = e.finding || "none";
159
+ const wf = e.workflow || "\u2014";
160
+ lines.push(
161
+ `| S${e.session} | ${e.date} | ${e.title} | ${wf} | ${friction} | ${finding} |`
162
+ );
163
+ }
164
+
165
+ lines.push(
166
+ "", "## Statistics", "",
167
+ `- **Total sessions**: ${entries.length}`,
168
+ `- **Workflows used**: ${wfSorted}`,
169
+ `- **Sessions with friction**: ${totalFriction}`,
170
+ `- **Sessions with findings**: ${totalFindings}`,
171
+ ""
172
+ );
173
+
174
+ if (frictionList.length > 0) {
175
+ lines.push("## Friction points", "");
176
+ for (const f of frictionList) lines.push(`- ${f}`);
177
+ lines.push("");
178
+ }
179
+
180
+ if (findingsList.length > 0) {
181
+ lines.push("## Findings", "");
182
+ for (const f of findingsList) lines.push(`- ${f}`);
183
+ lines.push("");
184
+ }
185
+
186
+ lines.push(
187
+ "## Dimension scores", "",
188
+ "Fill in after reviewing the session data above:", "",
189
+ "| Dimension | Score | One-line summary |",
190
+ "|-----------|:-----:|-----------------|",
191
+ "| Context quality | \u2014 | |",
192
+ "| Decision preservation | \u2014 | |",
193
+ "| Scope discipline | \u2014 | |",
194
+ "| Cascade coverage | \u2014 | |",
195
+ "| Audit completeness | \u2014 | |",
196
+ "| Bootstrap speed | \u2014 | |",
197
+ "| Lifecycle fit | \u2014 | |",
198
+ "| Model adequacy | \u2014 | |"
199
+ );
200
+
201
+ return lines.join("\n") + "\n";
202
+ }
@@ -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
@@ -1,28 +1,28 @@
1
- /** wwa scan — detect project type from directory contents. */
2
-
3
- import { getPipeline, outputData } from "./helpers.js";
4
-
5
- export function register(program) {
6
- program
7
- .command("scan [directory]")
8
- .description("Detect project type from directory contents")
9
- .option("--registry <path>", "Path to feature-registry.yaml")
10
- .option("--json", "Output as JSON")
11
- .action(async (directory, opts) => {
12
- directory = directory || ".";
13
- const { detectProjectType } = await getPipeline();
14
- const result = detectProjectType(directory);
15
-
16
- const ptype = result.project_type || "general";
17
- const friendlyMap = { analytical: "context", mixed: "mix" };
18
- if (ptype in friendlyMap) {
19
- result.friendly_name = friendlyMap[ptype];
20
- result.init_command = `npx wwa init ${friendlyMap[ptype]}`;
21
- } else {
22
- result.init_command = `npx wwa init ${ptype}`;
23
- }
24
-
25
- console.log(`Scanning: ${directory}`);
26
- outputData(result, opts.json);
27
- });
28
- }
1
+ /** wwa scan — detect project type from directory contents. */
2
+
3
+ import { getPipeline, outputData } from "./helpers.js";
4
+
5
+ export function register(program) {
6
+ program
7
+ .command("scan [directory]")
8
+ .description("Detect project type from directory contents")
9
+ .option("--registry <path>", "Path to feature-registry.yaml")
10
+ .option("--json", "Output as JSON")
11
+ .action(async (directory, opts) => {
12
+ directory = directory || ".";
13
+ const { detectProjectType } = await getPipeline();
14
+ const result = detectProjectType(directory);
15
+
16
+ const ptype = result.project_type || "general";
17
+ const friendlyMap = { analytical: "context", mixed: "mix" };
18
+ if (ptype in friendlyMap) {
19
+ result.friendly_name = friendlyMap[ptype];
20
+ result.init_command = `wwa init ${friendlyMap[ptype]}`;
21
+ } else {
22
+ result.init_command = `wwa init ${ptype}`;
23
+ }
24
+
25
+ console.log(`Scanning: ${directory}`);
26
+ outputData(result, opts.json);
27
+ });
28
+ }
package/lib/cli/status.js CHANGED
@@ -1,61 +1,61 @@
1
- /** wwa status — check if methodology version is current. */
2
-
3
- import { findEntryPoint, readMethodVersion, basename_of, pkg } from "./helpers.js";
4
-
5
- export function register(program) {
6
- program
7
- .command("status [directory]")
8
- .description("Check if your methodology version is current")
9
- .option("--json", "Output as JSON")
10
- .action(async (directory, opts) => {
11
- directory = directory || ".";
12
- const ep = findEntryPoint(directory);
13
- if (!ep) {
14
- console.error(
15
- `No entry point found in ${directory} ` +
16
- "(looked for CLAUDE.md, .cursorrules, AGENT.md)"
17
- );
18
- process.exit(1);
19
- }
20
-
21
- const epVersion = readMethodVersion(ep);
22
- const installed = pkg.version;
23
-
24
- let verStatus, message;
25
- if (!epVersion) {
26
- verStatus = "no_version";
27
- message =
28
- `Entry point ${basename_of(ep)} has no method_version setting. ` +
29
- `Add 'method_version: ${installed.split(".").slice(0, 2).join(".")}' ` +
30
- `to enable version tracking.`;
31
- } else if (epVersion === installed.split(".").slice(0, 2).join(".")) {
32
- verStatus = "current";
33
- message =
34
- `Entry point ${basename_of(ep)} is current ` +
35
- `(method_version: ${epVersion}, installed: ${installed})`;
36
- } else {
37
- verStatus = "outdated";
38
- message =
39
- `Entry point ${basename_of(ep)} is outdated ` +
40
- `(method_version: ${epVersion}, installed: ${installed}). ` +
41
- `Run \`npx wwa upgrade ${directory}\` to update.`;
42
- }
43
-
44
- if (opts.json) {
45
- console.log(
46
- JSON.stringify(
47
- {
48
- entry_point: ep,
49
- entry_point_version: epVersion,
50
- installed_version: installed,
51
- status: verStatus,
52
- },
53
- null,
54
- 2
55
- )
56
- );
57
- } else {
58
- console.log(message);
59
- }
60
- });
61
- }
1
+ /** wwa status — check if methodology version is current. */
2
+
3
+ import { findEntryPoint, readMethodVersion, basename_of, pkg } from "./helpers.js";
4
+
5
+ export function register(program) {
6
+ program
7
+ .command("status [directory]")
8
+ .description("Check if your methodology version is current")
9
+ .option("--json", "Output as JSON")
10
+ .action(async (directory, opts) => {
11
+ directory = directory || ".";
12
+ const ep = findEntryPoint(directory);
13
+ if (!ep) {
14
+ console.error(
15
+ `No entry point found in ${directory} ` +
16
+ "(looked for CLAUDE.md, .cursorrules, AGENT.md)"
17
+ );
18
+ process.exit(1);
19
+ }
20
+
21
+ const epVersion = readMethodVersion(ep);
22
+ const installed = pkg.version;
23
+
24
+ let verStatus, message;
25
+ if (!epVersion) {
26
+ verStatus = "no_version";
27
+ message =
28
+ `Entry point ${basename_of(ep)} has no method_version setting. ` +
29
+ `Add 'method_version: ${installed.split(".").slice(0, 2).join(".")}' ` +
30
+ `to enable version tracking.`;
31
+ } else if (epVersion === installed.split(".").slice(0, 2).join(".")) {
32
+ verStatus = "current";
33
+ message =
34
+ `Entry point ${basename_of(ep)} is current ` +
35
+ `(method_version: ${epVersion}, installed: ${installed})`;
36
+ } else {
37
+ verStatus = "outdated";
38
+ message =
39
+ `Entry point ${basename_of(ep)} is outdated ` +
40
+ `(method_version: ${epVersion}, installed: ${installed}). ` +
41
+ `Run \`wwa upgrade ${directory}\` to update.`;
42
+ }
43
+
44
+ if (opts.json) {
45
+ console.log(
46
+ JSON.stringify(
47
+ {
48
+ entry_point: ep,
49
+ entry_point_version: epVersion,
50
+ installed_version: installed,
51
+ status: verStatus,
52
+ },
53
+ null,
54
+ 2
55
+ )
56
+ );
57
+ } else {
58
+ console.log(message);
59
+ }
60
+ });
61
+ }