@waycraft/waypoint-mcp 0.1.0
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/LICENSE +21 -0
- package/README.md +110 -0
- package/dist/context.js +79 -0
- package/dist/index.js +46 -0
- package/dist/tools/audit.js +311 -0
- package/dist/tools/build.js +112 -0
- package/dist/tools/compare.js +92 -0
- package/dist/tools/debug.js +148 -0
- package/dist/tools/design.js +276 -0
- package/dist/tools/document.js +107 -0
- package/dist/tools/fix.js +103 -0
- package/dist/tools/goal.js +94 -0
- package/dist/tools/improve.js +99 -0
- package/dist/tools/measure.js +101 -0
- package/dist/tools/plan.js +107 -0
- package/dist/tools/research.js +104 -0
- package/dist/tools/review.js +123 -0
- package/dist/tools/test.js +107 -0
- package/package.json +38 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { getBaseContext, getArtifact, saveArtifact } from "../context.js";
|
|
2
|
+
export const definition = {
|
|
3
|
+
name: "waypoint_compare",
|
|
4
|
+
description: "Present decision tradeoffs, comparison methods, UI mockups if relevant.",
|
|
5
|
+
inputSchema: {
|
|
6
|
+
type: "object",
|
|
7
|
+
properties: {
|
|
8
|
+
workspacePath: {
|
|
9
|
+
type: "string",
|
|
10
|
+
description: "Absolute path to the workspace root.",
|
|
11
|
+
},
|
|
12
|
+
decision: {
|
|
13
|
+
type: "string",
|
|
14
|
+
description: "Specific decision to evaluate (optional). Omit to evaluate all open decisions from research.",
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
required: ["workspacePath"],
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
export async function run(args) {
|
|
21
|
+
const { workspacePath, decision } = args;
|
|
22
|
+
const ctx = await getBaseContext(workspacePath);
|
|
23
|
+
const goalArtifact = await getArtifact(workspacePath, "goal.md");
|
|
24
|
+
const researchArtifact = await getArtifact(workspacePath, "research.md");
|
|
25
|
+
if (!goalArtifact) {
|
|
26
|
+
return [
|
|
27
|
+
"## waypoint_compare — No goal found",
|
|
28
|
+
"",
|
|
29
|
+
"Run `waypoint_goal` first, then `waypoint_research` before evaluating options.",
|
|
30
|
+
].join("\n");
|
|
31
|
+
}
|
|
32
|
+
const goalLine = goalArtifact.match(/^# Goal\n+(.+)/m)?.[1] ?? "(goal not parsed)";
|
|
33
|
+
const hasResearch = !!researchArtifact;
|
|
34
|
+
const artifact = [
|
|
35
|
+
"# Options",
|
|
36
|
+
"",
|
|
37
|
+
`**Goal:** ${goalLine}`,
|
|
38
|
+
decision ? `**Decision under evaluation:** ${decision}` : "",
|
|
39
|
+
!hasResearch ? "\n> ⚠️ No research.md found — options may be incomplete. Run `waypoint_research` first." : "",
|
|
40
|
+
"",
|
|
41
|
+
"## Decision log",
|
|
42
|
+
"<!-- Record each key decision, the options considered, and the choice made -->",
|
|
43
|
+
"",
|
|
44
|
+
"### Decision 1",
|
|
45
|
+
`**Question:** ${decision ?? "What approach best satisfies the goal?"}`,
|
|
46
|
+
"",
|
|
47
|
+
"| Option | Pros | Cons | Fit |",
|
|
48
|
+
"|--------|------|------|-----|",
|
|
49
|
+
"| Option A | | | |",
|
|
50
|
+
"| Option B | | | |",
|
|
51
|
+
"| Option C | | | |",
|
|
52
|
+
"",
|
|
53
|
+
"**Recommended:** <!-- State your recommendation and the deciding factor -->",
|
|
54
|
+
"**Rationale:** <!-- Why this option over the others? -->",
|
|
55
|
+
"",
|
|
56
|
+
"## Eliminated approaches",
|
|
57
|
+
"<!-- Options ruled out early and why — prevents revisiting dead ends -->",
|
|
58
|
+
"- ",
|
|
59
|
+
"",
|
|
60
|
+
"## Assumptions & constraints",
|
|
61
|
+
"<!-- What must be true for the chosen option to work? -->",
|
|
62
|
+
"- ",
|
|
63
|
+
"",
|
|
64
|
+
`_Generated by waypoint_compare — ${new Date().toISOString()}_`,
|
|
65
|
+
]
|
|
66
|
+
.filter((l) => l !== undefined)
|
|
67
|
+
.join("\n");
|
|
68
|
+
await saveArtifact(workspacePath, "compare.md", artifact);
|
|
69
|
+
return [
|
|
70
|
+
"## waypoint_compare — Decision framework generated",
|
|
71
|
+
"",
|
|
72
|
+
`**Goal:** ${goalLine}`,
|
|
73
|
+
decision ? `**Decision focus:** ${decision}` : "",
|
|
74
|
+
!hasResearch
|
|
75
|
+
? "\n> No research.md found — consider running `waypoint_research` first for more informed options."
|
|
76
|
+
: "",
|
|
77
|
+
"",
|
|
78
|
+
"### How to use compare.md",
|
|
79
|
+
"1. Fill in the decision table — one row per option",
|
|
80
|
+
"2. State pros, cons, and fit for each",
|
|
81
|
+
"3. Write a **Recommended** line with clear rationale",
|
|
82
|
+
"4. List eliminated approaches to avoid revisiting them",
|
|
83
|
+
"",
|
|
84
|
+
"### Artifact saved",
|
|
85
|
+
"`compare.md` written to `.waypoint/compare.md`.",
|
|
86
|
+
"",
|
|
87
|
+
"### Suggested next step",
|
|
88
|
+
"Run `waypoint_plan` once decisions are recorded.",
|
|
89
|
+
]
|
|
90
|
+
.filter((l) => l !== undefined)
|
|
91
|
+
.join("\n");
|
|
92
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { getBaseContext, getArtifact, saveArtifact } from "../context.js";
|
|
2
|
+
export const definition = {
|
|
3
|
+
name: "waypoint_debug",
|
|
4
|
+
description: "Read-only diagnostics. Mode troubleshoot = root cause framing. Mode trace = execution path analysis.",
|
|
5
|
+
inputSchema: {
|
|
6
|
+
type: "object",
|
|
7
|
+
properties: {
|
|
8
|
+
workspacePath: {
|
|
9
|
+
type: "string",
|
|
10
|
+
description: "Absolute path to the workspace root.",
|
|
11
|
+
},
|
|
12
|
+
mode: {
|
|
13
|
+
type: "string",
|
|
14
|
+
enum: ["troubleshoot", "trace"],
|
|
15
|
+
description: "troubleshoot = root cause framing. trace = execution path analysis.",
|
|
16
|
+
},
|
|
17
|
+
symptom: {
|
|
18
|
+
type: "string",
|
|
19
|
+
description: "Observed symptom or failure to diagnose (optional).",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
required: ["workspacePath", "mode"],
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
export async function run(args) {
|
|
26
|
+
const { workspacePath, mode, symptom } = args;
|
|
27
|
+
const ctx = await getBaseContext(workspacePath);
|
|
28
|
+
const buildArtifact = await getArtifact(workspacePath, "build.md");
|
|
29
|
+
const goalArtifact = await getArtifact(workspacePath, "goal.md");
|
|
30
|
+
const goalLine = goalArtifact?.match(/^# Goal\n+(.+)/m)?.[1] ?? "(no goal defined)";
|
|
31
|
+
const focus = symptom ?? "unspecified symptom";
|
|
32
|
+
let modeContent;
|
|
33
|
+
if (mode === "troubleshoot") {
|
|
34
|
+
modeContent = [
|
|
35
|
+
"## Troubleshoot — Root cause framing",
|
|
36
|
+
"",
|
|
37
|
+
`**Symptom:** ${focus}`,
|
|
38
|
+
"",
|
|
39
|
+
"### Is/Is-not analysis",
|
|
40
|
+
"| Dimension | Is | Is Not |",
|
|
41
|
+
"|-----------|-----|--------|",
|
|
42
|
+
"| What | | |",
|
|
43
|
+
"| Where | | |",
|
|
44
|
+
"| When | | |",
|
|
45
|
+
"| Extent | | |",
|
|
46
|
+
"",
|
|
47
|
+
"### Root cause hypotheses",
|
|
48
|
+
"<!-- Rank by likelihood — most likely first -->",
|
|
49
|
+
"1. ",
|
|
50
|
+
"2. ",
|
|
51
|
+
"3. ",
|
|
52
|
+
"",
|
|
53
|
+
"### Diagnostic steps",
|
|
54
|
+
"<!-- Ordered read-only checks to confirm or rule out each hypothesis -->",
|
|
55
|
+
"- [ ] Check logs for errors around the time of symptom",
|
|
56
|
+
"- [ ] Reproduce symptom in isolation",
|
|
57
|
+
"- [ ] Identify the last known good state",
|
|
58
|
+
"- [ ] Diff current state against known good",
|
|
59
|
+
"",
|
|
60
|
+
"### AI diagnostic prompt",
|
|
61
|
+
"```",
|
|
62
|
+
`Diagnose the following symptom without modifying any code: ${focus}`,
|
|
63
|
+
"",
|
|
64
|
+
"Steps:",
|
|
65
|
+
"1. Identify the likely root cause",
|
|
66
|
+
"2. List evidence that supports or refutes each hypothesis",
|
|
67
|
+
"3. Propose the minimal targeted fix — do not implement it yet",
|
|
68
|
+
"```",
|
|
69
|
+
];
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
modeContent = [
|
|
73
|
+
"## Trace — Execution path analysis",
|
|
74
|
+
"",
|
|
75
|
+
`**Symptom:** ${focus}`,
|
|
76
|
+
"",
|
|
77
|
+
"### Entry point",
|
|
78
|
+
"<!-- Where does execution begin for this flow? -->",
|
|
79
|
+
"- ",
|
|
80
|
+
"",
|
|
81
|
+
"### Execution path",
|
|
82
|
+
"<!-- Step-by-step: function → function → output -->",
|
|
83
|
+
"1. ",
|
|
84
|
+
"2. ",
|
|
85
|
+
"3. ",
|
|
86
|
+
"",
|
|
87
|
+
"### Observed vs expected at each step",
|
|
88
|
+
"| Step | Expected | Observed | Diverges? |",
|
|
89
|
+
"|------|----------|----------|-----------|",
|
|
90
|
+
"| | | | |",
|
|
91
|
+
"",
|
|
92
|
+
"### Divergence point",
|
|
93
|
+
"<!-- Where exactly does actual behavior first differ from expected? -->",
|
|
94
|
+
"- ",
|
|
95
|
+
"",
|
|
96
|
+
"### AI trace prompt",
|
|
97
|
+
"```",
|
|
98
|
+
`Trace the execution path for: ${focus}`,
|
|
99
|
+
"",
|
|
100
|
+
"Without modifying any code:",
|
|
101
|
+
"1. Follow the call chain from entry point to output",
|
|
102
|
+
"2. Identify where the observed behavior first diverges from expected",
|
|
103
|
+
"3. Explain why that divergence occurs",
|
|
104
|
+
"```",
|
|
105
|
+
];
|
|
106
|
+
}
|
|
107
|
+
const artifact = [
|
|
108
|
+
"# Diagnose",
|
|
109
|
+
"",
|
|
110
|
+
`**Mode:** ${mode}`,
|
|
111
|
+
`**Goal context:** ${goalLine}`,
|
|
112
|
+
!buildArtifact ? "\n> ⚠️ No build.md found — diagnosis has no build baseline." : "",
|
|
113
|
+
"",
|
|
114
|
+
...modeContent,
|
|
115
|
+
"",
|
|
116
|
+
"## Workspace snapshot",
|
|
117
|
+
`**Files:** \n\`\`\`\n${ctx.fileTree}\n\`\`\``,
|
|
118
|
+
"",
|
|
119
|
+
`_Generated by waypoint_debug (${mode}) — ${new Date().toISOString()}_`,
|
|
120
|
+
]
|
|
121
|
+
.filter((l) => l !== undefined)
|
|
122
|
+
.join("\n");
|
|
123
|
+
await saveArtifact(workspacePath, "debug.md", artifact);
|
|
124
|
+
return [
|
|
125
|
+
`## waypoint_debug — ${mode === "troubleshoot" ? "Troubleshoot" : "Trace"} guide generated`,
|
|
126
|
+
"",
|
|
127
|
+
`**Mode:** ${mode}`,
|
|
128
|
+
`**Symptom:** ${focus}`,
|
|
129
|
+
"",
|
|
130
|
+
mode === "troubleshoot"
|
|
131
|
+
? [
|
|
132
|
+
"### Framework: Is/Is-not analysis",
|
|
133
|
+
"Define what the symptom IS and IS NOT across: what, where, when, extent.",
|
|
134
|
+
"Rank hypotheses by likelihood. Run diagnostic steps read-only first.",
|
|
135
|
+
].join("\n")
|
|
136
|
+
: [
|
|
137
|
+
"### Framework: Execution path trace",
|
|
138
|
+
"Map the call chain from entry point to output.",
|
|
139
|
+
"Find the exact step where observed behavior diverges from expected.",
|
|
140
|
+
].join("\n"),
|
|
141
|
+
"",
|
|
142
|
+
"### Artifact saved",
|
|
143
|
+
"`debug.md` written to `.waypoint/debug.md`.",
|
|
144
|
+
"",
|
|
145
|
+
"### Suggested next step",
|
|
146
|
+
"Run `waypoint_fix` once the root cause is confirmed.",
|
|
147
|
+
].join("\n");
|
|
148
|
+
}
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import { getBaseContext, getArtifact, saveArtifact } from "../context.js";
|
|
2
|
+
export const definition = {
|
|
3
|
+
name: "waypoint_design",
|
|
4
|
+
description: "Produce a design contract before building. Infers project tier (Prototype / Product / Platform) from the workspace and plan, confirms with one question, then prescribes patterns, structure, and anti-patterns for Build to follow.",
|
|
5
|
+
inputSchema: {
|
|
6
|
+
type: "object",
|
|
7
|
+
properties: {
|
|
8
|
+
workspacePath: {
|
|
9
|
+
type: "string",
|
|
10
|
+
description: "Absolute path to the workspace root.",
|
|
11
|
+
},
|
|
12
|
+
tier: {
|
|
13
|
+
type: "string",
|
|
14
|
+
enum: ["prototype", "product", "platform"],
|
|
15
|
+
description: "Explicitly set the project tier (optional). Omit to let waypoint_design infer it from the workspace and ask for confirmation.",
|
|
16
|
+
},
|
|
17
|
+
focus: {
|
|
18
|
+
type: "string",
|
|
19
|
+
description: "Specific area to produce design guidance for (optional). E.g. 'auth layer', 'data access', 'API structure'. Omit to cover the full plan.",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
required: ["workspacePath"],
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
// ─── Tier inference ───────────────────────────────────────────────────────────
|
|
26
|
+
function inferTier(ctx, planArtifact) {
|
|
27
|
+
let score = 0;
|
|
28
|
+
const fileTree = ctx.fileTree ?? "";
|
|
29
|
+
const pkg = (() => {
|
|
30
|
+
try {
|
|
31
|
+
return JSON.parse(ctx.packageJson ?? "{}");
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return {};
|
|
35
|
+
}
|
|
36
|
+
})();
|
|
37
|
+
const deps = Object.keys({ ...pkg.dependencies, ...pkg.devDependencies });
|
|
38
|
+
const allText = [fileTree, planArtifact ?? "", ctx.packageJson ?? ""].join("\n").toLowerCase();
|
|
39
|
+
const fileCount = (fileTree.match(/\n/g) ?? []).length;
|
|
40
|
+
if (fileCount > 40)
|
|
41
|
+
score += 2;
|
|
42
|
+
else if (fileCount > 15)
|
|
43
|
+
score += 1;
|
|
44
|
+
if (allText.includes("dockerfile") || allText.includes("docker-compose"))
|
|
45
|
+
score += 2;
|
|
46
|
+
if (allText.includes(".github/workflows") || allText.includes("ci.yml"))
|
|
47
|
+
score += 1;
|
|
48
|
+
if (allText.includes(".env.example") || allText.includes("config/"))
|
|
49
|
+
score += 1;
|
|
50
|
+
if (deps.some(d => ["prisma", "typeorm", "sequelize", "drizzle", "mongoose"].includes(d)))
|
|
51
|
+
score += 2;
|
|
52
|
+
if (deps.some(d => ["passport", "jsonwebtoken", "next-auth", "clerk"].includes(d)))
|
|
53
|
+
score += 1;
|
|
54
|
+
if (deps.some(d => ["jest", "vitest", "mocha", "playwright", "cypress"].includes(d)))
|
|
55
|
+
score += 1;
|
|
56
|
+
if (allText.includes("console.log") && fileCount < 10)
|
|
57
|
+
score -= 1;
|
|
58
|
+
if (allText.includes("todo") || allText.includes("fixme"))
|
|
59
|
+
score -= 1;
|
|
60
|
+
if (!ctx.packageJson)
|
|
61
|
+
score -= 1;
|
|
62
|
+
if (deps.some(d => ["@anthropic-ai/sdk", "openai", "langchain", "@langchain"].includes(d)))
|
|
63
|
+
score += 1;
|
|
64
|
+
if (score >= 6)
|
|
65
|
+
return { tier: "platform", confidence: "high" };
|
|
66
|
+
if (score >= 3)
|
|
67
|
+
return { tier: "product", confidence: score >= 4 ? "high" : "medium" };
|
|
68
|
+
return { tier: "prototype", confidence: score <= 1 ? "high" : "medium" };
|
|
69
|
+
}
|
|
70
|
+
// ─── Pattern sets per tier ────────────────────────────────────────────────────
|
|
71
|
+
const PATTERNS = {
|
|
72
|
+
prototype: {
|
|
73
|
+
label: "Prototype",
|
|
74
|
+
description: "Solo or exploratory — readable, no obvious traps. Avoid premature abstraction.",
|
|
75
|
+
structure: [
|
|
76
|
+
"Flat file structure — group by feature, not by layer",
|
|
77
|
+
"Single entry point (index.js / main.py)",
|
|
78
|
+
"Inline config via process.env — no config module needed yet",
|
|
79
|
+
],
|
|
80
|
+
apply: [
|
|
81
|
+
"Meaningful naming — variables and functions describe intent",
|
|
82
|
+
"No magic numbers — use named constants even in early code",
|
|
83
|
+
"Early returns to reduce nesting",
|
|
84
|
+
"Basic error handling — don't silently swallow errors",
|
|
85
|
+
],
|
|
86
|
+
avoid: [
|
|
87
|
+
"Dependency injection frameworks — premature at this scale",
|
|
88
|
+
"Layered architecture (controllers/services/repos) — adds overhead without benefit",
|
|
89
|
+
"Abstract base classes or interface hierarchies",
|
|
90
|
+
"Over-engineered config systems",
|
|
91
|
+
],
|
|
92
|
+
aiNative: [
|
|
93
|
+
"Prompt strings can live inline — extract to a prompts.js file when there are 3+",
|
|
94
|
+
"LLM calls should have at minimum a try/catch with a readable error message",
|
|
95
|
+
"No observability needed yet — console.log is fine",
|
|
96
|
+
],
|
|
97
|
+
},
|
|
98
|
+
product: {
|
|
99
|
+
label: "Product",
|
|
100
|
+
description: "Small team, real users, will grow — SOLID basics, modularity, testability.",
|
|
101
|
+
structure: [
|
|
102
|
+
"Feature-based folders at the top level (e.g. auth/, payments/, users/)",
|
|
103
|
+
"Within each feature: route/handler → service → repository/data-access",
|
|
104
|
+
"Shared utilities in lib/ or utils/ — no circular imports",
|
|
105
|
+
"Config module (config.js) as single source of truth for env vars",
|
|
106
|
+
"Separate entry point from app setup (index.js bootstraps, app.js configures)",
|
|
107
|
+
],
|
|
108
|
+
apply: [
|
|
109
|
+
"Single responsibility — each function/module does one thing",
|
|
110
|
+
"Dependency injection — pass dependencies as arguments, don't import globals into logic",
|
|
111
|
+
"Input validation at system boundaries (Zod, joi, or equivalent)",
|
|
112
|
+
"Centralized error handling — one error middleware, not scattered try/catches",
|
|
113
|
+
"Named exports over default exports — easier to refactor and trace",
|
|
114
|
+
"No direct DB calls in route handlers — always through a service",
|
|
115
|
+
],
|
|
116
|
+
avoid: [
|
|
117
|
+
"God modules — files over ~200 lines are a warning sign",
|
|
118
|
+
"Hardcoded secrets or environment-specific values in code",
|
|
119
|
+
"Shared mutable state across modules",
|
|
120
|
+
"Deep callback nesting — use async/await throughout",
|
|
121
|
+
"Direct SDK calls scattered across the codebase — wrap in a service",
|
|
122
|
+
],
|
|
123
|
+
aiNative: [
|
|
124
|
+
"Extract prompt strings to a dedicated prompts/ module — never inline in business logic",
|
|
125
|
+
"Wrap every LLM call in a resilience layer: retry on transient errors, timeout, fallback message",
|
|
126
|
+
"Agent tool functions must have single responsibility — one tool = one action",
|
|
127
|
+
"Log token usage at the service layer for cost visibility",
|
|
128
|
+
"Never put raw user input directly into a prompt — sanitize or structure first",
|
|
129
|
+
],
|
|
130
|
+
},
|
|
131
|
+
platform: {
|
|
132
|
+
label: "Platform",
|
|
133
|
+
description: "Multi-team, high scale, long-lived — full patterns, contracts, observability.",
|
|
134
|
+
structure: [
|
|
135
|
+
"Domain-driven folder structure — packages or modules per bounded context",
|
|
136
|
+
"Explicit interface contracts between layers (TypeScript interfaces or JSDoc types)",
|
|
137
|
+
"Shared kernel for cross-cutting concerns (logging, auth, config, errors)",
|
|
138
|
+
"Infrastructure layer isolated from domain logic (ports & adapters)",
|
|
139
|
+
"Separate read and write paths where contention is expected",
|
|
140
|
+
],
|
|
141
|
+
apply: [
|
|
142
|
+
"Full SOLID compliance — especially Open/Closed and Liskov",
|
|
143
|
+
"Repository pattern — domain logic never touches query syntax",
|
|
144
|
+
"Dependency inversion — depend on abstractions, inject implementations",
|
|
145
|
+
"Structured logging with correlation IDs on every request",
|
|
146
|
+
"Circuit breakers on all external service calls",
|
|
147
|
+
"Event-driven side effects — don't couple services via direct calls",
|
|
148
|
+
"Idempotency on all write operations that may be retried",
|
|
149
|
+
],
|
|
150
|
+
avoid: [
|
|
151
|
+
"Anemic domain models — logic belongs in the domain, not scattered in services",
|
|
152
|
+
"Shotgun surgery patterns — a single change requiring edits in 5+ files",
|
|
153
|
+
"Implicit service coupling — make dependencies explicit and injectable",
|
|
154
|
+
"Unversioned external contracts (APIs, events, schemas)",
|
|
155
|
+
"Synchronous calls to non-critical services in the request path",
|
|
156
|
+
],
|
|
157
|
+
aiNative: [
|
|
158
|
+
"Prompt versioning — treat prompts as versioned artifacts with changelogs",
|
|
159
|
+
"LLM call abstraction layer — swap providers without touching business logic",
|
|
160
|
+
"Structured output validation — never trust LLM output shape, always validate",
|
|
161
|
+
"Agent observability — trace each tool call with input, output, latency, tokens",
|
|
162
|
+
"Prompt injection hardening — sanitize all user-controlled content before interpolation",
|
|
163
|
+
"Async agent pipelines — long-running agent tasks should be queued, not blocking",
|
|
164
|
+
],
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
// ─── Confirmation prompt ──────────────────────────────────────────────────────
|
|
168
|
+
function confirmationPrompt(tier, confidence) {
|
|
169
|
+
const label = PATTERNS[tier].label;
|
|
170
|
+
if (confidence === "high") {
|
|
171
|
+
return `> **Tier inferred: ${label}** (high confidence)\n> If this is wrong, re-run \`waypoint_design\` with an explicit \`tier\` parameter.`;
|
|
172
|
+
}
|
|
173
|
+
const alternates = ["prototype", "product", "platform"].filter(t => t !== tier);
|
|
174
|
+
return [
|
|
175
|
+
`> **Tier inferred: ${label}** (medium confidence — mixed signals in the workspace)`,
|
|
176
|
+
`> If this doesn't match your intent, re-run \`waypoint_design\` with \`tier: "${alternates[0]}"\` or \`"${alternates[1]}"\`.`,
|
|
177
|
+
].join("\n");
|
|
178
|
+
}
|
|
179
|
+
// ─── Run ──────────────────────────────────────────────────────────────────────
|
|
180
|
+
export async function run(args) {
|
|
181
|
+
const { workspacePath, tier: explicitTier, focus } = args;
|
|
182
|
+
const ctx = await getBaseContext(workspacePath);
|
|
183
|
+
const planArtifact = await getArtifact(workspacePath, "plan.md");
|
|
184
|
+
const goalArtifact = await getArtifact(workspacePath, "goal.md");
|
|
185
|
+
const optionsArtifact = await getArtifact(workspacePath, "compare.md");
|
|
186
|
+
if (!planArtifact && !goalArtifact) {
|
|
187
|
+
return [
|
|
188
|
+
"## waypoint_design — No plan or goal found",
|
|
189
|
+
"",
|
|
190
|
+
"Run `waypoint_goal` → `waypoint_plan` before producing a design contract.",
|
|
191
|
+
"waypoint_design needs to know what you're building before it can prescribe how to build it.",
|
|
192
|
+
].join("\n");
|
|
193
|
+
}
|
|
194
|
+
const goalLine = goalArtifact?.match(/^# Goal\n+(.+)/m)?.[1] ?? "(goal not parsed)";
|
|
195
|
+
let tierKey;
|
|
196
|
+
let confidence;
|
|
197
|
+
let tierNote;
|
|
198
|
+
if (explicitTier) {
|
|
199
|
+
tierKey = explicitTier;
|
|
200
|
+
confidence = "explicit";
|
|
201
|
+
tierNote = `> **Tier set explicitly: ${PATTERNS[tierKey].label}**`;
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
const inferred = inferTier(ctx, planArtifact);
|
|
205
|
+
tierKey = inferred.tier;
|
|
206
|
+
confidence = inferred.confidence;
|
|
207
|
+
tierNote = confirmationPrompt(tierKey, inferred.confidence);
|
|
208
|
+
}
|
|
209
|
+
const patterns = PATTERNS[tierKey];
|
|
210
|
+
const focusNote = focus ? `\n**Focus:** ${focus}` : "";
|
|
211
|
+
const hasOptions = !!optionsArtifact;
|
|
212
|
+
const optionsNote = !hasOptions
|
|
213
|
+
? "\n> ⚠️ No compare.md found — design contract is based on goal/plan only. Run `waypoint_compare` for richer context."
|
|
214
|
+
: "";
|
|
215
|
+
const artifact = [
|
|
216
|
+
"# Design",
|
|
217
|
+
"",
|
|
218
|
+
`**Goal:** ${goalLine}`,
|
|
219
|
+
focusNote,
|
|
220
|
+
`**Tier:** ${patterns.label} — ${patterns.description}`,
|
|
221
|
+
optionsNote,
|
|
222
|
+
"",
|
|
223
|
+
tierNote,
|
|
224
|
+
"",
|
|
225
|
+
"## Recommended structure",
|
|
226
|
+
...patterns.structure.map(s => `- ${s}`),
|
|
227
|
+
"",
|
|
228
|
+
"## Patterns to apply",
|
|
229
|
+
...patterns.apply.map(p => `- ${p}`),
|
|
230
|
+
"",
|
|
231
|
+
"## Anti-patterns to avoid",
|
|
232
|
+
...patterns.avoid.map(a => `- ❌ ${a}`),
|
|
233
|
+
"",
|
|
234
|
+
"## AI-native considerations",
|
|
235
|
+
...patterns.aiNative.map(n => `- ${n}`),
|
|
236
|
+
"",
|
|
237
|
+
"## Design decisions",
|
|
238
|
+
"<!-- Record any project-specific choices made here — deviations from the above and why -->",
|
|
239
|
+
"- ",
|
|
240
|
+
"",
|
|
241
|
+
"## Contract for Build",
|
|
242
|
+
"<!-- Summarise what Build must honour — fill this in before handing off -->",
|
|
243
|
+
"- [ ] Follow the recommended structure above",
|
|
244
|
+
"- [ ] Apply all patterns marked for this tier",
|
|
245
|
+
"- [ ] Avoid all listed anti-patterns",
|
|
246
|
+
"- [ ] ",
|
|
247
|
+
"",
|
|
248
|
+
`_Generated by waypoint_design (${patterns.label}) — ${new Date().toISOString()}_`,
|
|
249
|
+
]
|
|
250
|
+
.filter(l => l !== undefined)
|
|
251
|
+
.join("\n");
|
|
252
|
+
await saveArtifact(workspacePath, "design.md", artifact);
|
|
253
|
+
return [
|
|
254
|
+
"## waypoint_design — Design contract generated",
|
|
255
|
+
"",
|
|
256
|
+
`**Goal:** ${goalLine}`,
|
|
257
|
+
`**Tier:** ${patterns.label}`,
|
|
258
|
+
focus ? `**Focus:** ${focus}` : "",
|
|
259
|
+
!hasOptions ? "\n> No compare.md — run `waypoint_compare` for decision context." : "",
|
|
260
|
+
"",
|
|
261
|
+
"### Contract covers",
|
|
262
|
+
`- **Structure** — ${patterns.structure.length} recommendations`,
|
|
263
|
+
`- **Patterns to apply** — ${patterns.apply.length} rules`,
|
|
264
|
+
`- **Anti-patterns to avoid** — ${patterns.avoid.length} rules`,
|
|
265
|
+
`- **AI-native** — ${patterns.aiNative.length} considerations`,
|
|
266
|
+
"",
|
|
267
|
+
"### Artifact saved",
|
|
268
|
+
"`design.md` written to `.waypoint/design.md`.",
|
|
269
|
+
"Fill in **Design decisions** for any project-specific deviations, then complete the **Contract for Build** checklist.",
|
|
270
|
+
"",
|
|
271
|
+
"### Suggested next step",
|
|
272
|
+
"Run `waypoint_build` — it will read `design.md` as a constraint alongside `plan.md`.",
|
|
273
|
+
]
|
|
274
|
+
.filter(l => l !== undefined)
|
|
275
|
+
.join("\n");
|
|
276
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { getBaseContext, getArtifact, saveArtifact } from "../context.js";
|
|
2
|
+
export const definition = {
|
|
3
|
+
name: "waypoint_document",
|
|
4
|
+
description: "Generate documentation for the current state of the project.",
|
|
5
|
+
inputSchema: {
|
|
6
|
+
type: "object",
|
|
7
|
+
properties: {
|
|
8
|
+
workspacePath: {
|
|
9
|
+
type: "string",
|
|
10
|
+
description: "Absolute path to the workspace root.",
|
|
11
|
+
},
|
|
12
|
+
audience: {
|
|
13
|
+
type: "string",
|
|
14
|
+
description: "Intended audience for the documentation (optional). E.g. 'new contributors', 'end users', 'API consumers'.",
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
required: ["workspacePath"],
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
export async function run(args) {
|
|
21
|
+
const { workspacePath, audience } = args;
|
|
22
|
+
const ctx = await getBaseContext(workspacePath);
|
|
23
|
+
const goalArtifact = await getArtifact(workspacePath, "goal.md");
|
|
24
|
+
const buildArtifact = await getArtifact(workspacePath, "build.md");
|
|
25
|
+
const planArtifact = await getArtifact(workspacePath, "plan.md");
|
|
26
|
+
const goalLine = goalArtifact?.match(/^# Goal\n+(.+)/m)?.[1] ?? "(goal not defined)";
|
|
27
|
+
const pkgInfo = (() => {
|
|
28
|
+
try {
|
|
29
|
+
const p = JSON.parse(ctx.packageJson ?? "{}");
|
|
30
|
+
return { name: p.name ?? "this project", version: p.version ?? "0.0.0", description: p.description ?? "" };
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return { name: "this project", version: "0.0.0", description: "" };
|
|
34
|
+
}
|
|
35
|
+
})();
|
|
36
|
+
const targetAudience = audience ?? "contributors and users";
|
|
37
|
+
const artifact = [
|
|
38
|
+
"# Documentation",
|
|
39
|
+
"",
|
|
40
|
+
`**Project:** ${pkgInfo.name} v${pkgInfo.version}`,
|
|
41
|
+
pkgInfo.description ? `**Description:** ${pkgInfo.description}` : "",
|
|
42
|
+
`**Audience:** ${targetAudience}`,
|
|
43
|
+
"",
|
|
44
|
+
"## What this is",
|
|
45
|
+
`<!-- 2-3 sentences explaining what ${pkgInfo.name} does and why it exists -->`,
|
|
46
|
+
goalLine !== "(goal not defined)" ? goalLine : "",
|
|
47
|
+
"",
|
|
48
|
+
"## How it works",
|
|
49
|
+
"<!-- High-level architecture or flow — no code, just concepts -->",
|
|
50
|
+
"",
|
|
51
|
+
"```",
|
|
52
|
+
ctx.fileTree,
|
|
53
|
+
"```",
|
|
54
|
+
"",
|
|
55
|
+
"## Getting started",
|
|
56
|
+
"",
|
|
57
|
+
"### Prerequisites",
|
|
58
|
+
"- ",
|
|
59
|
+
"",
|
|
60
|
+
"### Installation",
|
|
61
|
+
"```sh",
|
|
62
|
+
"# installation steps",
|
|
63
|
+
"```",
|
|
64
|
+
"",
|
|
65
|
+
"### Quick start",
|
|
66
|
+
"```sh",
|
|
67
|
+
"# minimal working example",
|
|
68
|
+
"```",
|
|
69
|
+
"",
|
|
70
|
+
"## Key concepts",
|
|
71
|
+
"<!-- Define the 3-5 concepts a reader must understand to use this effectively -->",
|
|
72
|
+
"",
|
|
73
|
+
"### Concept 1",
|
|
74
|
+
"<!-- What it is and why it matters -->",
|
|
75
|
+
"",
|
|
76
|
+
"## Reference",
|
|
77
|
+
"<!-- API, CLI flags, configuration options — one sub-section per entry point -->",
|
|
78
|
+
"",
|
|
79
|
+
"## Known limitations",
|
|
80
|
+
"- ",
|
|
81
|
+
"",
|
|
82
|
+
`_Generated by waypoint_document — ${new Date().toISOString()}_`,
|
|
83
|
+
]
|
|
84
|
+
.filter((l) => l !== undefined)
|
|
85
|
+
.join("\n");
|
|
86
|
+
await saveArtifact(workspacePath, "docs.md", artifact);
|
|
87
|
+
return [
|
|
88
|
+
"## waypoint_document — Documentation generated",
|
|
89
|
+
"",
|
|
90
|
+
`**Project:** ${pkgInfo.name} v${pkgInfo.version}`,
|
|
91
|
+
`**Audience:** ${targetAudience}`,
|
|
92
|
+
"",
|
|
93
|
+
"### Sections scaffolded",
|
|
94
|
+
"- **What this is** — project purpose pulled from goal.md",
|
|
95
|
+
"- **How it works** — architecture overview with file tree",
|
|
96
|
+
"- **Getting started** — prerequisites, install, quick start",
|
|
97
|
+
"- **Key concepts** — fill in 3-5 concepts readers need",
|
|
98
|
+
"- **Reference** — API/CLI/config reference",
|
|
99
|
+
"- **Known limitations** — be honest about what doesn't work yet",
|
|
100
|
+
"",
|
|
101
|
+
"### Artifact saved",
|
|
102
|
+
"`docs.md` written to `.waypoint/docs.md`.",
|
|
103
|
+
"",
|
|
104
|
+
"### Suggested next step",
|
|
105
|
+
"Run `waypoint_review` for a final quality check before shipping.",
|
|
106
|
+
].join("\n");
|
|
107
|
+
}
|