agent-method 1.5.12

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 (108) hide show
  1. package/README.md +343 -0
  2. package/bin/wwa.js +115 -0
  3. package/docs/internal/cli-commands.yaml +259 -0
  4. package/docs/internal/doc-tokens.yaml +1103 -0
  5. package/docs/internal/feature-registry.yaml +1643 -0
  6. package/lib/boundaries.js +247 -0
  7. package/lib/cli/add.js +170 -0
  8. package/lib/cli/casestudy.js +1000 -0
  9. package/lib/cli/check.js +323 -0
  10. package/lib/cli/close.js +838 -0
  11. package/lib/cli/completion.js +735 -0
  12. package/lib/cli/deps.js +234 -0
  13. package/lib/cli/digest.js +73 -0
  14. package/lib/cli/doc-review.js +486 -0
  15. package/lib/cli/docs.js +315 -0
  16. package/lib/cli/helpers.js +198 -0
  17. package/lib/cli/implement.js +169 -0
  18. package/lib/cli/init.js +280 -0
  19. package/lib/cli/pipeline.js +206 -0
  20. package/lib/cli/plan.js +140 -0
  21. package/lib/cli/record.js +98 -0
  22. package/lib/cli/refine.js +202 -0
  23. package/lib/cli/report-helpers.js +113 -0
  24. package/lib/cli/review.js +76 -0
  25. package/lib/cli/routable.js +109 -0
  26. package/lib/cli/route.js +101 -0
  27. package/lib/cli/scan.js +133 -0
  28. package/lib/cli/serve.js +23 -0
  29. package/lib/cli/status.js +65 -0
  30. package/lib/cli/update-docs.js +574 -0
  31. package/lib/cli/upgrade.js +222 -0
  32. package/lib/cli/watch.js +32 -0
  33. package/lib/dependencies.js +196 -0
  34. package/lib/init.js +692 -0
  35. package/lib/mcp-server.js +612 -0
  36. package/lib/pipeline.js +907 -0
  37. package/lib/registry.js +132 -0
  38. package/lib/watcher.js +165 -0
  39. package/package.json +54 -0
  40. package/templates/README.md +363 -0
  41. package/templates/entry-points/.cursorrules +90 -0
  42. package/templates/entry-points/AGENT.md +90 -0
  43. package/templates/entry-points/CLAUDE.md +88 -0
  44. package/templates/extensions/MANIFEST.md +110 -0
  45. package/templates/extensions/analytical-system.md +96 -0
  46. package/templates/extensions/code-project.md +77 -0
  47. package/templates/extensions/data-exploration.md +117 -0
  48. package/templates/full/.context/BASE.md +101 -0
  49. package/templates/full/.context/COMPOSITION.md +47 -0
  50. package/templates/full/.context/INDEX.yaml +56 -0
  51. package/templates/full/.context/METHODOLOGY.md +246 -0
  52. package/templates/full/.context/PROTOCOL.yaml +169 -0
  53. package/templates/full/.context/REGISTRY.md +75 -0
  54. package/templates/full/.cursorrules +90 -0
  55. package/templates/full/AGENT.md +90 -0
  56. package/templates/full/CLAUDE.md +90 -0
  57. package/templates/full/Management/DIGEST.md +23 -0
  58. package/templates/full/Management/STATUS.md +46 -0
  59. package/templates/full/PLAN.md +67 -0
  60. package/templates/full/PROJECT-PROFILE.md +61 -0
  61. package/templates/full/PROJECT.md +80 -0
  62. package/templates/full/REQUIREMENTS.md +30 -0
  63. package/templates/full/ROADMAP.md +39 -0
  64. package/templates/full/Reviews/INDEX.md +41 -0
  65. package/templates/full/Reviews/backlog.md +52 -0
  66. package/templates/full/Reviews/plan.md +43 -0
  67. package/templates/full/Reviews/project.md +41 -0
  68. package/templates/full/Reviews/requirements.md +42 -0
  69. package/templates/full/Reviews/roadmap.md +41 -0
  70. package/templates/full/Reviews/state.md +56 -0
  71. package/templates/full/SESSION-LOG.md +102 -0
  72. package/templates/full/STATE.md +42 -0
  73. package/templates/full/SUMMARY.md +27 -0
  74. package/templates/full/agentWorkflows/INDEX.md +42 -0
  75. package/templates/full/agentWorkflows/observations.md +65 -0
  76. package/templates/full/agentWorkflows/patterns.md +68 -0
  77. package/templates/full/agentWorkflows/sessions.md +92 -0
  78. package/templates/full/intro/README.md +39 -0
  79. package/templates/full/registry/feature-registry.yaml +25 -0
  80. package/templates/full/registry/features/catalog.yaml +743 -0
  81. package/templates/full/registry/features/protocol.yaml +121 -0
  82. package/templates/full/registry/features/routing.yaml +358 -0
  83. package/templates/full/registry/features/workflows.yaml +404 -0
  84. package/templates/full/todos/backlog.md +19 -0
  85. package/templates/starter/.context/BASE.md +66 -0
  86. package/templates/starter/.context/INDEX.yaml +51 -0
  87. package/templates/starter/.context/METHODOLOGY.md +228 -0
  88. package/templates/starter/.context/PROTOCOL.yaml +165 -0
  89. package/templates/starter/.cursorrules +90 -0
  90. package/templates/starter/AGENT.md +90 -0
  91. package/templates/starter/CLAUDE.md +90 -0
  92. package/templates/starter/Management/DIGEST.md +23 -0
  93. package/templates/starter/Management/STATUS.md +46 -0
  94. package/templates/starter/PLAN.md +67 -0
  95. package/templates/starter/PROJECT-PROFILE.md +44 -0
  96. package/templates/starter/PROJECT.md +80 -0
  97. package/templates/starter/ROADMAP.md +39 -0
  98. package/templates/starter/Reviews/INDEX.md +75 -0
  99. package/templates/starter/SESSION-LOG.md +102 -0
  100. package/templates/starter/STATE.md +42 -0
  101. package/templates/starter/SUMMARY.md +27 -0
  102. package/templates/starter/agentWorkflows/INDEX.md +61 -0
  103. package/templates/starter/intro/README.md +37 -0
  104. package/templates/starter/registry/feature-registry.yaml +25 -0
  105. package/templates/starter/registry/features/catalog.yaml +743 -0
  106. package/templates/starter/registry/features/protocol.yaml +121 -0
  107. package/templates/starter/registry/features/routing.yaml +358 -0
  108. package/templates/starter/registry/features/workflows.yaml +404 -0
