agent-bober 0.6.2 → 0.8.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/README.md +220 -30
- package/dist/cli/commands/eval.d.ts +2 -0
- package/dist/cli/commands/eval.d.ts.map +1 -1
- package/dist/cli/commands/eval.js +10 -0
- package/dist/cli/commands/eval.js.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +357 -62
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/plan.d.ts +2 -0
- package/dist/cli/commands/plan.d.ts.map +1 -1
- package/dist/cli/commands/plan.js +10 -0
- package/dist/cli/commands/plan.js.map +1 -1
- package/dist/cli/commands/run.d.ts +2 -0
- package/dist/cli/commands/run.d.ts.map +1 -1
- package/dist/cli/commands/run.js +10 -0
- package/dist/cli/commands/run.js.map +1 -1
- package/dist/cli/commands/sprint.d.ts +2 -0
- package/dist/cli/commands/sprint.d.ts.map +1 -1
- package/dist/cli/commands/sprint.js +10 -0
- package/dist/cli/commands/sprint.js.map +1 -1
- package/dist/cli/index.js +22 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/config/schema.d.ts +160 -43
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +11 -7
- package/dist/config/schema.js.map +1 -1
- package/dist/contracts/sprint-contract.d.ts +8 -8
- package/dist/discovery/config-generator.d.ts +28 -0
- package/dist/discovery/config-generator.d.ts.map +1 -0
- package/dist/discovery/config-generator.js +225 -0
- package/dist/discovery/config-generator.js.map +1 -0
- package/dist/discovery/index.d.ts +20 -0
- package/dist/discovery/index.d.ts.map +1 -0
- package/dist/discovery/index.js +19 -0
- package/dist/discovery/index.js.map +1 -0
- package/dist/discovery/scanner.d.ts +17 -0
- package/dist/discovery/scanner.d.ts.map +1 -0
- package/dist/discovery/scanner.js +120 -0
- package/dist/discovery/scanner.js.map +1 -0
- package/dist/discovery/scanners/ci-checks.d.ts +10 -0
- package/dist/discovery/scanners/ci-checks.d.ts.map +1 -0
- package/dist/discovery/scanners/ci-checks.js +169 -0
- package/dist/discovery/scanners/ci-checks.js.map +1 -0
- package/dist/discovery/scanners/code-conventions.d.ts +12 -0
- package/dist/discovery/scanners/code-conventions.d.ts.map +1 -0
- package/dist/discovery/scanners/code-conventions.js +216 -0
- package/dist/discovery/scanners/code-conventions.js.map +1 -0
- package/dist/discovery/scanners/documentation.d.ts +17 -0
- package/dist/discovery/scanners/documentation.d.ts.map +1 -0
- package/dist/discovery/scanners/documentation.js +92 -0
- package/dist/discovery/scanners/documentation.js.map +1 -0
- package/dist/discovery/scanners/git-conventions.d.ts +11 -0
- package/dist/discovery/scanners/git-conventions.d.ts.map +1 -0
- package/dist/discovery/scanners/git-conventions.js +128 -0
- package/dist/discovery/scanners/git-conventions.js.map +1 -0
- package/dist/discovery/scanners/package-scripts.d.ts +9 -0
- package/dist/discovery/scanners/package-scripts.d.ts.map +1 -0
- package/dist/discovery/scanners/package-scripts.js +112 -0
- package/dist/discovery/scanners/package-scripts.js.map +1 -0
- package/dist/discovery/scanners/test-conventions.d.ts +9 -0
- package/dist/discovery/scanners/test-conventions.d.ts.map +1 -0
- package/dist/discovery/scanners/test-conventions.js +231 -0
- package/dist/discovery/scanners/test-conventions.js.map +1 -0
- package/dist/discovery/synthesizer.d.ts +30 -0
- package/dist/discovery/synthesizer.d.ts.map +1 -0
- package/dist/discovery/synthesizer.js +348 -0
- package/dist/discovery/synthesizer.js.map +1 -0
- package/dist/discovery/types.d.ts +160 -0
- package/dist/discovery/types.d.ts.map +1 -0
- package/dist/discovery/types.js +9 -0
- package/dist/discovery/types.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/index.d.ts +4 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +4 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/run-manager.d.ts +47 -0
- package/dist/mcp/run-manager.d.ts.map +1 -0
- package/dist/mcp/run-manager.js +79 -0
- package/dist/mcp/run-manager.js.map +1 -0
- package/dist/mcp/server.d.ts +15 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +107 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools/config.d.ts +2 -0
- package/dist/mcp/tools/config.d.ts.map +1 -0
- package/dist/mcp/tools/config.js +153 -0
- package/dist/mcp/tools/config.js.map +1 -0
- package/dist/mcp/tools/contracts.d.ts +2 -0
- package/dist/mcp/tools/contracts.d.ts.map +1 -0
- package/dist/mcp/tools/contracts.js +61 -0
- package/dist/mcp/tools/contracts.js.map +1 -0
- package/dist/mcp/tools/eval.d.ts +2 -0
- package/dist/mcp/tools/eval.d.ts.map +1 -0
- package/dist/mcp/tools/eval.js +157 -0
- package/dist/mcp/tools/eval.js.map +1 -0
- package/dist/mcp/tools/index.d.ts +20 -0
- package/dist/mcp/tools/index.d.ts.map +1 -0
- package/dist/mcp/tools/index.js +47 -0
- package/dist/mcp/tools/index.js.map +1 -0
- package/dist/mcp/tools/init.d.ts +2 -0
- package/dist/mcp/tools/init.d.ts.map +1 -0
- package/dist/mcp/tools/init.js +222 -0
- package/dist/mcp/tools/init.js.map +1 -0
- package/dist/mcp/tools/plan.d.ts +2 -0
- package/dist/mcp/tools/plan.d.ts.map +1 -0
- package/dist/mcp/tools/plan.js +97 -0
- package/dist/mcp/tools/plan.js.map +1 -0
- package/dist/mcp/tools/principles.d.ts +2 -0
- package/dist/mcp/tools/principles.d.ts.map +1 -0
- package/dist/mcp/tools/principles.js +66 -0
- package/dist/mcp/tools/principles.js.map +1 -0
- package/dist/mcp/tools/registry.d.ts +45 -0
- package/dist/mcp/tools/registry.d.ts.map +1 -0
- package/dist/mcp/tools/registry.js +23 -0
- package/dist/mcp/tools/registry.js.map +1 -0
- package/dist/mcp/tools/run.d.ts +2 -0
- package/dist/mcp/tools/run.d.ts.map +1 -0
- package/dist/mcp/tools/run.js +66 -0
- package/dist/mcp/tools/run.js.map +1 -0
- package/dist/mcp/tools/spec.d.ts +2 -0
- package/dist/mcp/tools/spec.d.ts.map +1 -0
- package/dist/mcp/tools/spec.js +32 -0
- package/dist/mcp/tools/spec.js.map +1 -0
- package/dist/mcp/tools/sprint.d.ts +2 -0
- package/dist/mcp/tools/sprint.d.ts.map +1 -0
- package/dist/mcp/tools/sprint.js +243 -0
- package/dist/mcp/tools/sprint.js.map +1 -0
- package/dist/mcp/tools/status.d.ts +2 -0
- package/dist/mcp/tools/status.d.ts.map +1 -0
- package/dist/mcp/tools/status.js +76 -0
- package/dist/mcp/tools/status.js.map +1 -0
- package/dist/orchestrator/agentic-loop.d.ts +7 -6
- package/dist/orchestrator/agentic-loop.d.ts.map +1 -1
- package/dist/orchestrator/agentic-loop.js +33 -40
- package/dist/orchestrator/agentic-loop.js.map +1 -1
- package/dist/orchestrator/context-handoff.d.ts +20 -20
- package/dist/orchestrator/evaluator-agent.d.ts.map +1 -1
- package/dist/orchestrator/evaluator-agent.js +2 -2
- package/dist/orchestrator/evaluator-agent.js.map +1 -1
- package/dist/orchestrator/generator-agent.d.ts.map +1 -1
- package/dist/orchestrator/generator-agent.js +2 -2
- package/dist/orchestrator/generator-agent.js.map +1 -1
- package/dist/orchestrator/model-resolver.d.ts +35 -4
- package/dist/orchestrator/model-resolver.d.ts.map +1 -1
- package/dist/orchestrator/model-resolver.js +68 -15
- package/dist/orchestrator/model-resolver.js.map +1 -1
- package/dist/orchestrator/planner-agent.d.ts.map +1 -1
- package/dist/orchestrator/planner-agent.js +2 -2
- package/dist/orchestrator/planner-agent.js.map +1 -1
- package/dist/orchestrator/tools/index.d.ts +3 -4
- package/dist/orchestrator/tools/index.d.ts.map +1 -1
- package/dist/orchestrator/tools/index.js.map +1 -1
- package/dist/orchestrator/tools/schemas.d.ts +11 -12
- package/dist/orchestrator/tools/schemas.d.ts.map +1 -1
- package/dist/orchestrator/tools/schemas.js +3 -2
- package/dist/orchestrator/tools/schemas.js.map +1 -1
- package/dist/providers/anthropic.d.ts +15 -0
- package/dist/providers/anthropic.d.ts.map +1 -0
- package/dist/providers/anthropic.js +133 -0
- package/dist/providers/anthropic.js.map +1 -0
- package/dist/providers/factory.d.ts +37 -0
- package/dist/providers/factory.d.ts.map +1 -0
- package/dist/providers/factory.js +119 -0
- package/dist/providers/factory.js.map +1 -0
- package/dist/providers/google.d.ts +39 -0
- package/dist/providers/google.d.ts.map +1 -0
- package/dist/providers/google.js +195 -0
- package/dist/providers/google.js.map +1 -0
- package/dist/providers/index.d.ts +7 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +6 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/openai-compat.d.ts +39 -0
- package/dist/providers/openai-compat.d.ts.map +1 -0
- package/dist/providers/openai-compat.js +42 -0
- package/dist/providers/openai-compat.js.map +1 -0
- package/dist/providers/openai.d.ts +41 -0
- package/dist/providers/openai.d.ts.map +1 -0
- package/dist/providers/openai.js +205 -0
- package/dist/providers/openai.js.map +1 -0
- package/dist/providers/types.d.ts +144 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/providers/types.js +8 -0
- package/dist/providers/types.js.map +1 -0
- package/package.json +22 -4
- package/skills/bober.principles/SKILL.md +36 -3
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
// ── bober_init tool ──────────────────────────────────────────────────
|
|
2
|
+
//
|
|
3
|
+
// Creates bober.config.json and .bober/ directories in the current
|
|
4
|
+
// working directory. Accepts { preset?: string, provider?: string }.
|
|
5
|
+
// Returns a confirmation message.
|
|
6
|
+
import { writeFile } from "node:fs/promises";
|
|
7
|
+
import { join, basename } from "node:path";
|
|
8
|
+
import { cwd } from "node:process";
|
|
9
|
+
import { configExists } from "../../config/loader.js";
|
|
10
|
+
import { createDefaultConfig } from "../../config/schema.js";
|
|
11
|
+
import { getPresetNames } from "../../config/defaults.js";
|
|
12
|
+
import { ensureBoberDir } from "../../state/index.js";
|
|
13
|
+
import { registerTool } from "./registry.js";
|
|
14
|
+
import { scanProject } from "../../discovery/scanner.js";
|
|
15
|
+
import { generateEvalConfig } from "../../discovery/config-generator.js";
|
|
16
|
+
import { synthesizePrinciples } from "../../discovery/synthesizer.js";
|
|
17
|
+
// ── Registration ─────────────────────────────────────────────────────
|
|
18
|
+
export function registerInitTool() {
|
|
19
|
+
registerTool({
|
|
20
|
+
name: "bober_init",
|
|
21
|
+
description: "Initialise a Bober project in the current working directory. " +
|
|
22
|
+
"Creates bober.config.json and the .bober/ state directory. " +
|
|
23
|
+
"Accepts an optional preset (e.g. nextjs, react-vite, api-node) and " +
|
|
24
|
+
"an optional provider (anthropic, openai, google, openai-compat). " +
|
|
25
|
+
"If a config already exists this will overwrite it.",
|
|
26
|
+
inputSchema: {
|
|
27
|
+
type: "object",
|
|
28
|
+
properties: {
|
|
29
|
+
preset: {
|
|
30
|
+
type: "string",
|
|
31
|
+
description: "Optional project preset. One of: nextjs, react-vite, api-node, " +
|
|
32
|
+
"python-api, solidity, anchor. Leave blank for a generic config.",
|
|
33
|
+
},
|
|
34
|
+
provider: {
|
|
35
|
+
type: "string",
|
|
36
|
+
description: "AI provider to use: anthropic (default), openai, google, openai-compat.",
|
|
37
|
+
default: "anthropic",
|
|
38
|
+
},
|
|
39
|
+
mode: {
|
|
40
|
+
type: "string",
|
|
41
|
+
description: "Project mode: greenfield (default) or brownfield.",
|
|
42
|
+
default: "greenfield",
|
|
43
|
+
},
|
|
44
|
+
projectName: {
|
|
45
|
+
type: "string",
|
|
46
|
+
description: "Project name. Defaults to the name of the current directory.",
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
additionalProperties: false,
|
|
50
|
+
},
|
|
51
|
+
handler: async (args) => {
|
|
52
|
+
const projectRoot = cwd();
|
|
53
|
+
const projectName = typeof args.projectName === "string" && args.projectName.trim()
|
|
54
|
+
? args.projectName.trim()
|
|
55
|
+
: basename(projectRoot);
|
|
56
|
+
const rawPreset = typeof args.preset === "string" && args.preset.trim()
|
|
57
|
+
? args.preset.trim()
|
|
58
|
+
: undefined;
|
|
59
|
+
const provider = typeof args.provider === "string" && args.provider.trim()
|
|
60
|
+
? args.provider.trim()
|
|
61
|
+
: "anthropic";
|
|
62
|
+
const rawMode = typeof args.mode === "string" && args.mode.trim()
|
|
63
|
+
? args.mode.trim()
|
|
64
|
+
: "greenfield";
|
|
65
|
+
const mode = rawMode === "brownfield" ? "brownfield" : "greenfield";
|
|
66
|
+
// Validate preset if provided
|
|
67
|
+
if (rawPreset) {
|
|
68
|
+
const knownPresets = getPresetNames();
|
|
69
|
+
if (!knownPresets.includes(rawPreset)) {
|
|
70
|
+
return JSON.stringify({
|
|
71
|
+
error: `Unknown preset "${rawPreset}".`,
|
|
72
|
+
availablePresets: knownPresets,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// Warn if already initialised (but proceed — tool contract says overwrite)
|
|
77
|
+
const alreadyExists = await configExists(projectRoot);
|
|
78
|
+
if (alreadyExists) {
|
|
79
|
+
process.stderr.write(`[bober_init] Overwriting existing bober.config.json in ${projectRoot}\n`);
|
|
80
|
+
}
|
|
81
|
+
// ── Brownfield: run auto-discovery pipeline ────────────────────
|
|
82
|
+
if (mode === "brownfield") {
|
|
83
|
+
process.stderr.write(`[bober_init] Running brownfield auto-discovery for ${projectRoot}\n`);
|
|
84
|
+
const report = await scanProject(projectRoot);
|
|
85
|
+
const evalConfig = generateEvalConfig(report);
|
|
86
|
+
const config = createDefaultConfig(projectName, mode, undefined, {
|
|
87
|
+
planner: {
|
|
88
|
+
maxClarifications: 5,
|
|
89
|
+
model: "opus",
|
|
90
|
+
provider,
|
|
91
|
+
},
|
|
92
|
+
generator: {
|
|
93
|
+
model: "sonnet",
|
|
94
|
+
maxTurnsPerSprint: 50,
|
|
95
|
+
autoCommit: true,
|
|
96
|
+
branchPattern: "bober/{feature-name}",
|
|
97
|
+
provider,
|
|
98
|
+
},
|
|
99
|
+
evaluator: {
|
|
100
|
+
model: "sonnet",
|
|
101
|
+
strategies: evalConfig.strategies,
|
|
102
|
+
maxIterations: 3,
|
|
103
|
+
provider,
|
|
104
|
+
},
|
|
105
|
+
commands: evalConfig.commands,
|
|
106
|
+
});
|
|
107
|
+
// Write bober.config.json
|
|
108
|
+
const configPath = join(projectRoot, "bober.config.json");
|
|
109
|
+
await writeFile(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
110
|
+
// Create .bober/ directory structure
|
|
111
|
+
await ensureBoberDir(projectRoot);
|
|
112
|
+
// Synthesize principles
|
|
113
|
+
let principles = null;
|
|
114
|
+
let principlesError = null;
|
|
115
|
+
try {
|
|
116
|
+
principles = await synthesizePrinciples(report, projectRoot, config);
|
|
117
|
+
const principlesPath = join(projectRoot, ".bober", "principles.md");
|
|
118
|
+
await writeFile(principlesPath, principles, "utf-8");
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
principlesError = err instanceof Error ? err.message : String(err);
|
|
122
|
+
process.stderr.write(`[bober_init] Could not synthesize principles: ${principlesError}\n`);
|
|
123
|
+
}
|
|
124
|
+
// Build discovery summary for response
|
|
125
|
+
const stack = report.detectedStack;
|
|
126
|
+
const detectedTech = [];
|
|
127
|
+
if (stack) {
|
|
128
|
+
if (stack.hasTypescript)
|
|
129
|
+
detectedTech.push("TypeScript");
|
|
130
|
+
if (stack.hasReact)
|
|
131
|
+
detectedTech.push("React");
|
|
132
|
+
if (stack.hasNext)
|
|
133
|
+
detectedTech.push("Next.js");
|
|
134
|
+
if (stack.hasVite)
|
|
135
|
+
detectedTech.push("Vite");
|
|
136
|
+
if (stack.hasEslint)
|
|
137
|
+
detectedTech.push("ESLint");
|
|
138
|
+
if (stack.hasVitest)
|
|
139
|
+
detectedTech.push("Vitest");
|
|
140
|
+
if (stack.hasJest)
|
|
141
|
+
detectedTech.push("Jest");
|
|
142
|
+
if (stack.hasPlaywright)
|
|
143
|
+
detectedTech.push("Playwright");
|
|
144
|
+
if (stack.hasNestjs)
|
|
145
|
+
detectedTech.push("NestJS");
|
|
146
|
+
if (stack.hasFastify)
|
|
147
|
+
detectedTech.push("Fastify");
|
|
148
|
+
if (stack.hasExpress)
|
|
149
|
+
detectedTech.push("Express");
|
|
150
|
+
if (stack.hasPython)
|
|
151
|
+
detectedTech.push("Python");
|
|
152
|
+
if (stack.hasRust)
|
|
153
|
+
detectedTech.push("Rust");
|
|
154
|
+
}
|
|
155
|
+
process.stderr.write(`[bober_init] Initialised brownfield project "${projectName}" in ${projectRoot}\n`);
|
|
156
|
+
return JSON.stringify({
|
|
157
|
+
status: "initialised",
|
|
158
|
+
projectName,
|
|
159
|
+
mode,
|
|
160
|
+
provider,
|
|
161
|
+
configPath,
|
|
162
|
+
boberDir: join(projectRoot, ".bober"),
|
|
163
|
+
discovery: {
|
|
164
|
+
detectedTech,
|
|
165
|
+
packageManager: report.packageManager,
|
|
166
|
+
strategies: evalConfig.strategies.map((s) => s.type),
|
|
167
|
+
commands: evalConfig.commands,
|
|
168
|
+
},
|
|
169
|
+
principles: principles ?? null,
|
|
170
|
+
principlesError,
|
|
171
|
+
message: alreadyExists
|
|
172
|
+
? "Existing configuration was overwritten using auto-discovery."
|
|
173
|
+
: "Brownfield project initialised with auto-discovered configuration.",
|
|
174
|
+
nextStep: principles
|
|
175
|
+
? "Run bober_plan with a task description to generate a sprint plan."
|
|
176
|
+
: "Run /bober-principles to generate project principles, then bober_plan.",
|
|
177
|
+
}, null, 2);
|
|
178
|
+
}
|
|
179
|
+
// ── Greenfield: use preset/default config ──────────────────────
|
|
180
|
+
const config = createDefaultConfig(projectName, mode, rawPreset, {
|
|
181
|
+
planner: {
|
|
182
|
+
maxClarifications: 5,
|
|
183
|
+
model: "opus",
|
|
184
|
+
provider,
|
|
185
|
+
},
|
|
186
|
+
generator: {
|
|
187
|
+
model: "sonnet",
|
|
188
|
+
maxTurnsPerSprint: 50,
|
|
189
|
+
autoCommit: true,
|
|
190
|
+
branchPattern: "bober/{feature-name}",
|
|
191
|
+
provider,
|
|
192
|
+
},
|
|
193
|
+
evaluator: {
|
|
194
|
+
model: "sonnet",
|
|
195
|
+
strategies: [],
|
|
196
|
+
maxIterations: 3,
|
|
197
|
+
provider,
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
// Write bober.config.json
|
|
201
|
+
const configPath = join(projectRoot, "bober.config.json");
|
|
202
|
+
await writeFile(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
203
|
+
// Create .bober/ directory structure
|
|
204
|
+
await ensureBoberDir(projectRoot);
|
|
205
|
+
process.stderr.write(`[bober_init] Initialised project "${projectName}" in ${projectRoot}\n`);
|
|
206
|
+
return JSON.stringify({
|
|
207
|
+
status: "initialised",
|
|
208
|
+
projectName,
|
|
209
|
+
mode,
|
|
210
|
+
preset: rawPreset ?? null,
|
|
211
|
+
provider,
|
|
212
|
+
configPath,
|
|
213
|
+
boberDir: join(projectRoot, ".bober"),
|
|
214
|
+
message: alreadyExists
|
|
215
|
+
? "Existing configuration was overwritten."
|
|
216
|
+
: "Project successfully initialised. Run bober_plan to create your first plan.",
|
|
217
|
+
nextStep: "Run bober_plan with a task description to generate a sprint plan.",
|
|
218
|
+
}, null, 2);
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/mcp/tools/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/plan.ts"],"names":[],"mappings":"AAkBA,wBAAgB,gBAAgB,IAAI,IAAI,CAiGvC"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// ── bober_plan tool ─────────────────────────────────────────────────
|
|
2
|
+
//
|
|
3
|
+
// Accepts { task: string }, calls the planner agent, and returns a
|
|
4
|
+
// JSON summary of the produced PlanSpec.
|
|
5
|
+
import { cwd } from "node:process";
|
|
6
|
+
import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
|
|
7
|
+
import { configExists, loadConfig } from "../../config/loader.js";
|
|
8
|
+
import { createContract } from "../../contracts/sprint-contract.js";
|
|
9
|
+
import { runPlanner } from "../../orchestrator/planner-agent.js";
|
|
10
|
+
import { ensureBoberDir, saveContract } from "../../state/index.js";
|
|
11
|
+
import { registerTool } from "./registry.js";
|
|
12
|
+
// ── Registration ─────────────────────────────────────────────────────
|
|
13
|
+
export function registerPlanTool() {
|
|
14
|
+
registerTool({
|
|
15
|
+
name: "bober_plan",
|
|
16
|
+
description: "Run the Bober planner agent. Accepts a task/feature description and " +
|
|
17
|
+
"produces a PlanSpec with a sprint breakdown saved to .bober/specs/. " +
|
|
18
|
+
"Returns a JSON summary with the plan title, description, and sprint list.",
|
|
19
|
+
inputSchema: {
|
|
20
|
+
type: "object",
|
|
21
|
+
properties: {
|
|
22
|
+
task: {
|
|
23
|
+
type: "string",
|
|
24
|
+
description: "Feature or project description to plan.",
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
required: ["task"],
|
|
28
|
+
additionalProperties: false,
|
|
29
|
+
},
|
|
30
|
+
handler: async (args) => {
|
|
31
|
+
const task = String(args.task ?? "").trim();
|
|
32
|
+
if (!task) {
|
|
33
|
+
return JSON.stringify({ error: "task is required and must be a non-empty string." });
|
|
34
|
+
}
|
|
35
|
+
const projectRoot = cwd();
|
|
36
|
+
// Check config exists before attempting to load
|
|
37
|
+
const hasConfig = await configExists(projectRoot);
|
|
38
|
+
if (!hasConfig) {
|
|
39
|
+
throw new McpError(ErrorCode.InvalidRequest, "No bober.config.json found. Run bober_init first.");
|
|
40
|
+
}
|
|
41
|
+
let config;
|
|
42
|
+
try {
|
|
43
|
+
config = await loadConfig(projectRoot);
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
return JSON.stringify({
|
|
47
|
+
error: `Failed to load config: ${err instanceof Error ? err.message : String(err)}`,
|
|
48
|
+
projectRoot,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
await ensureBoberDir(projectRoot);
|
|
52
|
+
try {
|
|
53
|
+
const spec = await runPlanner(task, projectRoot, config);
|
|
54
|
+
// Generate sprint contracts from features (same as pipeline.ts)
|
|
55
|
+
const contracts = [];
|
|
56
|
+
for (const feature of spec.features) {
|
|
57
|
+
const contract = createContract(feature.title, feature.description, feature.acceptanceCriteria.map((ac, idx) => ({
|
|
58
|
+
id: `${feature.id}-criterion-${idx + 1}`,
|
|
59
|
+
description: ac,
|
|
60
|
+
verificationMethod: "agent-evaluation",
|
|
61
|
+
})));
|
|
62
|
+
contracts.push(contract);
|
|
63
|
+
await saveContract(projectRoot, contract);
|
|
64
|
+
}
|
|
65
|
+
const summary = {
|
|
66
|
+
id: spec.id,
|
|
67
|
+
title: spec.title,
|
|
68
|
+
description: spec.description,
|
|
69
|
+
projectType: spec.projectType,
|
|
70
|
+
techStack: spec.techStack,
|
|
71
|
+
sprintCount: spec.features.length,
|
|
72
|
+
sprints: spec.features.map((f, idx) => ({
|
|
73
|
+
id: f.id,
|
|
74
|
+
contractId: contracts[idx]?.id,
|
|
75
|
+
feature: f.title,
|
|
76
|
+
description: f.description,
|
|
77
|
+
priority: f.priority,
|
|
78
|
+
estimatedSprints: f.estimatedSprints,
|
|
79
|
+
criteriaCount: f.acceptanceCriteria.length,
|
|
80
|
+
status: "proposed",
|
|
81
|
+
})),
|
|
82
|
+
contractIds: contracts.map((c) => c.id),
|
|
83
|
+
nonFunctional: spec.nonFunctional,
|
|
84
|
+
constraints: spec.constraints,
|
|
85
|
+
savedTo: `.bober/specs/${spec.id}.json`,
|
|
86
|
+
};
|
|
87
|
+
return JSON.stringify(summary, null, 2);
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
return JSON.stringify({
|
|
91
|
+
error: `Planner failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=plan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../../../src/mcp/tools/plan.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"principles.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/principles.ts"],"names":[],"mappings":"AAsBA,wBAAgB,sBAAsB,IAAI,IAAI,CAwE7C"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// ── bober_principles tool ─────────────────────────────────────────────
|
|
2
|
+
//
|
|
3
|
+
// No args -> read .bober/principles.md and return content.
|
|
4
|
+
// With { content } -> write/update .bober/principles.md.
|
|
5
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { cwd } from "node:process";
|
|
8
|
+
import { ensureBoberDir } from "../../state/index.js";
|
|
9
|
+
import { registerTool } from "./registry.js";
|
|
10
|
+
// ── Constants ─────────────────────────────────────────────────────────
|
|
11
|
+
const PRINCIPLES_FILENAME = "principles.md";
|
|
12
|
+
function principlesPath(projectRoot) {
|
|
13
|
+
return join(projectRoot, ".bober", PRINCIPLES_FILENAME);
|
|
14
|
+
}
|
|
15
|
+
// ── Registration ─────────────────────────────────────────────────────
|
|
16
|
+
export function registerPrinciplesTool() {
|
|
17
|
+
registerTool({
|
|
18
|
+
name: "bober_principles",
|
|
19
|
+
description: "Read or write the project principles file (.bober/principles.md). " +
|
|
20
|
+
"Without arguments reads the current principles. " +
|
|
21
|
+
"With content writes/replaces the principles file. " +
|
|
22
|
+
"Principles are injected into every generator and evaluator agent prompt.",
|
|
23
|
+
inputSchema: {
|
|
24
|
+
type: "object",
|
|
25
|
+
properties: {
|
|
26
|
+
content: {
|
|
27
|
+
type: "string",
|
|
28
|
+
description: "Principles content to write. Omit to read current principles.",
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
additionalProperties: false,
|
|
32
|
+
},
|
|
33
|
+
handler: async (args) => {
|
|
34
|
+
const projectRoot = cwd();
|
|
35
|
+
const filePath = principlesPath(projectRoot);
|
|
36
|
+
const newContent = typeof args.content === "string" ? args.content : undefined;
|
|
37
|
+
// Write mode
|
|
38
|
+
if (newContent !== undefined) {
|
|
39
|
+
await ensureBoberDir(projectRoot);
|
|
40
|
+
await writeFile(filePath, newContent, "utf-8");
|
|
41
|
+
process.stderr.write(`[bober_principles] Wrote ${newContent.length} characters to ${filePath}\n`);
|
|
42
|
+
return JSON.stringify({
|
|
43
|
+
status: "updated",
|
|
44
|
+
path: filePath,
|
|
45
|
+
characters: newContent.length,
|
|
46
|
+
message: "Principles file updated. These will be injected into all future agent prompts.",
|
|
47
|
+
}, null, 2);
|
|
48
|
+
}
|
|
49
|
+
// Read mode
|
|
50
|
+
try {
|
|
51
|
+
const content = await readFile(filePath, "utf-8");
|
|
52
|
+
return JSON.stringify({
|
|
53
|
+
path: filePath,
|
|
54
|
+
content,
|
|
55
|
+
}, null, 2);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return JSON.stringify({
|
|
59
|
+
content: null,
|
|
60
|
+
message: "No principles file. Use bober_principles with content to create one.",
|
|
61
|
+
}, null, 2);
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=principles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"principles.js","sourceRoot":"","sources":["../../../src/mcp/tools/principles.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,EAAE;AACF,2DAA2D;AAC3D,yDAAyD;AAEzD,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAEnC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C,yEAAyE;AAEzE,MAAM,mBAAmB,GAAG,eAAe,CAAC;AAE5C,SAAS,cAAc,CAAC,WAAmB;IACzC,OAAO,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,mBAAmB,CAAC,CAAC;AAC1D,CAAC;AAED,wEAAwE;AAExE,MAAM,UAAU,sBAAsB;IACpC,YAAY,CAAC;QACX,IAAI,EAAE,kBAAkB;QACxB,WAAW,EACT,oEAAoE;YACpE,kDAAkD;YAClD,oDAAoD;YACpD,0EAA0E;QAC5E,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,OAAO,EAAE;oBACP,IAAI,EAAE,QAAQ;oBACd,WAAW,EACT,+DAA+D;iBAClE;aACF;YACD,oBAAoB,EAAE,KAAK;SAC5B;QACD,OAAO,EAAE,KAAK,EAAE,IAA6B,EAAmB,EAAE;YAChE,MAAM,WAAW,GAAG,GAAG,EAAE,CAAC;YAC1B,MAAM,QAAQ,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;YAE7C,MAAM,UAAU,GACd,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;YAE9D,aAAa;YACb,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;gBAC7B,MAAM,cAAc,CAAC,WAAW,CAAC,CAAC;gBAClC,MAAM,SAAS,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;gBAE/C,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,4BAA4B,UAAU,CAAC,MAAM,kBAAkB,QAAQ,IAAI,CAC5E,CAAC;gBAEF,OAAO,IAAI,CAAC,SAAS,CACnB;oBACE,MAAM,EAAE,SAAS;oBACjB,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE,UAAU,CAAC,MAAM;oBAC7B,OAAO,EACL,gFAAgF;iBACnF,EACD,IAAI,EACJ,CAAC,CACF,CAAC;YACJ,CAAC;YAED,YAAY;YACZ,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;gBAClD,OAAO,IAAI,CAAC,SAAS,CACnB;oBACE,IAAI,EAAE,QAAQ;oBACd,OAAO;iBACR,EACD,IAAI,EACJ,CAAC,CACF,CAAC;YACJ,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,IAAI,CAAC,SAAS,CACnB;oBACE,OAAO,EAAE,IAAI;oBACb,OAAO,EACL,sEAAsE;iBACzE,EACD,IAAI,EACJ,CAAC,CACF,CAAC;YACJ,CAAC;QACH,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A JSON Schema object for describing a tool's input parameters.
|
|
3
|
+
*/
|
|
4
|
+
export interface JsonSchemaObject {
|
|
5
|
+
type: string;
|
|
6
|
+
properties?: Record<string, JsonSchemaProperty>;
|
|
7
|
+
required?: string[];
|
|
8
|
+
additionalProperties?: boolean;
|
|
9
|
+
description?: string;
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
}
|
|
12
|
+
export interface JsonSchemaProperty {
|
|
13
|
+
type?: string;
|
|
14
|
+
description?: string;
|
|
15
|
+
enum?: unknown[];
|
|
16
|
+
default?: unknown;
|
|
17
|
+
[key: string]: unknown;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Definition of a single MCP tool that agent-bober exposes.
|
|
21
|
+
*/
|
|
22
|
+
export interface BoberToolDefinition {
|
|
23
|
+
/** The tool name as it will appear in tools/list (e.g. "bober_ping"). */
|
|
24
|
+
name: string;
|
|
25
|
+
/** Human-readable description of what the tool does. */
|
|
26
|
+
description: string;
|
|
27
|
+
/** JSON Schema object describing the tool's input parameters. */
|
|
28
|
+
inputSchema: JsonSchemaObject;
|
|
29
|
+
/** Function that executes the tool and returns a string result. */
|
|
30
|
+
handler: (args: Record<string, unknown>) => Promise<string>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Register a tool in the global tool registry.
|
|
34
|
+
* If a tool with the same name is already registered, it is overwritten.
|
|
35
|
+
*/
|
|
36
|
+
export declare function registerTool(tool: BoberToolDefinition): void;
|
|
37
|
+
/**
|
|
38
|
+
* Returns all registered tool definitions.
|
|
39
|
+
*/
|
|
40
|
+
export declare function getAllTools(): BoberToolDefinition[];
|
|
41
|
+
/**
|
|
42
|
+
* Looks up a tool by name. Returns undefined if not found.
|
|
43
|
+
*/
|
|
44
|
+
export declare function getTool(name: string): BoberToolDefinition | undefined;
|
|
45
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/registry.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAChD,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,WAAW,EAAE,MAAM,CAAC;IACpB,iEAAiE;IACjE,WAAW,EAAE,gBAAgB,CAAC;IAC9B,mEAAmE;IACnE,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CAC7D;AAMD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,mBAAmB,GAAG,IAAI,CAE5D;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,mBAAmB,EAAE,CAEnD;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS,CAErE"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// ── Tool Registry ───────────────────────────────────────────────────
|
|
2
|
+
// ── Registry implementation ─────────────────────────────────────────
|
|
3
|
+
const registry = new Map();
|
|
4
|
+
/**
|
|
5
|
+
* Register a tool in the global tool registry.
|
|
6
|
+
* If a tool with the same name is already registered, it is overwritten.
|
|
7
|
+
*/
|
|
8
|
+
export function registerTool(tool) {
|
|
9
|
+
registry.set(tool.name, tool);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Returns all registered tool definitions.
|
|
13
|
+
*/
|
|
14
|
+
export function getAllTools() {
|
|
15
|
+
return Array.from(registry.values());
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Looks up a tool by name. Returns undefined if not found.
|
|
19
|
+
*/
|
|
20
|
+
export function getTool(name) {
|
|
21
|
+
return registry.get(name);
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/mcp/tools/registry.ts"],"names":[],"mappings":"AAAA,uEAAuE;AAoCvE,uEAAuE;AAEvE,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA+B,CAAC;AAExD;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,IAAyB;IACpD,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AAChC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW;IACzB,OAAO,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;AACvC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,OAAO,CAAC,IAAY;IAClC,OAAO,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC5B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/run.ts"],"names":[],"mappings":"AAgBA,wBAAgB,eAAe,IAAI,IAAI,CA0EtC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// ── bober_run tool ───────────────────────────────────────────────────
|
|
2
|
+
//
|
|
3
|
+
// Accepts { task: string }, starts the full pipeline asynchronously,
|
|
4
|
+
// and returns immediately with a runId. The pipeline runs in the
|
|
5
|
+
// background; poll bober_status to track progress.
|
|
6
|
+
import { cwd } from "node:process";
|
|
7
|
+
import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
|
|
8
|
+
import { configExists, loadConfig } from "../../config/loader.js";
|
|
9
|
+
import { registerTool } from "./registry.js";
|
|
10
|
+
import { runManager } from "../run-manager.js";
|
|
11
|
+
// ── Registration ─────────────────────────────────────────────────────
|
|
12
|
+
export function registerRunTool() {
|
|
13
|
+
registerTool({
|
|
14
|
+
name: "bober_run",
|
|
15
|
+
description: "Start the full Bober pipeline (plan + sprint + eval) asynchronously. " +
|
|
16
|
+
"Accepts a task description and returns immediately with a runId. " +
|
|
17
|
+
"Use bober_status to poll progress. Only one pipeline can run at a time.",
|
|
18
|
+
inputSchema: {
|
|
19
|
+
type: "object",
|
|
20
|
+
properties: {
|
|
21
|
+
task: {
|
|
22
|
+
type: "string",
|
|
23
|
+
description: "Feature or project description to build. Passed to the planner.",
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
required: ["task"],
|
|
27
|
+
additionalProperties: false,
|
|
28
|
+
},
|
|
29
|
+
handler: async (args) => {
|
|
30
|
+
const task = String(args.task ?? "").trim();
|
|
31
|
+
if (!task) {
|
|
32
|
+
return JSON.stringify({
|
|
33
|
+
error: "task is required and must be a non-empty string.",
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
const projectRoot = cwd();
|
|
37
|
+
// Require a bober config before starting
|
|
38
|
+
const hasConfig = await configExists(projectRoot);
|
|
39
|
+
if (!hasConfig) {
|
|
40
|
+
throw new McpError(ErrorCode.InvalidRequest, "No bober.config.json found. Run bober_init first.");
|
|
41
|
+
}
|
|
42
|
+
// Reject concurrent runs with a clear error
|
|
43
|
+
if (runManager.isRunning()) {
|
|
44
|
+
const state = runManager.getStatus();
|
|
45
|
+
throw new McpError(ErrorCode.InvalidRequest, `A pipeline is already running (runId: ${state.runId}). Use bober_status to check progress.`);
|
|
46
|
+
}
|
|
47
|
+
let config;
|
|
48
|
+
try {
|
|
49
|
+
config = await loadConfig(projectRoot);
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
return JSON.stringify({
|
|
53
|
+
error: `Failed to load config: ${err instanceof Error ? err.message : String(err)}`,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
const runId = runManager.startRun(task, projectRoot, config);
|
|
57
|
+
process.stderr.write(`[bober_run] Started pipeline run ${runId} for task: ${task.slice(0, 100)}\n`);
|
|
58
|
+
return JSON.stringify({
|
|
59
|
+
runId,
|
|
60
|
+
status: "running",
|
|
61
|
+
message: "Pipeline started. Use bober_status to check progress.",
|
|
62
|
+
}, null, 2);
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../../src/mcp/tools/run.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,EAAE;AACF,qEAAqE;AACrE,iEAAiE;AACjE,mDAAmD;AAEnD,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAEnC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAC;AAEzE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,wEAAwE;AAExE,MAAM,UAAU,eAAe;IAC7B,YAAY,CAAC;QACX,IAAI,EAAE,WAAW;QACjB,WAAW,EACT,uEAAuE;YACvE,mEAAmE;YACnE,yEAAyE;QAC3E,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,IAAI,EAAE;oBACJ,IAAI,EAAE,QAAQ;oBACd,WAAW,EACT,iEAAiE;iBACpE;aACF;YACD,QAAQ,EAAE,CAAC,MAAM,CAAC;YAClB,oBAAoB,EAAE,KAAK;SAC5B;QACD,OAAO,EAAE,KAAK,EAAE,IAA6B,EAAmB,EAAE;YAChE,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;YAC5C,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,OAAO,IAAI,CAAC,SAAS,CAAC;oBACpB,KAAK,EAAE,kDAAkD;iBAC1D,CAAC,CAAC;YACL,CAAC;YAED,MAAM,WAAW,GAAG,GAAG,EAAE,CAAC;YAE1B,yCAAyC;YACzC,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,WAAW,CAAC,CAAC;YAClD,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,MAAM,IAAI,QAAQ,CAChB,SAAS,CAAC,cAAc,EACxB,mDAAmD,CACpD,CAAC;YACJ,CAAC;YAED,4CAA4C;YAC5C,IAAI,UAAU,CAAC,SAAS,EAAE,EAAE,CAAC;gBAC3B,MAAM,KAAK,GAAG,UAAU,CAAC,SAAS,EAAE,CAAC;gBACrC,MAAM,IAAI,QAAQ,CAChB,SAAS,CAAC,cAAc,EACxB,yCAAyC,KAAM,CAAC,KAAK,wCAAwC,CAC9F,CAAC;YACJ,CAAC;YAED,IAAI,MAAM,CAAC;YACX,IAAI,CAAC;gBACH,MAAM,GAAG,MAAM,UAAU,CAAC,WAAW,CAAC,CAAC;YACzC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,IAAI,CAAC,SAAS,CAAC;oBACpB,KAAK,EAAE,0BAA0B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;iBACpF,CAAC,CAAC;YACL,CAAC;YAED,MAAM,KAAK,GAAG,UAAU,CAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;YAE7D,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,oCAAoC,KAAK,cAAc,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,CAC9E,CAAC;YAEF,OAAO,IAAI,CAAC,SAAS,CACnB;gBACE,KAAK;gBACL,MAAM,EAAE,SAAS;gBACjB,OAAO,EACL,uDAAuD;aAC1D,EACD,IAAI,EACJ,CAAC,CACF,CAAC;QACJ,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/spec.ts"],"names":[],"mappings":"AAYA,wBAAgB,gBAAgB,IAAI,IAAI,CA6BvC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// ── bober_spec tool ───────────────────────────────────────────────────
|
|
2
|
+
//
|
|
3
|
+
// Returns the latest PlanSpec JSON.
|
|
4
|
+
// If no plans exist, returns a descriptive error object.
|
|
5
|
+
import { cwd } from "node:process";
|
|
6
|
+
import { loadLatestSpec } from "../../state/index.js";
|
|
7
|
+
import { registerTool } from "./registry.js";
|
|
8
|
+
// ── Registration ─────────────────────────────────────────────────────
|
|
9
|
+
export function registerSpecTool() {
|
|
10
|
+
registerTool({
|
|
11
|
+
name: "bober_spec",
|
|
12
|
+
description: "Return the latest PlanSpec JSON. " +
|
|
13
|
+
"The spec contains the project overview, feature breakdown, and sprint contracts. " +
|
|
14
|
+
"If no plan exists yet, returns an error message.",
|
|
15
|
+
inputSchema: {
|
|
16
|
+
type: "object",
|
|
17
|
+
properties: {},
|
|
18
|
+
additionalProperties: false,
|
|
19
|
+
},
|
|
20
|
+
handler: async (_args) => {
|
|
21
|
+
const projectRoot = cwd();
|
|
22
|
+
const spec = await loadLatestSpec(projectRoot);
|
|
23
|
+
if (spec === null) {
|
|
24
|
+
return JSON.stringify({
|
|
25
|
+
error: "No plans found. Run bober_plan first.",
|
|
26
|
+
}, null, 2);
|
|
27
|
+
}
|
|
28
|
+
return JSON.stringify(spec, null, 2);
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec.js","sourceRoot":"","sources":["../../../src/mcp/tools/spec.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,EAAE;AACF,oCAAoC;AACpC,yDAAyD;AAEzD,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAEnC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C,wEAAwE;AAExE,MAAM,UAAU,gBAAgB;IAC9B,YAAY,CAAC;QACX,IAAI,EAAE,YAAY;QAClB,WAAW,EACT,mCAAmC;YACnC,mFAAmF;YACnF,kDAAkD;QACpD,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE,EAAE;YACd,oBAAoB,EAAE,KAAK;SAC5B;QACD,OAAO,EAAE,KAAK,EAAE,KAA8B,EAAmB,EAAE;YACjE,MAAM,WAAW,GAAG,GAAG,EAAE,CAAC;YAE1B,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,WAAW,CAAC,CAAC;YAC/C,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;gBAClB,OAAO,IAAI,CAAC,SAAS,CACnB;oBACE,KAAK,EAAE,uCAAuC;iBAC/C,EACD,IAAI,EACJ,CAAC,CACF,CAAC;YACJ,CAAC;YAED,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACvC,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sprint.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/sprint.ts"],"names":[],"mappings":"AAgEA,wBAAgB,kBAAkB,IAAI,IAAI,CAwPzC"}
|