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.
Files changed (83) hide show
  1. package/README.md +110 -0
  2. package/dist/bin/planpong-mcp.d.ts +2 -0
  3. package/dist/bin/planpong-mcp.js +7 -0
  4. package/dist/bin/planpong-mcp.js.map +1 -0
  5. package/dist/bin/planpong.d.ts +2 -0
  6. package/dist/bin/planpong.js +13 -0
  7. package/dist/bin/planpong.js.map +1 -0
  8. package/dist/src/cli/commands/plan.d.ts +2 -0
  9. package/dist/src/cli/commands/plan.js +128 -0
  10. package/dist/src/cli/commands/plan.js.map +1 -0
  11. package/dist/src/cli/commands/review.d.ts +2 -0
  12. package/dist/src/cli/commands/review.js +156 -0
  13. package/dist/src/cli/commands/review.js.map +1 -0
  14. package/dist/src/cli/ui.d.ts +11 -0
  15. package/dist/src/cli/ui.js +65 -0
  16. package/dist/src/cli/ui.js.map +1 -0
  17. package/dist/src/config/defaults.d.ts +2 -0
  18. package/dist/src/config/defaults.js +12 -0
  19. package/dist/src/config/defaults.js.map +1 -0
  20. package/dist/src/config/loader.d.ts +17 -0
  21. package/dist/src/config/loader.js +74 -0
  22. package/dist/src/config/loader.js.map +1 -0
  23. package/dist/src/core/convergence.d.ts +10 -0
  24. package/dist/src/core/convergence.js +56 -0
  25. package/dist/src/core/convergence.js.map +1 -0
  26. package/dist/src/core/loop.d.ts +53 -0
  27. package/dist/src/core/loop.js +256 -0
  28. package/dist/src/core/loop.js.map +1 -0
  29. package/dist/src/core/operations.d.ts +68 -0
  30. package/dist/src/core/operations.js +323 -0
  31. package/dist/src/core/operations.js.map +1 -0
  32. package/dist/src/core/session.d.ts +14 -0
  33. package/dist/src/core/session.js +77 -0
  34. package/dist/src/core/session.js.map +1 -0
  35. package/dist/src/mcp/server.d.ts +2 -0
  36. package/dist/src/mcp/server.js +109 -0
  37. package/dist/src/mcp/server.js.map +1 -0
  38. package/dist/src/mcp/tools/get-feedback.d.ts +2 -0
  39. package/dist/src/mcp/tools/get-feedback.js +109 -0
  40. package/dist/src/mcp/tools/get-feedback.js.map +1 -0
  41. package/dist/src/mcp/tools/list-sessions.d.ts +2 -0
  42. package/dist/src/mcp/tools/list-sessions.js +61 -0
  43. package/dist/src/mcp/tools/list-sessions.js.map +1 -0
  44. package/dist/src/mcp/tools/revise.d.ts +2 -0
  45. package/dist/src/mcp/tools/revise.js +84 -0
  46. package/dist/src/mcp/tools/revise.js.map +1 -0
  47. package/dist/src/mcp/tools/start-review.d.ts +2 -0
  48. package/dist/src/mcp/tools/start-review.js +105 -0
  49. package/dist/src/mcp/tools/start-review.js.map +1 -0
  50. package/dist/src/mcp/tools/status.d.ts +2 -0
  51. package/dist/src/mcp/tools/status.js +83 -0
  52. package/dist/src/mcp/tools/status.js.map +1 -0
  53. package/dist/src/prompts/planner.d.ts +3 -0
  54. package/dist/src/prompts/planner.js +96 -0
  55. package/dist/src/prompts/planner.js.map +1 -0
  56. package/dist/src/prompts/reviewer.d.ts +11 -0
  57. package/dist/src/prompts/reviewer.js +70 -0
  58. package/dist/src/prompts/reviewer.js.map +1 -0
  59. package/dist/src/providers/claude.d.ts +8 -0
  60. package/dist/src/providers/claude.js +77 -0
  61. package/dist/src/providers/claude.js.map +1 -0
  62. package/dist/src/providers/codex.d.ts +8 -0
  63. package/dist/src/providers/codex.js +83 -0
  64. package/dist/src/providers/codex.js.map +1 -0
  65. package/dist/src/providers/registry.d.ts +4 -0
  66. package/dist/src/providers/registry.js +17 -0
  67. package/dist/src/providers/registry.js.map +1 -0
  68. package/dist/src/providers/types.d.ts +18 -0
  69. package/dist/src/providers/types.js +2 -0
  70. package/dist/src/providers/types.js.map +1 -0
  71. package/dist/src/schemas/config.d.ts +75 -0
  72. package/dist/src/schemas/config.js +14 -0
  73. package/dist/src/schemas/config.js.map +1 -0
  74. package/dist/src/schemas/feedback.d.ts +95 -0
  75. package/dist/src/schemas/feedback.js +24 -0
  76. package/dist/src/schemas/feedback.js.map +1 -0
  77. package/dist/src/schemas/revision.d.ts +116 -0
  78. package/dist/src/schemas/revision.js +17 -0
  79. package/dist/src/schemas/revision.js.map +1 -0
  80. package/dist/src/schemas/session.d.ts +79 -0
  81. package/dist/src/schemas/session.js +16 -0
  82. package/dist/src/schemas/session.js.map +1 -0
  83. 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,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerListSessions(server: McpServer): void;
