agent-method 1.5.1 → 1.5.5

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.
@@ -1,146 +1,149 @@
1
- /** agent-method upgrade — brownfield-safe methodology update. */
2
-
3
- import {
4
- readFileSync, existsSync, copyFileSync, mkdirSync, writeFileSync,
5
- } from "node:fs";
6
- import { resolve, join, dirname } from "node:path";
7
- import {
8
- findEntryPoint, readMethodVersion, basename_of, pkg, packageRoot,
9
- } from "./helpers.js";
10
-
11
- export function register(program) {
12
- program
13
- .command("upgrade [directory]")
14
- .description("Update your project to the latest methodology version")
15
- .option("--dry-run", "Show what would change without modifying files")
16
- .action(async (directory, opts) => {
17
- directory = directory || ".";
18
- const d = resolve(directory);
19
- const ep = findEntryPoint(directory);
20
- const actions = [];
21
-
22
- const templateDirs = {
23
- starter: join(packageRoot, "templates", "starter"),
24
- full: join(packageRoot, "templates", "full"),
25
- };
26
-
27
- // Determine which template tier this project uses
28
- let tier = "starter";
29
- if (existsSync(join(d, ".context", "REGISTRY.md"))) {
30
- tier = "full";
31
- } else if (
32
- existsSync(join(d, "REQUIREMENTS.md")) &&
33
- existsSync(join(d, "SUMMARY.md"))
34
- ) {
35
- tier = "full";
36
- }
37
- const srcDir = templateDirs[tier] || templateDirs.starter;
38
-
39
- if (!existsSync(srcDir)) {
40
- console.error(
41
- `Template directory not found: ${srcDir}. ` +
42
- "Run from the agent-method repo or install from source."
43
- );
44
- process.exit(1);
45
- }
46
-
47
- // 1. Update method_version in entry point
48
- if (ep) {
49
- let content = readFileSync(ep, "utf-8");
50
- const currentVer = readMethodVersion(ep);
51
- const newVer = pkg.version.split(".").slice(0, 2).join(".");
52
- if (currentVer && currentVer !== newVer) {
53
- actions.push(
54
- `Update ${basename_of(ep)}: method_version ${currentVer} -> ${newVer}`
55
- );
56
- if (!opts.dryRun) {
57
- content = content.replace(/(method_version:\s*)\S+/, `$1${newVer}`);
58
- writeFileSync(ep, content, "utf-8");
59
- }
60
- } else if (!currentVer) {
61
- actions.push(`Add method_version: ${newVer} to ${basename_of(ep)}`);
62
- if (!opts.dryRun) {
63
- if (content.includes("## Conventions")) {
64
- const insert =
65
- `## Method version\n\n` +
66
- `method_version: ${newVer}\n` +
67
- `<!-- Tracks which methodology version generated this entry point -->\n` +
68
- `<!-- Use \`npx agent-method status\` to compare against latest -->\n\n`;
69
- content = content.replace("## Conventions", insert + "## Conventions");
70
- writeFileSync(ep, content, "utf-8");
71
- }
72
- }
73
- }
74
- }
75
-
76
- // 2. Add missing methodology files (brownfield-safe: skip existing)
77
- const methodologyFiles = ["SESSION-LOG.md", "PROJECT-PROFILE.md"];
78
- if (tier === "full") {
79
- methodologyFiles.push(join(".context", "METHODOLOGY.md"));
80
- }
81
-
82
- for (const fname of methodologyFiles) {
83
- const src = join(srcDir, fname);
84
- const dst = join(d, fname);
85
- if (existsSync(src) && !existsSync(dst)) {
86
- actions.push(`Create ${fname} (new)`);
87
- if (!opts.dryRun) {
88
- mkdirSync(dirname(dst), { recursive: true });
89
- copyFileSync(src, dst);
90
- }
91
- }
92
- }
93
-
94
- // 3. Check for session close cascade (add if missing)
95
- if (ep) {
96
- let content = readFileSync(ep, "utf-8");
97
- if (!content.toLowerCase().includes("session close")) {
98
- actions.push(`Add session close cascade rule to ${basename_of(ep)}`);
99
- if (!opts.dryRun) {
100
- if (content.includes("<!-- INSTRUCTION: Add project-specific cascade")) {
101
- content = content.replace(
102
- "<!-- INSTRUCTION: Add project-specific cascade",
103
- "| Session close | SESSION-LOG.md (append micro-entry" +
104
- " \u2014 workflow, features, cascades, friction, findings) " +
105
- "|\n\n<!-- INSTRUCTION: Add project-specific cascade"
106
- );
107
- writeFileSync(ep, content, "utf-8");
108
- }
109
- }
110
- }
111
-
112
- // 4. Check for session observation convention
113
- content = readFileSync(ep, "utf-8");
114
- if (!content.toLowerCase().includes("session-log")) {
115
- actions.push(
116
- `Add session observation convention to ${basename_of(ep)}`
117
- );
118
- if (!opts.dryRun) {
119
- if (content.includes("## Do not")) {
120
- content = content.replace(
121
- "## Do not",
122
- "- At session close, append a micro-entry to " +
123
- "SESSION-LOG.md \u2014 never skip, never read " +
124
- "previous entries during normal work\n\n" +
125
- "## Do not"
126
- );
127
- writeFileSync(ep, content, "utf-8");
128
- }
129
- }
130
- }
131
- }
132
-
133
- // Report
134
- if (actions.length === 0) {
135
- console.log(`Project at ${directory} is up to date (v${pkg.version}).`);
136
- } else if (opts.dryRun) {
137
- console.log(`Dry run \u2014 ${actions.length} changes needed:`);
138
- for (const a of actions) console.log(` - ${a}`);
139
- } else {
140
- console.log(
141
- `Upgraded ${directory} to methodology v${pkg.version} (${actions.length} changes):`
142
- );
143
- for (const a of actions) console.log(` - ${a}`);
144
- }
145
- });
146
- }
1
+ /** wwa upgrade — brownfield-safe methodology update. */
2
+
3
+ import {
4
+ readFileSync, existsSync, copyFileSync, mkdirSync, writeFileSync,
5
+ } from "node:fs";
6
+ import { resolve, join, dirname } from "node:path";
7
+ import {
8
+ findEntryPoint, readMethodVersion, basename_of, pkg, packageRoot,
9
+ } from "./helpers.js";
10
+
11
+ export function register(program) {
12
+ program
13
+ .command("upgrade [directory]")
14
+ .description("Update your project to the latest methodology version")
15
+ .option("--dry-run", "Show what would change without modifying files")
16
+ .action(async (directory, opts) => {
17
+ directory = directory || ".";
18
+ const d = resolve(directory);
19
+ const ep = findEntryPoint(directory);
20
+ const actions = [];
21
+
22
+ const templateDirs = {
23
+ starter: join(packageRoot, "templates", "starter"),
24
+ full: join(packageRoot, "templates", "full"),
25
+ };
26
+
27
+ // Determine which template tier this project uses
28
+ let tier = "starter";
29
+ if (existsSync(join(d, ".context", "REGISTRY.md"))) {
30
+ tier = "full";
31
+ } else if (
32
+ existsSync(join(d, "REQUIREMENTS.md")) &&
33
+ existsSync(join(d, "SUMMARY.md"))
34
+ ) {
35
+ tier = "full";
36
+ }
37
+ const srcDir = templateDirs[tier] || templateDirs.starter;
38
+
39
+ if (!existsSync(srcDir)) {
40
+ console.error(
41
+ `Template directory not found: ${srcDir}. ` +
42
+ "Run from the wwa repo or install from source."
43
+ );
44
+ process.exit(1);
45
+ }
46
+
47
+ // 1. Update method_version in entry point
48
+ if (ep) {
49
+ let content = readFileSync(ep, "utf-8");
50
+ const currentVer = readMethodVersion(ep);
51
+ const newVer = pkg.version.split(".").slice(0, 2).join(".");
52
+ if (currentVer && currentVer !== newVer) {
53
+ actions.push(
54
+ `Update ${basename_of(ep)}: method_version ${currentVer} -> ${newVer}`
55
+ );
56
+ if (!opts.dryRun) {
57
+ content = content.replace(/(method_version:\s*)\S+/, `$1${newVer}`);
58
+ writeFileSync(ep, content, "utf-8");
59
+ }
60
+ } else if (!currentVer) {
61
+ actions.push(`Add method_version: ${newVer} to ${basename_of(ep)}`);
62
+ if (!opts.dryRun) {
63
+ if (content.includes("## Conventions")) {
64
+ const insert =
65
+ `## Method version\n\n` +
66
+ `method_version: ${newVer}\n` +
67
+ `<!-- Tracks which methodology version generated this entry point -->\n` +
68
+ `<!-- Use \`npx agent-method status\` to compare against latest -->\n\n`;
69
+ content = content.replace("## Conventions", insert + "## Conventions");
70
+ writeFileSync(ep, content, "utf-8");
71
+ }
72
+ }
73
+ }
74
+ }
75
+
76
+ // 2. Add missing methodology files (brownfield-safe: skip existing)
77
+ const methodologyFiles = ["SESSION-LOG.md", "PROJECT-PROFILE.md"];
78
+ if (tier === "full") {
79
+ methodologyFiles.push(join(".context", "METHODOLOGY.md"));
80
+ }
81
+
82
+ for (const fname of methodologyFiles) {
83
+ const src = join(srcDir, fname);
84
+ const dst = join(d, fname);
85
+ if (existsSync(src) && !existsSync(dst)) {
86
+ actions.push(`Create ${fname} (new)`);
87
+ if (!opts.dryRun) {
88
+ mkdirSync(dirname(dst), { recursive: true });
89
+ copyFileSync(src, dst);
90
+ }
91
+ }
92
+ }
93
+
94
+ // 3. Check for session close cascade (add if missing)
95
+ if (ep) {
96
+ let content = readFileSync(ep, "utf-8");
97
+ if (!content.toLowerCase().includes("session close")) {
98
+ actions.push(`Add session close cascade rule to ${basename_of(ep)}`);
99
+ if (!opts.dryRun) {
100
+ if (content.includes("<!-- INSTRUCTION: Add project-specific cascade")) {
101
+ content = content.replace(
102
+ "<!-- INSTRUCTION: Add project-specific cascade",
103
+ "| Session close or high-effort task completion | SESSION-LOG.md (append metrics entry" +
104
+ " \u2014 effort, ambiguity, context level, tokens, time, user response, refinement delta, workflow, features, cascades, friction, findings) " +
105
+ "|\n\n<!-- INSTRUCTION: Add project-specific cascade"
106
+ );
107
+ writeFileSync(ep, content, "utf-8");
108
+ }
109
+ }
110
+ }
111
+
112
+ // 4. Check for session observation convention
113
+ content = readFileSync(ep, "utf-8");
114
+ if (!content.toLowerCase().includes("session-log")) {
115
+ actions.push(
116
+ `Add session observation convention to ${basename_of(ep)}`
117
+ );
118
+ if (!opts.dryRun) {
119
+ if (content.includes("## Do not")) {
120
+ content = content.replace(
121
+ "## Do not",
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, time, user response (accepted/edited/revised/rejected/redirected), " +
125
+ "and for medium/high effort tasks: revision count, refinement magnitude " +
126
+ "(none/minor/moderate/major/rework), delta categories, and survival rate. Never skip, never read " +
127
+ "previous entries during normal work\n\n" +
128
+ "## Do not"
129
+ );
130
+ writeFileSync(ep, content, "utf-8");
131
+ }
132
+ }
133
+ }
134
+ }
135
+
136
+ // Report
137
+ if (actions.length === 0) {
138
+ console.log(`Project at ${directory} is up to date (v${pkg.version}).`);
139
+ } else if (opts.dryRun) {
140
+ console.log(`Dry run \u2014 ${actions.length} changes needed:`);
141
+ for (const a of actions) console.log(` - ${a}`);
142
+ } else {
143
+ console.log(
144
+ `Upgraded ${directory} to methodology v${pkg.version} (${actions.length} changes):`
145
+ );
146
+ for (const a of actions) console.log(` - ${a}`);
147
+ }
148
+ });
149
+ }
@@ -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
+ }