agent-method 1.5.1 → 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/README.md +141 -151
- package/bin/{agent-method.js → wwa.js} +12 -4
- package/lib/cli/check.js +2 -2
- package/lib/cli/init.js +107 -17
- package/lib/cli/pipeline.js +1 -1
- package/lib/cli/refine.js +3 -3
- package/lib/cli/route.js +1 -1
- package/lib/cli/scan.js +3 -3
- package/lib/cli/serve.js +23 -0
- package/lib/cli/status.js +2 -2
- package/lib/cli/upgrade.js +8 -7
- package/lib/cli/watch.js +32 -0
- package/lib/init.js +62 -6
- package/lib/mcp-server.js +524 -0
- package/lib/pipeline.js +1 -1
- package/lib/registry.js +1 -1
- package/lib/watcher.js +165 -0
- package/package.json +7 -5
- package/templates/README.md +24 -20
- package/templates/entry-points/.cursorrules +11 -11
- package/templates/entry-points/AGENT.md +11 -11
- package/templates/entry-points/CLAUDE.md +11 -11
- package/templates/full/.cursorrules +11 -11
- package/templates/full/AGENT.md +11 -11
- package/templates/full/CLAUDE.md +11 -11
- package/templates/full/SESSION-LOG.md +37 -5
- package/templates/starter/.cursorrules +11 -11
- package/templates/starter/AGENT.md +11 -11
- package/templates/starter/CLAUDE.md +11 -11
- package/templates/starter/SESSION-LOG.md +37 -5
package/lib/cli/route.js
CHANGED
package/lib/cli/scan.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/**
|
|
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 = `npx
|
|
20
|
+
result.init_command = `npx wwa init ${friendlyMap[ptype]}`;
|
|
21
21
|
} else {
|
|
22
|
-
result.init_command = `npx
|
|
22
|
+
result.init_command = `npx wwa init ${ptype}`;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
console.log(`Scanning: ${directory}`);
|
package/lib/cli/serve.js
ADDED
|
@@ -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
|
-
/**
|
|
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 \`npx
|
|
41
|
+
`Run \`npx wwa upgrade ${directory}\` to update.`;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
if (opts.json) {
|
package/lib/cli/upgrade.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/**
|
|
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
|
|
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 \`npx
|
|
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
|
|
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
|
|
123
|
-
"SESSION-LOG.md \u2014
|
|
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
|
);
|
package/lib/cli/watch.js
ADDED
|
@@ -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
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
+
}
|