@@ -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,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerRevise(server: McpServer): void;
@@ -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":"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"}
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerStartReview(server: McpServer): void;
@@ -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,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerStatus(server: McpServer): void;
@@ -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":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,0BAA0B,CAAC;AAElC,MAAM,WAAW,GAAG;IAClB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qBAAqB,CAAC;IACtD,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,sEAAsE,EACtE,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,MAAM,MAAM,GASP,EAAE,CAAC;QAER,MAAM,UAAU,GAAkD,EAAE,CAAC;QAErE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/C,MAAM,EAAE,GAAG,iBAAiB,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;YACjD,MAAM,IAAI,GAAG,iBAAiB,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;YAEnD,MAAM,SAAS,GAAuB,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;YAEnD,IAAI,EAAE,EAAE,CAAC;gBACP,SAAS,CAAC,gBAAgB,GAAG,EAAE,CAAC,OAAO,CAAC;gBACxC,SAAS,CAAC,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC;gBAC/B,MAAM,QAAQ,GAAG,oBAAoB,CAAC,EAAE,CAAC,CAAC;gBAC1C,SAAS,CAAC,eAAe,GAAG,QAAQ,CAAC;gBACrC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC5B,CAAC;YAED,IAAI,IAAI,EAAE,CAAC;gBACT,IAAI,QAAQ,GAAG,CAAC,EACd,QAAQ,GAAG,CAAC,EACZ,QAAQ,GAAG,CAAC,CAAC;gBACf,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;oBACtC,IAAI,QAAQ,CAAC,MAAM,KAAK,UAAU;wBAAE,QAAQ,EAAE,CAAC;yBAC1C,IAAI,QAAQ,CAAC,MAAM,KAAK,UAAU;wBAAE,QAAQ,EAAE,CAAC;yBAC/C,IAAI,QAAQ,CAAC,MAAM,KAAK,UAAU;wBAAE,QAAQ,EAAE,CAAC;gBACtD,CAAC;gBACD,SAAS,CAAC,gBAAgB,GAAG,GAAG,QAAQ,cAAc,QAAQ,cAAc,QAAQ,WAAW,CAAC;gBAChG,SAAS,CAAC,QAAQ,GAAG,QAAQ,CAAC;gBAC9B,SAAS,CAAC,QAAQ,GAAG,QAAQ,CAAC;gBAC9B,SAAS,CAAC,QAAQ,GAAG,QAAQ,CAAC;YAChC,CAAC;YAED,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACzB,CAAC;QAED,MAAM,UAAU,GACd,UAAU,CAAC,MAAM,GAAG,CAAC;YACnB,CAAC,CAAC,gBAAgB,CAAC,UAAU,CAAC;YAC9B,CAAC,CAAC,qBAAqB,CAAC;QAE5B,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;wBACnB,OAAO,EAAE;4BACP,EAAE,EAAE,OAAO,CAAC,EAAE;4BACd,SAAS,EAAE,OAAO,CAAC,QAAQ;4BAC3B,MAAM,EAAE,OAAO,CAAC,MAAM;4BACtB,aAAa,EAAE,OAAO,CAAC,YAAY;4BACnC,UAAU,EAAE,OAAO,CAAC,SAAS;4BAC7B,OAAO,EAAE,OAAO,CAAC,OAAO;4BACxB,QAAQ,EAAE,OAAO,CAAC,QAAQ;yBAC3B;wBACD,MAAM;wBACN,UAAU;qBACX,CAAC;iBACH;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -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;