agent-method 1.5.0 → 1.5.3

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/lib/cli/init.js CHANGED
@@ -1,4 +1,4 @@
1
- /** agent-method init — set up a new project or describe entry point contents. */
1
+ /** wwa init — set up a new project with methodology templates. */
2
2
 
3
3
  import {
4
4
  resolveProjectType,
@@ -10,9 +10,11 @@ import {
10
10
 
11
11
  export function register(program) {
12
12
  program
13
- .command("init <project-type> [directory]")
13
+ .command("init [project-type] [directory]")
14
14
  .description("Set up a new project with methodology templates")
15
- .option("--tier <tier>", "Template tier (starter/full)", "starter")
15
+ .option("--tier <tier>", "Template tier (starter/full)")
16
+ .option("--runtime <runtime>", "Agent runtime (claude/cursor/all)")
17
+ .option("--profile <profile>", "Integration profile (lite/standard/full)")
16
18
  .option("--registry <path>", "Path to feature-registry.yaml")
17
19
  .option("--json", "Output as JSON")
18
20
  .option(
@@ -20,15 +22,13 @@ export function register(program) {
20
22
  "Only describe what the entry point should contain (no file creation)"
21
23
  )
22
24
  .action(async (projectTypeArg, directory, opts) => {
23
- const projectType = resolveProjectType(projectTypeArg);
24
-
25
- if (opts.describe || !directory) {
26
- // Describe mode
25
+ // If describe mode with a type, show entry point spec
26
+ if (opts.describe && projectTypeArg) {
27
+ const projectType = resolveProjectType(projectTypeArg);
27
28
  const { generateEntryPoint } = await getPipeline();
28
29
  const reg = await loadRegistryData(opts.registry);
29
- const result = generateEntryPoint(projectType, opts.tier, reg);
30
+ const result = generateEntryPoint(projectType, opts.tier || "starter", reg);
30
31
 
31
- // Show friendly name
32
32
  let friendly = projectType;
33
33
  for (const [alias, internal] of Object.entries(PROJECT_TYPE_ALIASES)) {
34
34
  if (internal === projectType && alias !== projectType) {
@@ -38,22 +38,112 @@ export function register(program) {
38
38
  }
39
39
 
40
40
  console.log(
41
- `Entry point specification for: ${friendly} (${opts.tier})`
41
+ `Entry point specification for: ${friendly} (${opts.tier || "starter"})`
42
42
  );
43
43
  outputData(result, opts.json);
44
+ return;
45
+ }
46
+
47
+ // Interactive mode — prompt for missing values
48
+ if (!projectTypeArg || !directory) {
49
+ const inquirer = (await import("inquirer")).default;
50
+
51
+ console.log("\n wwa — Set up AI-agent-assisted development\n");
52
+
53
+ const answers = {};
54
+
55
+ if (!projectTypeArg) {
56
+ const { type } = await inquirer.prompt([
57
+ {
58
+ type: "list",
59
+ name: "type",
60
+ message: "Project type:",
61
+ choices: [
62
+ { name: "Code — software project", value: "code" },
63
+ { name: "Data — data index/querying", value: "data" },
64
+ { name: "Analytical — prompts, chains, evaluation", value: "context" },
65
+ { name: "Mixed — multiple types combined", value: "mix" },
66
+ { name: "General — universal rules only", value: "general" },
67
+ ],
68
+ },
69
+ ]);
70
+ answers.type = type;
71
+ }
72
+
44
73
  if (!directory) {
45
- console.log(
46
- "\nTo create a project, specify a directory:\n" +
47
- ` agent-method init ${projectTypeArg} ~/my-project`
48
- );
74
+ const { dir } = await inquirer.prompt([
75
+ {
76
+ type: "input",
77
+ name: "dir",
78
+ message: "Project directory:",
79
+ default: ".",
80
+ },
81
+ ]);
82
+ answers.dir = dir;
49
83
  }
50
- return;
84
+
85
+ if (!opts.runtime) {
86
+ const { runtime } = await inquirer.prompt([
87
+ {
88
+ type: "list",
89
+ name: "runtime",
90
+ message: "Agent runtime:",
91
+ choices: [
92
+ { name: "Claude Code — creates CLAUDE.md", value: "claude" },
93
+ { name: "Cursor — creates .cursorrules", value: "cursor" },
94
+ { name: "Other / All — keeps all entry points", value: "all" },
95
+ ],
96
+ },
97
+ ]);
98
+ answers.runtime = runtime;
99
+ }
100
+
101
+ if (!opts.tier) {
102
+ const { tier } = await inquirer.prompt([
103
+ {
104
+ type: "list",
105
+ name: "tier",
106
+ message: "Template tier:",
107
+ choices: [
108
+ { name: "Starter (7 files) — recommended for most projects", value: "starter" },
109
+ { name: "Full (11+ files) — complex or long-running projects", value: "full" },
110
+ ],
111
+ },
112
+ ]);
113
+ answers.tier = tier;
114
+ }
115
+
116
+ if (!opts.profile) {
117
+ const { profile } = await inquirer.prompt([
118
+ {
119
+ type: "list",
120
+ name: "profile",
121
+ message: "Integration profile:",
122
+ choices: [
123
+ { name: "Standard (Sonnet) — recommended", value: "standard" },
124
+ { name: "Lite (Haiku) — minimal rules, simple projects", value: "lite" },
125
+ { name: "Full (Opus) — all rules inline, complex projects", value: "full" },
126
+ ],
127
+ },
128
+ ]);
129
+ answers.profile = profile;
130
+ }
131
+
132
+ projectTypeArg = projectTypeArg || answers.type;
133
+ directory = directory || answers.dir;
134
+ opts.runtime = opts.runtime || answers.runtime;
135
+ opts.tier = opts.tier || answers.tier;
136
+ opts.profile = opts.profile || answers.profile;
51
137
  }
52
138
 
53
- // Interactive setup mode
139
+ const projectType = resolveProjectType(projectTypeArg);
140
+
141
+ // Setup mode
54
142
  const { initProject } = await import("../init.js");
55
143
  await initProject(projectType, directory, {
56
- tier: opts.tier,
144
+ tier: opts.tier || "starter",
145
+ runtime: opts.runtime || "all",
146
+ profile: opts.profile || "standard",
57
147
  registryPath: opts.registry,
58
148
  });
59
149
  });
@@ -1,4 +1,4 @@
1
- /** agent-method pipeline — advanced subcommands for debugging and testing. */
1
+ /** wwa pipeline — advanced subcommands for debugging and testing. */
2
2
 
3
3
  import { resolve, dirname, join } from "node:path";
4
4
  import { existsSync, readdirSync } from "node:fs";
package/lib/cli/refine.js CHANGED
@@ -1,4 +1,4 @@
1
- /** agent-method refine — extract refinement report from session history. */
1
+ /** wwa refine — extract refinement report from session history. */
2
2
 
3
3
  import { readFileSync, existsSync, writeFileSync } from "node:fs";
4
4
  import { findSessionLog } from "./helpers.js";
@@ -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: agent-method refine path/to/SESSION-LOG.md"
18
+ "Specify a path: npx wwa refine path/to/SESSION-LOG.md"
19
19
  );
20
20
  process.exit(1);
21
21
  }
@@ -135,7 +135,7 @@ function generateRefinementReport(parsed) {
135
135
  const lines = [
136
136
  `# Refinement Report: ${project}`,
137
137
  "",
138
- "Auto-generated from SESSION-LOG.md by `agent-method refine`.",
138
+ "Auto-generated from SESSION-LOG.md by `wwa refine`.",
139
139
  "",
140
140
  "## Source",
141
141
  "",
package/lib/cli/route.js CHANGED
@@ -1,4 +1,4 @@
1
- /** agent-method route — show how a query routes through the pipeline. */
1
+ /** wwa route — show how a query routes through the pipeline. */
2
2
 
3
3
  import {
4
4
  resolveProjectType,
package/lib/cli/scan.js CHANGED
@@ -1,4 +1,4 @@
1
- /** agent-method scan — detect project type from directory contents. */
1
+ /** wwa scan — detect project type from directory contents. */
2
2
 
3
3
  import { getPipeline, outputData } from "./helpers.js";
4
4
 
@@ -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 = `agent-method init ${friendlyMap[ptype]}`;
20
+ result.init_command = `npx wwa init ${friendlyMap[ptype]}`;
21
21
  } else {
22
- result.init_command = `agent-method init ${ptype}`;
22
+ result.init_command = `npx wwa init ${ptype}`;
23
23
  }
24
24
 
25
25
  console.log(`Scanning: ${directory}`);
@@ -0,0 +1,23 @@
1
+ /** wwa serve — start MCP server on stdio transport. */
2
+
3
+ export function register(program) {
4
+ program
5
+ .command("serve")
6
+ .description("Start MCP server exposing methodology tools via stdio transport")
7
+ .option("--registry <path>", "Path to feature-registry.yaml")
8
+ .action(async (opts) => {
9
+ // Redirect all non-MCP output to stderr so stdout stays clean for JSON-RPC
10
+ const info = (msg) => process.stderr.write(msg + "\n");
11
+
12
+ info("wwa MCP server starting...");
13
+
14
+ try {
15
+ const { startServer } = await import("../mcp-server.js");
16
+ await startServer(opts.registry || undefined);
17
+ info("wwa MCP server running on stdio. Press Ctrl+C to stop.");
18
+ } catch (err) {
19
+ info(`Error: ${err.message}`);
20
+ process.exit(1);
21
+ }
22
+ });
23
+ }
package/lib/cli/status.js CHANGED
@@ -1,4 +1,4 @@
1
- /** agent-method status — check if methodology version is current. */
1
+ /** wwa status — check if methodology version is current. */
2
2
 
3
3
  import { findEntryPoint, readMethodVersion, basename_of, pkg } from "./helpers.js";
4
4
 
@@ -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 \`agent-method upgrade ${directory}\` to update.`;
41
+ `Run \`npx wwa upgrade ${directory}\` to update.`;
42
42
  }
43
43
 
44
44
  if (opts.json) {
@@ -1,4 +1,4 @@
1
- /** agent-method upgrade — brownfield-safe methodology update. */
1
+ /** wwa upgrade — brownfield-safe methodology update. */
2
2
 
3
3
  import {
4
4
  readFileSync, existsSync, copyFileSync, mkdirSync, writeFileSync,
@@ -39,7 +39,7 @@ export function register(program) {
39
39
  if (!existsSync(srcDir)) {
40
40
  console.error(
41
41
  `Template directory not found: ${srcDir}. ` +
42
- "Run from the agent-method repo or install from source."
42
+ "Run from the wwa repo or install from source."
43
43
  );
44
44
  process.exit(1);
45
45
  }
@@ -65,7 +65,7 @@ export function register(program) {
65
65
  `## Method version\n\n` +
66
66
  `method_version: ${newVer}\n` +
67
67
  `<!-- Tracks which methodology version generated this entry point -->\n` +
68
- `<!-- Use \`agent-method status\` to compare against latest -->\n\n`;
68
+ `<!-- Use \`npx wwa status\` to compare against latest -->\n\n`;
69
69
  content = content.replace("## Conventions", insert + "## Conventions");
70
70
  writeFileSync(ep, content, "utf-8");
71
71
  }
@@ -100,8 +100,8 @@ export function register(program) {
100
100
  if (content.includes("<!-- INSTRUCTION: Add project-specific cascade")) {
101
101
  content = content.replace(
102
102
  "<!-- INSTRUCTION: Add project-specific cascade",
103
- "| Session close | SESSION-LOG.md (append micro-entry" +
104
- " \u2014 workflow, features, cascades, friction, findings) " +
103
+ "| Session close or high-effort task completion | SESSION-LOG.md (append metrics entry" +
104
+ " \u2014 effort, ambiguity, context level, tokens, time, workflow, features, cascades, friction, findings) " +
105
105
  "|\n\n<!-- INSTRUCTION: Add project-specific cascade"
106
106
  );
107
107
  writeFileSync(ep, content, "utf-8");
@@ -119,8 +119,9 @@ export function register(program) {
119
119
  if (content.includes("## Do not")) {
120
120
  content = content.replace(
121
121
  "## Do not",
122
- "- At session close, append a micro-entry to " +
123
- "SESSION-LOG.md \u2014 never skip, never read " +
122
+ "- At session close or after any high-effort task, append a metrics entry to " +
123
+ "SESSION-LOG.md \u2014 include effort level, question ambiguity, context level, " +
124
+ "estimated tokens, and time. Never skip, never read " +
124
125
  "previous entries during normal work\n\n" +
125
126
  "## Do not"
126
127
  );
@@ -0,0 +1,32 @@
1
+ /** wwa watch — file watcher for proactive validation. */
2
+
3
+ export function register(program) {
4
+ program
5
+ .command("watch [directory]")
6
+ .description("Watch entry points and markdown files for changes, validate on save")
7
+ .option("--registry <path>", "Path to feature-registry.yaml")
8
+ .action(async (directory, opts) => {
9
+ const dir = directory || ".";
10
+
11
+ console.log(`Watching: ${dir}`);
12
+ console.log("Monitoring entry points, registry, and markdown files...");
13
+ console.log("Press Ctrl+C to stop.\n");
14
+
15
+ try {
16
+ const { createWatcher } = await import("../watcher.js");
17
+ const watcher = createWatcher(dir, {
18
+ registryPath: opts.registry || undefined,
19
+ });
20
+
21
+ // Keep process alive
22
+ process.on("SIGINT", () => {
23
+ watcher.close();
24
+ console.log("\nWatcher stopped.");
25
+ process.exit(0);
26
+ });
27
+ } catch (err) {
28
+ console.error(`Error: ${err.message}`);
29
+ process.exit(1);
30
+ }
31
+ });
32
+ }
package/lib/init.js CHANGED
@@ -5,7 +5,7 @@
5
5
  * prompts for project configuration.
6
6
  */
7
7
 
8
- import { existsSync, mkdirSync, copyFileSync, readFileSync, writeFileSync, readdirSync } from "node:fs";
8
+ import { existsSync, mkdirSync, copyFileSync, readFileSync, writeFileSync, readdirSync, unlinkSync } from "node:fs";
9
9
  import { resolve, join, dirname, basename, relative } from "node:path";
10
10
  import { fileURLToPath } from "node:url";
11
11
 
@@ -26,11 +26,17 @@ const FRIENDLY_NAMES = {
26
26
  general: "General project",
27
27
  };
28
28
 
29
+ const RUNTIME_ENTRY_POINTS = {
30
+ claude: "CLAUDE.md",
31
+ cursor: ".cursorrules",
32
+ all: null, // keep all
33
+ };
34
+
29
35
  /**
30
36
  * Set up a new project with methodology templates.
31
37
  */
32
38
  export async function initProject(projectType, directory, opts = {}) {
33
- const { tier = "starter", registryPath } = opts;
39
+ const { tier = "starter", runtime = "all", profile = "standard", registryPath } = opts;
34
40
  const targetDir = resolve(directory);
35
41
  const methodRoot = resolve(__dirname, "..");
36
42
 
@@ -42,6 +48,8 @@ export async function initProject(projectType, directory, opts = {}) {
42
48
 
43
49
  console.log(`\nSetting up ${FRIENDLY_NAMES[projectType] || projectType} project`);
44
50
  console.log(` Template: ${tier}`);
51
+ console.log(` Profile: ${profile}`);
52
+ console.log(` Runtime: ${runtime}`);
45
53
  console.log(` Target: ${targetDir}\n`);
46
54
 
47
55
  // Detect brownfield (existing project with methodology files)
@@ -72,21 +80,38 @@ export async function initProject(projectType, directory, opts = {}) {
72
80
  // Replace placeholders in entry points
73
81
  replacePlaceholders(targetDir, projectType, tier);
74
82
 
83
+ // Set integration profile in entry points
84
+ setProfile(targetDir, profile);
85
+
86
+ // Remove unused entry points based on runtime choice
87
+ const removed = removeUnusedEntryPoints(targetDir, runtime, isBrownfield);
88
+
75
89
  // Report
76
90
  console.log(` Files created: ${copied.length}`);
77
91
  for (const f of copied) console.log(` + ${f}`);
92
+ if (removed.length > 0) {
93
+ console.log(` Entry points removed: ${removed.length}`);
94
+ for (const f of removed) console.log(` - ${f}`);
95
+ }
78
96
  if (skipped.length > 0) {
79
97
  console.log(` Files skipped (already exist): ${skipped.length}`);
80
98
  for (const f of skipped) console.log(` ~ ${f}`);
81
99
  }
82
100
 
101
+ // Determine which entry point the user kept
102
+ const keptEntry = runtime === "claude" ? "CLAUDE.md"
103
+ : runtime === "cursor" ? ".cursorrules"
104
+ : "CLAUDE.md / .cursorrules / AGENT.md";
105
+
83
106
  console.log(`\nNext steps:`);
84
107
  console.log(` 1. cd ${relative(process.cwd(), targetDir) || "."}`);
85
108
  console.log(` 2. Fill in PROJECT.md with your project vision`);
86
- console.log(` 3. Delete the two entry point files you don't use`);
87
- console.log(` (keep CLAUDE.md, .cursorrules, or AGENT.md)`);
88
- console.log(` 4. Start a conversation — the agent reads the entry point`);
89
- console.log(`\nRun \`agent-method check\` to validate your setup.`);
109
+ if (runtime === "all") {
110
+ console.log(` 3. Delete the two entry point files you don't use`);
111
+ console.log(` (keep CLAUDE.md, .cursorrules, or AGENT.md)`);
112
+ }
113
+ console.log(` ${runtime === "all" ? "4" : "3"}. Start a conversation — the agent reads ${keptEntry} automatically`);
114
+ console.log(`\nVerify: npx wwa check`);
90
115
  }
91
116
 
92
117
  function detectBrownfield(dir) {
@@ -238,3 +263,34 @@ function replacePlaceholders(targetDir, projectType, tier) {
238
263
  writeFileSync(epPath, content, "utf-8");
239
264
  }
240
265
  }
266
+
267
+ function setProfile(targetDir, profile) {
268
+ for (const epName of ["CLAUDE.md", ".cursorrules", "AGENT.md"]) {
269
+ const epPath = join(targetDir, epName);
270
+ if (!existsSync(epPath)) continue;
271
+
272
+ let content = readFileSync(epPath, "utf-8");
273
+ content = content.replace(/tier:\s*(lite|standard|full)/, `tier: ${profile}`);
274
+ writeFileSync(epPath, content, "utf-8");
275
+ }
276
+ }
277
+
278
+ function removeUnusedEntryPoints(targetDir, runtime, isBrownfield) {
279
+ if (runtime === "all" || isBrownfield) return [];
280
+
281
+ const allEntryPoints = ["CLAUDE.md", ".cursorrules", "AGENT.md"];
282
+ const keep = RUNTIME_ENTRY_POINTS[runtime];
283
+ if (!keep) return [];
284
+
285
+ const removed = [];
286
+ for (const ep of allEntryPoints) {
287
+ if (ep !== keep) {
288
+ const epPath = join(targetDir, ep);
289
+ if (existsSync(epPath)) {
290
+ unlinkSync(epPath);
291
+ removed.push(ep);
292
+ }
293
+ }
294
+ }
295
+ return removed;
296
+ }