@@ -0,0 +1,323 @@
1
+ /** wwa check — validate entry point and project setup. */
2
+
3
+ import { dirname, join, resolve } from "node:path";
4
+ import { existsSync, readFileSync } from "node:fs";
5
+ import {
6
+ findEntryPoint,
7
+ resolveProjectType,
8
+ getPipeline,
9
+ loadRegistryData,
10
+ } from "./helpers.js";
11
+ import { resolveTokensPath, loadBoundaries } from "../boundaries.js";
12
+ import { printCliReport, writeLastRunSummary } from "./report-helpers.js";
13
+
14
+ /** Phase 7q-2: Detect if PROTOCOL.yaml has an active (uncommented) boundaries section. */
15
+ function hasActiveBoundariesSection(raw) {
16
+ const lines = raw.split("\n");
17
+ for (const line of lines) {
18
+ if (/^\s*boundaries\s*:/.test(line)) return !line.trimStart().startsWith("#");
19
+ }
20
+ return false;
21
+ }
22
+
23
+ export function register(program) {
24
+ program
25
+ .command("check [entry-point]")
26
+ .description("Validate your entry point and project setup")
27
+ .option(
28
+ "-p, --project-type <type>",
29
+ "Project type: code, context, data, mix, general (auto-detected if omitted)"
30
+ )
31
+ .option("--registry <path>", "Path to feature-registry.yaml")
32
+ .option("--json", "Output as JSON")
33
+ .action(async (entryPoint, opts) => {
34
+ const { validateEntryPoint, detectProjectType } = await getPipeline();
35
+ const reg = await loadRegistryData(opts.registry);
36
+
37
+ if (!entryPoint) {
38
+ entryPoint = findEntryPoint(".");
39
+ if (!entryPoint) {
40
+ console.error(
41
+ "No entry point found in current directory " +
42
+ "(looked for CLAUDE.md, .cursorrules, AGENT.md).\n" +
43
+ "Specify a path: wwa check path/to/CLAUDE.md"
44
+ );
45
+ process.exit(1);
46
+ }
47
+ }
48
+
49
+ let projectType;
50
+ if (opts.projectType) {
51
+ projectType = resolveProjectType(opts.projectType);
52
+ } else {
53
+ const detected = detectProjectType(resolve(dirname(resolve(entryPoint))));
54
+ projectType = detected.project_type || "general";
55
+ }
56
+
57
+ const result = validateEntryPoint(entryPoint, projectType, reg);
58
+
59
+ // Resolve project root once for consistent path resolution (Phase 7q-2)
60
+ const entryResolved = resolve(entryPoint);
61
+ const epDir = dirname(entryResolved);
62
+ const epDirAbs = resolve(epDir);
63
+
64
+ // V-09: PROTOCOL.yaml presence and structure
65
+ let epContent;
66
+ try { epContent = readFileSync(entryResolved, "utf-8"); } catch { epContent = ""; }
67
+ if (epContent.includes("PROTOCOL.yaml")) {
68
+ const protocolPath = join(epDirAbs, ".context", "PROTOCOL.yaml");
69
+ if (existsSync(protocolPath)) {
70
+ try {
71
+ const yaml = (await import("js-yaml")).default;
72
+ const raw = readFileSync(protocolPath, "utf-8");
73
+ const parsed = yaml.load(raw);
74
+ const requiredKeys = ["scoping", "cascade", "close_check"];
75
+ const missingKeys = requiredKeys.filter(k => !parsed || !parsed[k]);
76
+ if (missingKeys.length > 0) {
77
+ result.checks["V-09_protocol_structure"] = { pass: false, missing: missingKeys };
78
+ result.issues.push({
79
+ check: "V-09",
80
+ severity: "medium",
81
+ description: `PROTOCOL.yaml missing required sections: ${missingKeys.join(", ")}`,
82
+ });
83
+ } else {
84
+ result.checks["V-09_protocol_structure"] = { pass: true };
85
+ }
86
+ } catch (e) {
87
+ result.checks["V-09_protocol_structure"] = { pass: false };
88
+ result.issues.push({
89
+ check: "V-09",
90
+ severity: "high",
91
+ description: `PROTOCOL.yaml parse error: ${e.message}`,
92
+ });
93
+ }
94
+ } else {
95
+ result.checks["V-09_protocol_presence"] = { pass: false };
96
+ result.issues.push({
97
+ check: "V-09",
98
+ severity: "warning",
99
+ description: `PROTOCOL.yaml not found at expected path`,
100
+ expectedPath: protocolPath,
101
+ suggestion: "Create .context/ and copy PROTOCOL.yaml from a template, or run wwa init.",
102
+ });
103
+ }
104
+ }
105
+
106
+ // V-10: doc_graph health (informational — does not affect overall validity)
107
+ const docTokensPath = await resolveTokensPath(epDirAbs);
108
+ if (existsSync(docTokensPath)) {
109
+ try {
110
+ const yaml = (await import("js-yaml")).default;
111
+ const dtRaw = readFileSync(docTokensPath, "utf-8");
112
+ const dtParsed = yaml.load(dtRaw);
113
+ if (dtParsed?.doc_graph) {
114
+ const nodes = dtParsed.doc_graph.nodes || [];
115
+ const edges = dtParsed.doc_graph.edges || [];
116
+ const nodePaths = new Set(nodes.map((n) => n.path));
117
+ const missingOnDisk = nodes.filter(
118
+ (n) => !existsSync(join(epDirAbs, n.path))
119
+ );
120
+ const danglingEdges = edges.filter(
121
+ (e) => !nodePaths.has(e.from) || !nodePaths.has(e.to)
122
+ );
123
+ const pass = missingOnDisk.length === 0 && danglingEdges.length === 0;
124
+ result.checks["V-10_doc_graph_health"] = {
125
+ pass,
126
+ nodes: nodes.length,
127
+ edges: edges.length,
128
+ missingOnDisk: missingOnDisk.map((n) => n.path),
129
+ danglingEdges: danglingEdges.length,
130
+ };
131
+ if (!pass) {
132
+ result.issues.push({
133
+ check: "V-10",
134
+ severity: "info",
135
+ description: `doc_graph: ${missingOnDisk.length} nodes missing on disk, ${danglingEdges.length} dangling edges`,
136
+ });
137
+ }
138
+ }
139
+ } catch {
140
+ // doc-tokens.yaml parse error — skip V-10 silently
141
+ }
142
+ }
143
+
144
+ // V-11: Boundaries configuration health (informational) — Phase 7q-2: distinguish not configured vs file not found
145
+ const protocolForBounds = join(epDirAbs, ".context", "PROTOCOL.yaml");
146
+ if (existsSync(protocolForBounds)) {
147
+ try {
148
+ const protocolRaw = readFileSync(protocolForBounds, "utf-8");
149
+ const boundariesConfigured = hasActiveBoundariesSection(protocolRaw);
150
+ if (!boundariesConfigured) {
151
+ result.checks["V-11_boundaries_health"] = { pass: false, reason: "boundaries_not_configured" };
152
+ result.issues.push({
153
+ check: "V-11",
154
+ severity: "info",
155
+ description: "Boundaries section not configured or commented out in .context/PROTOCOL.yaml.",
156
+ suggestion: "Uncomment the boundaries section and set registries.tokens, registries.feature_registry, docs_map, and output. Run `wwa init` to generate a project with boundaries enabled, or copy from templates.",
157
+ });
158
+ } else {
159
+ const bounds = await loadBoundaries(epDirAbs);
160
+ const issues = [];
161
+ const details = [];
162
+ for (const [key, relPath] of Object.entries(bounds.registries || {})) {
163
+ if (key === "output") continue;
164
+ const absPath = join(epDirAbs, relPath);
165
+ if (!existsSync(absPath)) {
166
+ issues.push(`registries.${key}: ${relPath} not found`);
167
+ details.push({ key, configuredPath: relPath, resolvedPath: absPath });
168
+ }
169
+ }
170
+ const internalSet = new Set(bounds.visibility?.internal || []);
171
+ for (const r of bounds.visibility?.release || []) {
172
+ if (internalSet.has(r)) issues.push(`visibility overlap: ${r} in both internal and release`);
173
+ }
174
+ const pass = issues.length === 0;
175
+ result.checks["V-11_boundaries_health"] = { pass, issues, details };
176
+ if (!pass) {
177
+ const firstDetail = details[0];
178
+ let description = `Boundaries: ${issues.length} issue(s) — `;
179
+ if (firstDetail) {
180
+ description += `registries.${firstDetail.key}: file not found at ${firstDetail.resolvedPath} (configured as "${firstDetail.configuredPath}")`;
181
+ } else {
182
+ description += issues[0];
183
+ }
184
+ result.issues.push({
185
+ check: "V-11",
186
+ severity: "info",
187
+ description,
188
+ suggestion: details.length > 0 ? "Ensure registry files exist at the paths in .context/PROTOCOL.yaml boundaries.registries, or run wwa init to create them." : undefined,
189
+ });
190
+ }
191
+ }
192
+ } catch (e) {
193
+ result.checks["V-11_boundaries_health"] = { pass: false, reason: "path_resolution_failed", error: e.message };
194
+ result.issues.push({
195
+ check: "V-11",
196
+ severity: "info",
197
+ description: `Path resolution failed: ${e.message}`,
198
+ suggestion: "Check that .context/PROTOCOL.yaml is valid YAML and boundaries.registries paths are relative to project root.",
199
+ });
200
+ }
201
+ }
202
+
203
+ // V-12: Token drift detection (informational — compares registry values against source of truth)
204
+ if (existsSync(docTokensPath)) {
205
+ try {
206
+ const yaml = (await import("js-yaml")).default;
207
+ const dtRaw = readFileSync(docTokensPath, "utf-8");
208
+ const dtParsed = yaml.load(dtRaw);
209
+ if (dtParsed?.tokens) {
210
+ const driftIssues = [];
211
+ const t = dtParsed.tokens;
212
+
213
+ // Compare against feature registry (source of truth for counts)
214
+ const bounds = await loadBoundaries(epDirAbs);
215
+ const regPath = join(epDirAbs, bounds.registries.feature_registry);
216
+ if (existsSync(regPath)) {
217
+ const reg = yaml.load(readFileSync(regPath, "utf-8"));
218
+ if (reg?.features) {
219
+ const actual = Object.keys(reg.features).length;
220
+ if (t.feature_count && t.feature_count !== actual) {
221
+ driftIssues.push(`feature_count: token=${t.feature_count} actual=${actual}`);
222
+ }
223
+ }
224
+ if (reg?.workflows) {
225
+ const actual = reg.workflows.length;
226
+ if (t.workflow_count && t.workflow_count !== actual) {
227
+ driftIssues.push(`workflow_count: token=${t.workflow_count} actual=${actual}`);
228
+ }
229
+ }
230
+ if (reg?.domains) {
231
+ const actual = reg.domains.length;
232
+ if (t.domain_count && t.domain_count !== actual) {
233
+ driftIssues.push(`domain_count: token=${t.domain_count} actual=${actual}`);
234
+ }
235
+ }
236
+ if (reg?.protocol?.core_directives) {
237
+ const actual = reg.protocol.core_directives.length;
238
+ if (t.directive_count && t.directive_count !== actual) {
239
+ driftIssues.push(`directive_count: token=${t.directive_count} actual=${actual}`);
240
+ }
241
+ }
242
+ }
243
+
244
+ const pass = driftIssues.length === 0;
245
+ result.checks["V-12_token_drift"] = { pass, driftIssues };
246
+ if (!pass) {
247
+ result.issues.push({
248
+ check: "V-12",
249
+ severity: "info",
250
+ description: `Token drift: ${driftIssues.length} mismatch(es) — ${driftIssues[0]}${driftIssues.length > 1 ? ` (+${driftIssues.length - 1} more)` : ""}`,
251
+ });
252
+ }
253
+ }
254
+ } catch {
255
+ // drift check failed — skip silently
256
+ }
257
+ }
258
+
259
+ // V-13: Legacy registry paths (informational — detect .context/ YAML when registry/ exists)
260
+ const registryDir = join(epDirAbs, "registry");
261
+ if (existsSync(registryDir)) {
262
+ const legacyFiles = [];
263
+ const legacyTokens = join(epDirAbs, ".context", "doc-tokens.yaml");
264
+ const legacyFeatures = join(epDirAbs, ".context", "feature-registry.yaml");
265
+ if (existsSync(legacyTokens)) legacyFiles.push(".context/doc-tokens.yaml");
266
+ if (existsSync(legacyFeatures)) legacyFiles.push(".context/feature-registry.yaml");
267
+ if (legacyFiles.length > 0) {
268
+ result.checks["V-13_legacy_registry_paths"] = { pass: false, legacyFiles };
269
+ result.issues.push({
270
+ check: "V-13",
271
+ severity: "info",
272
+ description: `Legacy registry files in .context/: ${legacyFiles.join(", ")} — run \`wwa upgrade\` to migrate to registry/`,
273
+ });
274
+ } else {
275
+ result.checks["V-13_legacy_registry_paths"] = { pass: true };
276
+ }
277
+ }
278
+
279
+ // Recompute overall validity (V-10, V-11, V-12, V-13 are informational, exclude from pass/fail)
280
+ const informational = new Set(["V-10_doc_graph_health", "V-11_boundaries_health", "V-12_token_drift", "V-13_legacy_registry_paths"]);
281
+ result.valid = Object.entries(result.checks).every(
282
+ ([key, c]) => c.pass || informational.has(key)
283
+ );
284
+
285
+ if (opts.json) {
286
+ console.log(JSON.stringify(result, null, 2));
287
+ } else {
288
+ const overall = result.valid ? "PASS" : "FAIL";
289
+ const issueCount = result.issues?.length ?? 0;
290
+ const firstSuggestion = result.issues?.[0]?.suggestion;
291
+ const summary = [
292
+ `Validation ${overall}.`,
293
+ issueCount
294
+ ? `${issueCount} issue(s) found.${firstSuggestion ? ` Fix: ${firstSuggestion}` : " See issues below."}`
295
+ : "All checks passed.",
296
+ ].join(" ");
297
+ const inputRef = `entry-point=${entryPoint}, project type=${projectType}`;
298
+ printCliReport({ command: "check", inputRef, summary });
299
+ console.log(` Detail — Checking: ${entryPoint} (type: ${projectType})`);
300
+ console.log(` Overall: ${overall}`);
301
+ for (const [checkId, chk] of Object.entries(result.checks)) {
302
+ const cStatus = chk.pass ? "PASS" : "FAIL";
303
+ let extra = "";
304
+ if (chk.missing && chk.missing.length > 0) {
305
+ extra = ` (missing: ${chk.missing.join(", ")})`;
306
+ }
307
+ console.log(` ${checkId}: ${cStatus}${extra}`);
308
+ }
309
+ if (result.issues && result.issues.length > 0) {
310
+ console.log("\n Issues:");
311
+ for (const issue of result.issues) {
312
+ console.log(
313
+ ` [${issue.severity}] ${issue.check}: ${issue.description}`
314
+ );
315
+ if (issue.suggestion) {
316
+ console.log(` Suggestion: ${issue.suggestion}`);
317
+ }
318
+ }
319
+ }
320
+ writeLastRunSummary(epDirAbs, { command: "check", inputRef, summary });
321
+ }
322
+ });
323
+ }