planpong 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/README.md +110 -0
- package/dist/bin/planpong-mcp.d.ts +2 -0
- package/dist/bin/planpong-mcp.js +7 -0
- package/dist/bin/planpong-mcp.js.map +1 -0
- package/dist/bin/planpong.d.ts +2 -0
- package/dist/bin/planpong.js +13 -0
- package/dist/bin/planpong.js.map +1 -0
- package/dist/src/cli/commands/plan.d.ts +2 -0
- package/dist/src/cli/commands/plan.js +128 -0
- package/dist/src/cli/commands/plan.js.map +1 -0
- package/dist/src/cli/commands/review.d.ts +2 -0
- package/dist/src/cli/commands/review.js +156 -0
- package/dist/src/cli/commands/review.js.map +1 -0
- package/dist/src/cli/ui.d.ts +11 -0
- package/dist/src/cli/ui.js +65 -0
- package/dist/src/cli/ui.js.map +1 -0
- package/dist/src/config/defaults.d.ts +2 -0
- package/dist/src/config/defaults.js +12 -0
- package/dist/src/config/defaults.js.map +1 -0
- package/dist/src/config/loader.d.ts +17 -0
- package/dist/src/config/loader.js +74 -0
- package/dist/src/config/loader.js.map +1 -0
- package/dist/src/core/convergence.d.ts +10 -0
- package/dist/src/core/convergence.js +56 -0
- package/dist/src/core/convergence.js.map +1 -0
- package/dist/src/core/loop.d.ts +53 -0
- package/dist/src/core/loop.js +256 -0
- package/dist/src/core/loop.js.map +1 -0
- package/dist/src/core/operations.d.ts +68 -0
- package/dist/src/core/operations.js +323 -0
- package/dist/src/core/operations.js.map +1 -0
- package/dist/src/core/session.d.ts +14 -0
- package/dist/src/core/session.js +77 -0
- package/dist/src/core/session.js.map +1 -0
- package/dist/src/mcp/server.d.ts +2 -0
- package/dist/src/mcp/server.js +109 -0
- package/dist/src/mcp/server.js.map +1 -0
- package/dist/src/mcp/tools/get-feedback.d.ts +2 -0
- package/dist/src/mcp/tools/get-feedback.js +109 -0
- package/dist/src/mcp/tools/get-feedback.js.map +1 -0
- package/dist/src/mcp/tools/list-sessions.d.ts +2 -0
- package/dist/src/mcp/tools/list-sessions.js +61 -0
- package/dist/src/mcp/tools/list-sessions.js.map +1 -0
- package/dist/src/mcp/tools/revise.d.ts +2 -0
- package/dist/src/mcp/tools/revise.js +84 -0
- package/dist/src/mcp/tools/revise.js.map +1 -0
- package/dist/src/mcp/tools/start-review.d.ts +2 -0
- package/dist/src/mcp/tools/start-review.js +105 -0
- package/dist/src/mcp/tools/start-review.js.map +1 -0
- package/dist/src/mcp/tools/status.d.ts +2 -0
- package/dist/src/mcp/tools/status.js +83 -0
- package/dist/src/mcp/tools/status.js.map +1 -0
- package/dist/src/prompts/planner.d.ts +3 -0
- package/dist/src/prompts/planner.js +96 -0
- package/dist/src/prompts/planner.js.map +1 -0
- package/dist/src/prompts/reviewer.d.ts +11 -0
- package/dist/src/prompts/reviewer.js +70 -0
- package/dist/src/prompts/reviewer.js.map +1 -0
- package/dist/src/providers/claude.d.ts +8 -0
- package/dist/src/providers/claude.js +77 -0
- package/dist/src/providers/claude.js.map +1 -0
- package/dist/src/providers/codex.d.ts +8 -0
- package/dist/src/providers/codex.js +83 -0
- package/dist/src/providers/codex.js.map +1 -0
- package/dist/src/providers/registry.d.ts +4 -0
- package/dist/src/providers/registry.js +17 -0
- package/dist/src/providers/registry.js.map +1 -0
- package/dist/src/providers/types.d.ts +18 -0
- package/dist/src/providers/types.js +2 -0
- package/dist/src/providers/types.js.map +1 -0
- package/dist/src/schemas/config.d.ts +75 -0
- package/dist/src/schemas/config.js +14 -0
- package/dist/src/schemas/config.js.map +1 -0
- package/dist/src/schemas/feedback.d.ts +95 -0
- package/dist/src/schemas/feedback.js +24 -0
- package/dist/src/schemas/feedback.js.map +1 -0
- package/dist/src/schemas/revision.d.ts +116 -0
- package/dist/src/schemas/revision.js +17 -0
- package/dist/src/schemas/revision.js.map +1 -0
- package/dist/src/schemas/session.d.ts +79 -0
- package/dist/src/schemas/session.js +16 -0
- package/dist/src/schemas/session.js.map +1 -0
- package/package.json +52 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
import { loadConfig } from "../../config/loader.js";
|
|
5
|
+
import { getProvider } from "../../providers/registry.js";
|
|
6
|
+
import { readSessionState, writeSessionState, readInitialPlan, } from "../../core/session.js";
|
|
7
|
+
import { runReviewRound, writeStatusLineToPlan, } from "../../core/operations.js";
|
|
8
|
+
const inputSchema = {
|
|
9
|
+
session_id: z.string().describe("Session ID from planpong_start_review"),
|
|
10
|
+
cwd: z
|
|
11
|
+
.string()
|
|
12
|
+
.optional()
|
|
13
|
+
.describe("Working directory (defaults to process.cwd())"),
|
|
14
|
+
};
|
|
15
|
+
export function registerGetFeedback(server) {
|
|
16
|
+
server.tool("planpong_get_feedback", "Send the current plan to the reviewer model for critique. Returns structured feedback with issues, severity counts, and convergence status.", inputSchema, async (input) => {
|
|
17
|
+
const cwd = input.cwd ?? process.cwd();
|
|
18
|
+
const session = readSessionState(cwd, input.session_id);
|
|
19
|
+
if (!session) {
|
|
20
|
+
return {
|
|
21
|
+
content: [
|
|
22
|
+
{
|
|
23
|
+
type: "text",
|
|
24
|
+
text: JSON.stringify({
|
|
25
|
+
error: `Session not found: ${input.session_id}`,
|
|
26
|
+
}),
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
isError: true,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
if (session.status !== "in_review") {
|
|
33
|
+
return {
|
|
34
|
+
content: [
|
|
35
|
+
{
|
|
36
|
+
type: "text",
|
|
37
|
+
text: JSON.stringify({
|
|
38
|
+
error: `Session status is '${session.status}', expected 'in_review'`,
|
|
39
|
+
}),
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
isError: true,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
// Advance round
|
|
46
|
+
session.currentRound++;
|
|
47
|
+
writeSessionState(cwd, session);
|
|
48
|
+
const config = loadConfig({ cwd });
|
|
49
|
+
// Use session-stored provider config
|
|
50
|
+
const reviewerProvider = getProvider(session.reviewer.provider);
|
|
51
|
+
if (!reviewerProvider) {
|
|
52
|
+
return {
|
|
53
|
+
content: [
|
|
54
|
+
{
|
|
55
|
+
type: "text",
|
|
56
|
+
text: JSON.stringify({
|
|
57
|
+
error: `Reviewer provider not found: ${session.reviewer.provider}`,
|
|
58
|
+
}),
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
isError: true,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
// Build config with session overrides
|
|
65
|
+
const sessionConfig = {
|
|
66
|
+
...config,
|
|
67
|
+
reviewer: session.reviewer,
|
|
68
|
+
planner: session.planner,
|
|
69
|
+
};
|
|
70
|
+
const result = await runReviewRound(session, cwd, sessionConfig, reviewerProvider);
|
|
71
|
+
// Update status line with review results
|
|
72
|
+
const suffix = result.converged
|
|
73
|
+
? `Approved after ${result.round} rounds`
|
|
74
|
+
: `Reviewed — ${result.feedback.issues.length} issues`;
|
|
75
|
+
const statusLine = writeStatusLineToPlan(session, cwd, sessionConfig, suffix);
|
|
76
|
+
const response = {
|
|
77
|
+
round: result.round,
|
|
78
|
+
verdict: result.feedback.verdict,
|
|
79
|
+
summary: result.feedback.summary,
|
|
80
|
+
issues: result.feedback.issues,
|
|
81
|
+
severity_counts: result.severity,
|
|
82
|
+
is_converged: result.converged,
|
|
83
|
+
status_line: statusLine,
|
|
84
|
+
};
|
|
85
|
+
if (result.converged) {
|
|
86
|
+
session.status = "approved";
|
|
87
|
+
const planPath = resolve(cwd, session.planPath);
|
|
88
|
+
let planContent = readFileSync(planPath, "utf-8");
|
|
89
|
+
planContent = planContent.replace(/\*\*Status:\*\* .*/, "**Status:** Approved");
|
|
90
|
+
writeFileSync(planPath, planContent);
|
|
91
|
+
writeSessionState(cwd, session);
|
|
92
|
+
// Include initial plan for change summary
|
|
93
|
+
const initialPlan = readInitialPlan(cwd, session.id);
|
|
94
|
+
if (initialPlan) {
|
|
95
|
+
response.initial_plan = initialPlan;
|
|
96
|
+
response.final_plan = readFileSync(planPath, "utf-8");
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
content: [
|
|
101
|
+
{
|
|
102
|
+
type: "text",
|
|
103
|
+
text: JSON.stringify(response),
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
};
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=get-feedback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-feedback.js","sourceRoot":"","sources":["../../../../src/mcp/tools/get-feedback.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
const SESSIONS_DIR = ".planpong/sessions";
|
|
5
|
+
const inputSchema = {
|
|
6
|
+
cwd: z
|
|
7
|
+
.string()
|
|
8
|
+
.optional()
|
|
9
|
+
.describe("Working directory (defaults to process.cwd())"),
|
|
10
|
+
};
|
|
11
|
+
export function registerListSessions(server) {
|
|
12
|
+
server.tool("planpong_list_sessions", "List all planpong review sessions in the current project.", inputSchema, async (input) => {
|
|
13
|
+
const cwd = input.cwd ?? process.cwd();
|
|
14
|
+
const sessionsDir = join(cwd, SESSIONS_DIR);
|
|
15
|
+
if (!existsSync(sessionsDir)) {
|
|
16
|
+
return {
|
|
17
|
+
content: [
|
|
18
|
+
{
|
|
19
|
+
type: "text",
|
|
20
|
+
text: JSON.stringify({ sessions: [] }),
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const entries = readdirSync(sessionsDir, { withFileTypes: true });
|
|
26
|
+
const sessions = [];
|
|
27
|
+
for (const entry of entries) {
|
|
28
|
+
if (!entry.isDirectory())
|
|
29
|
+
continue;
|
|
30
|
+
const sessionFile = join(sessionsDir, entry.name, "session.json");
|
|
31
|
+
if (!existsSync(sessionFile))
|
|
32
|
+
continue;
|
|
33
|
+
try {
|
|
34
|
+
const session = JSON.parse(readFileSync(sessionFile, "utf-8"));
|
|
35
|
+
sessions.push({
|
|
36
|
+
id: session.id,
|
|
37
|
+
plan_path: session.planPath,
|
|
38
|
+
status: session.status,
|
|
39
|
+
current_round: session.currentRound,
|
|
40
|
+
started_at: session.startedAt,
|
|
41
|
+
planner: session.planner.provider,
|
|
42
|
+
reviewer: session.reviewer.provider,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// Skip malformed session files
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Sort by started_at descending
|
|
50
|
+
sessions.sort((a, b) => b.started_at.localeCompare(a.started_at));
|
|
51
|
+
return {
|
|
52
|
+
content: [
|
|
53
|
+
{
|
|
54
|
+
type: "text",
|
|
55
|
+
text: JSON.stringify({ sessions }),
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
};
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=list-sessions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-sessions.js","sourceRoot":"","sources":["../../../../src/mcp/tools/list-sessions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAIjC,MAAM,YAAY,GAAG,oBAAoB,CAAC;AAE1C,MAAM,WAAW,GAAG;IAClB,GAAG,EAAE,CAAC;SACH,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,+CAA+C,CAAC;CAC7D,CAAC;AAEF,MAAM,UAAU,oBAAoB,CAAC,MAAiB;IACpD,MAAM,CAAC,IAAI,CACT,wBAAwB,EACxB,2DAA2D,EAC3D,WAAW,EACX,KAAK,EAAE,KAAK,EAAE,EAAE;QACd,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QACvC,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;QAE5C,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC7B,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;qBACvC;iBACF;aACF,CAAC;QACJ,CAAC;QAED,MAAM,OAAO,GAAG,WAAW,CAAC,WAAW,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAClE,MAAM,QAAQ,GAQT,EAAE,CAAC;QAER,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;gBAAE,SAAS;YACnC,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;YAClE,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;gBAAE,SAAS;YAEvC,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CACxB,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CACxB,CAAC;gBACb,QAAQ,CAAC,IAAI,CAAC;oBACZ,EAAE,EAAE,OAAO,CAAC,EAAE;oBACd,SAAS,EAAE,OAAO,CAAC,QAAQ;oBAC3B,MAAM,EAAE,OAAO,CAAC,MAAM;oBACtB,aAAa,EAAE,OAAO,CAAC,YAAY;oBACnC,UAAU,EAAE,OAAO,CAAC,SAAS;oBAC7B,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,QAAQ;oBACjC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,QAAQ;iBACpC,CAAC,CAAC;YACL,CAAC;YAAC,MAAM,CAAC;gBACP,+BAA+B;YACjC,CAAC;QACH,CAAC;QAED,gCAAgC;QAChC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;QAElE,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;iBACnC;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { loadConfig } from "../../config/loader.js";
|
|
3
|
+
import { getProvider } from "../../providers/registry.js";
|
|
4
|
+
import { readSessionState } from "../../core/session.js";
|
|
5
|
+
import { runRevisionRound, writeStatusLineToPlan, } from "../../core/operations.js";
|
|
6
|
+
const inputSchema = {
|
|
7
|
+
session_id: z.string().describe("Session ID from planpong_start_review"),
|
|
8
|
+
cwd: z
|
|
9
|
+
.string()
|
|
10
|
+
.optional()
|
|
11
|
+
.describe("Working directory (defaults to process.cwd())"),
|
|
12
|
+
};
|
|
13
|
+
export function registerRevise(server) {
|
|
14
|
+
server.tool("planpong_revise", "Send plan + latest feedback to the planner model for revision. Writes the updated plan to disk. Call after planpong_get_feedback returns is_converged: false.", inputSchema, async (input) => {
|
|
15
|
+
const cwd = input.cwd ?? process.cwd();
|
|
16
|
+
const session = readSessionState(cwd, input.session_id);
|
|
17
|
+
if (!session) {
|
|
18
|
+
return {
|
|
19
|
+
content: [
|
|
20
|
+
{
|
|
21
|
+
type: "text",
|
|
22
|
+
text: JSON.stringify({
|
|
23
|
+
error: `Session not found: ${input.session_id}`,
|
|
24
|
+
}),
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
isError: true,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
if (session.status !== "in_review") {
|
|
31
|
+
return {
|
|
32
|
+
content: [
|
|
33
|
+
{
|
|
34
|
+
type: "text",
|
|
35
|
+
text: JSON.stringify({
|
|
36
|
+
error: `Session status is '${session.status}', expected 'in_review'`,
|
|
37
|
+
}),
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
isError: true,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const config = loadConfig({ cwd });
|
|
44
|
+
const plannerProvider = getProvider(session.planner.provider);
|
|
45
|
+
if (!plannerProvider) {
|
|
46
|
+
return {
|
|
47
|
+
content: [
|
|
48
|
+
{
|
|
49
|
+
type: "text",
|
|
50
|
+
text: JSON.stringify({
|
|
51
|
+
error: `Planner provider not found: ${session.planner.provider}`,
|
|
52
|
+
}),
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
isError: true,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const sessionConfig = {
|
|
59
|
+
...config,
|
|
60
|
+
planner: session.planner,
|
|
61
|
+
reviewer: session.reviewer,
|
|
62
|
+
};
|
|
63
|
+
const result = await runRevisionRound(session, cwd, sessionConfig, plannerProvider);
|
|
64
|
+
// Update status line in plan file (planner may have mangled it)
|
|
65
|
+
const statusLine = writeStatusLineToPlan(session, cwd, sessionConfig, "Revision submitted");
|
|
66
|
+
return {
|
|
67
|
+
content: [
|
|
68
|
+
{
|
|
69
|
+
type: "text",
|
|
70
|
+
text: JSON.stringify({
|
|
71
|
+
round: result.round,
|
|
72
|
+
responses: result.revision.responses,
|
|
73
|
+
accepted: result.accepted,
|
|
74
|
+
rejected: result.rejected,
|
|
75
|
+
deferred: result.deferred,
|
|
76
|
+
plan_updated: result.planUpdated,
|
|
77
|
+
status_line: statusLine,
|
|
78
|
+
}),
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
};
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=revise.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"revise.js","sourceRoot":"","sources":["../../../../src/mcp/tools/revise.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EACL,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,0BAA0B,CAAC;AAElC,MAAM,WAAW,GAAG;IAClB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uCAAuC,CAAC;IACxE,GAAG,EAAE,CAAC;SACH,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,+CAA+C,CAAC;CAC7D,CAAC;AAEF,MAAM,UAAU,cAAc,CAAC,MAAiB;IAC9C,MAAM,CAAC,IAAI,CACT,iBAAiB,EACjB,+JAA+J,EAC/J,WAAW,EACX,KAAK,EAAE,KAAK,EAAE,EAAE;QACd,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QACvC,MAAM,OAAO,GAAG,gBAAgB,CAAC,GAAG,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;QAExD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;4BACnB,KAAK,EAAE,sBAAsB,KAAK,CAAC,UAAU,EAAE;yBAChD,CAAC;qBACH;iBACF;gBACD,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QAED,IAAI,OAAO,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YACnC,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;4BACnB,KAAK,EAAE,sBAAsB,OAAO,CAAC,MAAM,yBAAyB;yBACrE,CAAC;qBACH;iBACF;gBACD,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,UAAU,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QACnC,MAAM,eAAe,GAAG,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC9D,IAAI,CAAC,eAAe,EAAE,CAAC;YACrB,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;4BACnB,KAAK,EAAE,+BAA+B,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE;yBACjE,CAAC;qBACH;iBACF;gBACD,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QAED,MAAM,aAAa,GAAG;YACpB,GAAG,MAAM;YACT,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,QAAQ,EAAE,OAAO,CAAC,QAAQ;SAC3B,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,gBAAgB,CACnC,OAAO,EACP,GAAG,EACH,aAAa,EACb,eAAe,CAChB,CAAC;QAEF,gEAAgE;QAChE,MAAM,UAAU,GAAG,qBAAqB,CACtC,OAAO,EACP,GAAG,EACH,aAAa,EACb,oBAAoB,CACrB,CAAC;QAEF,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;wBACnB,KAAK,EAAE,MAAM,CAAC,KAAK;wBACnB,SAAS,EAAE,MAAM,CAAC,QAAQ,CAAC,SAAS;wBACpC,QAAQ,EAAE,MAAM,CAAC,QAAQ;wBACzB,QAAQ,EAAE,MAAM,CAAC,QAAQ;wBACzB,QAAQ,EAAE,MAAM,CAAC,QAAQ;wBACzB,YAAY,EAAE,MAAM,CAAC,WAAW;wBAChC,WAAW,EAAE,UAAU;qBACxB,CAAC;iBACH;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { loadConfig } from "../../config/loader.js";
|
|
4
|
+
import { getAvailableProviders, } from "../../providers/registry.js";
|
|
5
|
+
import { initReviewSession } from "../../core/operations.js";
|
|
6
|
+
const inputSchema = {
|
|
7
|
+
plan_path: z
|
|
8
|
+
.string()
|
|
9
|
+
.describe("Path to the plan markdown file (absolute or relative to cwd)"),
|
|
10
|
+
cwd: z
|
|
11
|
+
.string()
|
|
12
|
+
.optional()
|
|
13
|
+
.describe("Working directory (defaults to process.cwd())"),
|
|
14
|
+
max_rounds: z
|
|
15
|
+
.number()
|
|
16
|
+
.int()
|
|
17
|
+
.min(1)
|
|
18
|
+
.max(50)
|
|
19
|
+
.optional()
|
|
20
|
+
.describe("Maximum review rounds"),
|
|
21
|
+
planner: z
|
|
22
|
+
.object({
|
|
23
|
+
provider: z.string().optional(),
|
|
24
|
+
model: z.string().optional(),
|
|
25
|
+
effort: z.string().optional(),
|
|
26
|
+
})
|
|
27
|
+
.optional()
|
|
28
|
+
.describe("Planner configuration overrides"),
|
|
29
|
+
reviewer: z
|
|
30
|
+
.object({
|
|
31
|
+
provider: z.string().optional(),
|
|
32
|
+
model: z.string().optional(),
|
|
33
|
+
effort: z.string().optional(),
|
|
34
|
+
})
|
|
35
|
+
.optional()
|
|
36
|
+
.describe("Reviewer configuration overrides"),
|
|
37
|
+
interactive: z
|
|
38
|
+
.boolean()
|
|
39
|
+
.optional()
|
|
40
|
+
.describe("If true, pause after each round for user confirmation. Default: false (autonomous)"),
|
|
41
|
+
};
|
|
42
|
+
export function registerStartReview(server) {
|
|
43
|
+
server.tool("planpong_start_review", "Create a review session for an existing plan file. Validates the file, loads config, checks provider availability, and creates a session. Does NOT invoke any models.", inputSchema, async (input) => {
|
|
44
|
+
const cwd = input.cwd ?? process.cwd();
|
|
45
|
+
const planPath = resolve(cwd, input.plan_path);
|
|
46
|
+
const config = loadConfig({
|
|
47
|
+
cwd,
|
|
48
|
+
overrides: {
|
|
49
|
+
plannerProvider: input.planner?.provider,
|
|
50
|
+
plannerModel: input.planner?.model,
|
|
51
|
+
plannerEffort: input.planner?.effort,
|
|
52
|
+
reviewerProvider: input.reviewer?.provider,
|
|
53
|
+
reviewerModel: input.reviewer?.model,
|
|
54
|
+
reviewerEffort: input.reviewer?.effort,
|
|
55
|
+
maxRounds: input.max_rounds,
|
|
56
|
+
autonomous: true,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
// Check provider availability
|
|
60
|
+
const available = await getAvailableProviders();
|
|
61
|
+
const availableNames = available.map((p) => p.name);
|
|
62
|
+
const plannerAvailable = availableNames.includes(config.planner.provider);
|
|
63
|
+
const reviewerAvailable = availableNames.includes(config.reviewer.provider);
|
|
64
|
+
if (!plannerAvailable || !reviewerAvailable) {
|
|
65
|
+
const missing = [];
|
|
66
|
+
if (!plannerAvailable)
|
|
67
|
+
missing.push(`planner: ${config.planner.provider}`);
|
|
68
|
+
if (!reviewerAvailable)
|
|
69
|
+
missing.push(`reviewer: ${config.reviewer.provider}`);
|
|
70
|
+
return {
|
|
71
|
+
content: [
|
|
72
|
+
{
|
|
73
|
+
type: "text",
|
|
74
|
+
text: JSON.stringify({
|
|
75
|
+
error: `Providers not available: ${missing.join(", ")}`,
|
|
76
|
+
available: availableNames,
|
|
77
|
+
}),
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
isError: true,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
const { session, planContent } = initReviewSession(planPath, cwd, config);
|
|
84
|
+
const planSummary = planContent.split("\n").slice(0, 20).join("\n");
|
|
85
|
+
return {
|
|
86
|
+
content: [
|
|
87
|
+
{
|
|
88
|
+
type: "text",
|
|
89
|
+
text: JSON.stringify({
|
|
90
|
+
session_id: session.id,
|
|
91
|
+
plan_path: planPath,
|
|
92
|
+
plan_summary: planSummary,
|
|
93
|
+
interactive: input.interactive ?? false,
|
|
94
|
+
config: {
|
|
95
|
+
planner: config.planner,
|
|
96
|
+
reviewer: config.reviewer,
|
|
97
|
+
max_rounds: config.max_rounds,
|
|
98
|
+
},
|
|
99
|
+
}),
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
};
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=start-review.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start-review.js","sourceRoot":"","sources":["../../../../src/mcp/tools/start-review.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { readSessionState, readRoundFeedback, readRoundResponse, } from "../../core/session.js";
|
|
3
|
+
import { formatTrajectory, severityFromFeedback, } from "../../core/operations.js";
|
|
4
|
+
const inputSchema = {
|
|
5
|
+
session_id: z.string().describe("Session ID to check"),
|
|
6
|
+
cwd: z
|
|
7
|
+
.string()
|
|
8
|
+
.optional()
|
|
9
|
+
.describe("Working directory (defaults to process.cwd())"),
|
|
10
|
+
};
|
|
11
|
+
export function registerStatus(server) {
|
|
12
|
+
server.tool("planpong_status", "Check session state and round history for a planpong review session.", inputSchema, async (input) => {
|
|
13
|
+
const cwd = input.cwd ?? process.cwd();
|
|
14
|
+
const session = readSessionState(cwd, input.session_id);
|
|
15
|
+
if (!session) {
|
|
16
|
+
return {
|
|
17
|
+
content: [
|
|
18
|
+
{
|
|
19
|
+
type: "text",
|
|
20
|
+
text: JSON.stringify({
|
|
21
|
+
error: `Session not found: ${input.session_id}`,
|
|
22
|
+
}),
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
isError: true,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const rounds = [];
|
|
29
|
+
const severities = [];
|
|
30
|
+
for (let r = 1; r <= session.currentRound; r++) {
|
|
31
|
+
const fb = readRoundFeedback(cwd, session.id, r);
|
|
32
|
+
const resp = readRoundResponse(cwd, session.id, r);
|
|
33
|
+
const roundInfo = { round: r };
|
|
34
|
+
if (fb) {
|
|
35
|
+
roundInfo.feedback_summary = fb.summary;
|
|
36
|
+
roundInfo.verdict = fb.verdict;
|
|
37
|
+
const severity = severityFromFeedback(fb);
|
|
38
|
+
roundInfo.severity_counts = severity;
|
|
39
|
+
severities.push(severity);
|
|
40
|
+
}
|
|
41
|
+
if (resp) {
|
|
42
|
+
let accepted = 0, rejected = 0, deferred = 0;
|
|
43
|
+
for (const response of resp.responses) {
|
|
44
|
+
if (response.action === "accepted")
|
|
45
|
+
accepted++;
|
|
46
|
+
else if (response.action === "rejected")
|
|
47
|
+
rejected++;
|
|
48
|
+
else if (response.action === "deferred")
|
|
49
|
+
deferred++;
|
|
50
|
+
}
|
|
51
|
+
roundInfo.response_summary = `${accepted} accepted, ${rejected} rejected, ${deferred} deferred`;
|
|
52
|
+
roundInfo.accepted = accepted;
|
|
53
|
+
roundInfo.rejected = rejected;
|
|
54
|
+
roundInfo.deferred = deferred;
|
|
55
|
+
}
|
|
56
|
+
rounds.push(roundInfo);
|
|
57
|
+
}
|
|
58
|
+
const trajectory = severities.length > 0
|
|
59
|
+
? formatTrajectory(severities)
|
|
60
|
+
: "No rounds completed";
|
|
61
|
+
return {
|
|
62
|
+
content: [
|
|
63
|
+
{
|
|
64
|
+
type: "text",
|
|
65
|
+
text: JSON.stringify({
|
|
66
|
+
session: {
|
|
67
|
+
id: session.id,
|
|
68
|
+
plan_path: session.planPath,
|
|
69
|
+
status: session.status,
|
|
70
|
+
current_round: session.currentRound,
|
|
71
|
+
started_at: session.startedAt,
|
|
72
|
+
planner: session.planner,
|
|
73
|
+
reviewer: session.reviewer,
|
|
74
|
+
},
|
|
75
|
+
rounds,
|
|
76
|
+
trajectory,
|
|
77
|
+
}),
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../../src/mcp/tools/status.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { ReviewFeedback } from "../schemas/feedback.js";
|
|
2
|
+
export declare function buildInitialPlanPrompt(requirements: string, plansDir: string): string;
|
|
3
|
+
export declare function buildRevisionPrompt(currentPlan: string, feedback: ReviewFeedback, keyDecisions: string | null, priorContext: string | null): string;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
export function buildInitialPlanPrompt(requirements, plansDir) {
|
|
2
|
+
return `You are a software architect creating an implementation plan.
|
|
3
|
+
|
|
4
|
+
Given the following requirements, create a detailed implementation plan in markdown format.
|
|
5
|
+
|
|
6
|
+
The plan MUST include ALL of the following sections:
|
|
7
|
+
1. **Status line** as the first line after the title: \`**Status:** Draft\`
|
|
8
|
+
2. **Context** — why this work exists, in 2-3 sentences
|
|
9
|
+
3. **Steps as checkboxes** — use \`- [ ]\` format with clear descriptions
|
|
10
|
+
4. **File references** — table of files to create, modify, or delete
|
|
11
|
+
5. **Verification criteria** — what "done" looks like, specific and testable
|
|
12
|
+
6. **Key decisions** — alternatives considered and why one was chosen
|
|
13
|
+
|
|
14
|
+
Output ONLY the markdown plan. No preamble, no commentary.
|
|
15
|
+
|
|
16
|
+
## Requirements
|
|
17
|
+
|
|
18
|
+
${requirements}`;
|
|
19
|
+
}
|
|
20
|
+
export function buildRevisionPrompt(currentPlan, feedback, keyDecisions, priorContext) {
|
|
21
|
+
const contextBlock = priorContext
|
|
22
|
+
? `\n## Prior Research & Constraints\n\n${priorContext}\n`
|
|
23
|
+
: "";
|
|
24
|
+
const decisionsBlock = keyDecisions
|
|
25
|
+
? `\n## Key Decisions From Plan\n\n${keyDecisions}\n`
|
|
26
|
+
: "";
|
|
27
|
+
const issuesList = feedback.issues
|
|
28
|
+
.map((issue) => `### ${issue.id} (${issue.severity}): ${issue.title}\n**Section:** ${issue.section}\n**Description:** ${issue.description}\n**Suggestion:** ${issue.suggestion}`)
|
|
29
|
+
.join("\n\n");
|
|
30
|
+
return `You are revising a plan based on reviewer feedback. You are the plan's ADVOCATE, not a compliance engine. Evaluate each issue on its merits:
|
|
31
|
+
|
|
32
|
+
REJECT when:
|
|
33
|
+
- The issue is based on a false premise or misunderstanding of the design
|
|
34
|
+
- The concern was already addressed by a decision documented in the plan
|
|
35
|
+
- The issue conflicts with validated constraints or prior research
|
|
36
|
+
- The reviewer is speculating (look for low-confidence hedging language)
|
|
37
|
+
|
|
38
|
+
DISPUTE SEVERITY when:
|
|
39
|
+
- The issue is valid but the impact is overstated (P1 claimed, P2 actual)
|
|
40
|
+
- The risk is theoretical, not practical (quantify if possible)
|
|
41
|
+
- The issue has a simple fix that doesn't warrant the flagged severity
|
|
42
|
+
|
|
43
|
+
ACCEPT when:
|
|
44
|
+
- The issue identifies a genuine gap not covered by existing decisions
|
|
45
|
+
- The concern is supported by evidence or concrete scenarios
|
|
46
|
+
- The fix improves the plan without contradicting its design principles
|
|
47
|
+
|
|
48
|
+
DEFER when:
|
|
49
|
+
- The issue is valid but out of scope for the current phase
|
|
50
|
+
- Addressing it would expand scope beyond what was agreed
|
|
51
|
+
- It's a good idea for v2 but not a blocker for v1
|
|
52
|
+
|
|
53
|
+
For each response, cite specific evidence: reference the plan section, the research that informed the decision, or the constraint that makes the suggestion inapplicable. Vague agreement ("good point, updated") is not acceptable — explain WHY you're accepting, with the same rigor you'd use for a rejection.
|
|
54
|
+
${contextBlock}${decisionsBlock}
|
|
55
|
+
## Current Plan
|
|
56
|
+
|
|
57
|
+
${currentPlan}
|
|
58
|
+
|
|
59
|
+
## Reviewer Feedback
|
|
60
|
+
|
|
61
|
+
**Summary:** ${feedback.summary}
|
|
62
|
+
|
|
63
|
+
${issuesList}
|
|
64
|
+
|
|
65
|
+
## Your Task
|
|
66
|
+
|
|
67
|
+
Respond with a JSON object wrapped in <planpong-revision> tags. The JSON must match this schema:
|
|
68
|
+
|
|
69
|
+
\`\`\`
|
|
70
|
+
{
|
|
71
|
+
"responses": [
|
|
72
|
+
{
|
|
73
|
+
"issue_id": "F1",
|
|
74
|
+
"action": "accepted" | "rejected" | "deferred",
|
|
75
|
+
"severity_dispute": { // optional
|
|
76
|
+
"original": "P1",
|
|
77
|
+
"revised": "P2",
|
|
78
|
+
"justification": "..."
|
|
79
|
+
},
|
|
80
|
+
"rationale": "Detailed explanation of why this action was taken"
|
|
81
|
+
}
|
|
82
|
+
],
|
|
83
|
+
"updated_plan": "The full updated plan in markdown (incorporate accepted changes)"
|
|
84
|
+
}
|
|
85
|
+
\`\`\`
|
|
86
|
+
|
|
87
|
+
IMPORTANT:
|
|
88
|
+
- Every issue MUST have a response. Do not skip any.
|
|
89
|
+
- The \`updated_plan\` must be the complete plan markdown, not a diff.
|
|
90
|
+
- Wrap your JSON response in <planpong-revision>...</planpong-revision> tags.
|
|
91
|
+
|
|
92
|
+
<planpong-revision>
|
|
93
|
+
YOUR_JSON_HERE
|
|
94
|
+
</planpong-revision>`;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=planner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"planner.js","sourceRoot":"","sources":["../../../src/prompts/planner.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,sBAAsB,CACpC,YAAoB,EACpB,QAAgB;IAEhB,OAAO;;;;;;;;;;;;;;;;EAgBP,YAAY,EAAE,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,WAAmB,EACnB,QAAwB,EACxB,YAA2B,EAC3B,YAA2B;IAE3B,MAAM,YAAY,GAAG,YAAY;QAC/B,CAAC,CAAC,wCAAwC,YAAY,IAAI;QAC1D,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,cAAc,GAAG,YAAY;QACjC,CAAC,CAAC,mCAAmC,YAAY,IAAI;QACrD,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM;SAC/B,GAAG,CACF,CAAC,KAAK,EAAE,EAAE,CACR,OAAO,KAAK,CAAC,EAAE,KAAK,KAAK,CAAC,QAAQ,MAAM,KAAK,CAAC,KAAK,kBAAkB,KAAK,CAAC,OAAO,sBAAsB,KAAK,CAAC,WAAW,qBAAqB,KAAK,CAAC,UAAU,EAAE,CACnK;SACA,IAAI,CAAC,MAAM,CAAC,CAAC;IAEhB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;EAwBP,YAAY,GAAG,cAAc;;;EAG7B,WAAW;;;;eAIE,QAAQ,CAAC,OAAO;;EAE7B,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA+BS,CAAC;AACtB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { IssueResponse } from "../schemas/revision.js";
|
|
2
|
+
export declare function buildReviewPrompt(planContent: string, priorDecisions: string | null): string;
|
|
3
|
+
export declare function formatPriorDecisions(rounds: Array<{
|
|
4
|
+
round: number;
|
|
5
|
+
responses: IssueResponse[];
|
|
6
|
+
issues: Array<{
|
|
7
|
+
id: string;
|
|
8
|
+
severity: string;
|
|
9
|
+
title: string;
|
|
10
|
+
}>;
|
|
11
|
+
}>): string;
|