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
package/README.md ADDED
@@ -0,0 +1,110 @@
1
+ # Planpong
2
+
3
+ Adversarial plan review for AI-assisted development. Two AI models play ping-pong with your plan — one critiques, the other revises — until the plan converges or you stop them.
4
+
5
+ ## How it works
6
+
7
+ 1. You write a plan (markdown file)
8
+ 2. A **reviewer** model finds issues (P1/P2/P3 severity)
9
+ 3. A **planner** model accepts, rejects, or defers each issue and rewrites the plan
10
+ 4. Repeat until the reviewer approves or max rounds hit
11
+
12
+ Default config: Claude revises, Codex reviews. Both are swappable.
13
+
14
+ ## Prerequisites
15
+
16
+ You need **two AI CLI tools** installed and authenticated:
17
+
18
+ - **Claude Code** — `npm install -g @anthropic-ai/claude-code` (needs Anthropic API key or Max subscription)
19
+ - **Codex CLI** — `npm install -g @openai/codex` (needs OpenAI API key)
20
+
21
+ Verify both work:
22
+
23
+ ```sh
24
+ claude --version
25
+ codex --version
26
+ ```
27
+
28
+ Planpong shells out to these CLIs. No API keys are configured in planpong itself.
29
+
30
+ ## Install
31
+
32
+ ```sh
33
+ npm install -g github:andrewhml/planpong
34
+ ```
35
+
36
+ ## Setup (Claude Code MCP)
37
+
38
+ Add planpong as an MCP server so Claude Code can use it natively:
39
+
40
+ ```sh
41
+ claude mcp add planpong -- planpong-mcp
42
+ ```
43
+
44
+ Then allow the tools in your Claude Code settings (`.claude/settings.json`):
45
+
46
+ ```json
47
+ {
48
+ "permissions": {
49
+ "allow": ["mcp__planpong"]
50
+ }
51
+ }
52
+ ```
53
+
54
+ Restart Claude Code. You should see `planpong` tools in your tool list.
55
+
56
+ ## Usage
57
+
58
+ ### Via Claude Code (recommended)
59
+
60
+ Ask Claude to review a plan:
61
+
62
+ ```
63
+ Review my plan at docs/plans/my-feature.md using planpong
64
+ ```
65
+
66
+ Or use the slash commands (auto-installed with the MCP server):
67
+
68
+ ```
69
+ /planpong:review docs/plans/my-feature.md # autonomous — runs to completion
70
+ /planpong:review_interactive docs/plans/my-feature.md # pauses between rounds
71
+ ```
72
+
73
+ ### Via CLI
74
+
75
+ ```sh
76
+ planpong review docs/plans/my-feature.md
77
+ ```
78
+
79
+ ## Configuration
80
+
81
+ Optional. Create `planpong.yaml` in your project root:
82
+
83
+ ```yaml
84
+ planner:
85
+ provider: claude # claude or codex
86
+ model: opus # provider-specific model name
87
+ effort: high # reasoning effort level
88
+ reviewer:
89
+ provider: codex
90
+ model: o3
91
+ effort: high
92
+ max_rounds: 10
93
+ plans_dir: docs/plans
94
+ ```
95
+
96
+ All fields are optional. Defaults: claude (planner) + codex (reviewer), 10 rounds, `docs/plans/` directory.
97
+
98
+ ## What it writes
99
+
100
+ Planpong updates your plan file in-place. It adds a status line:
101
+
102
+ ```
103
+ **planpong:** R3/10 | claude → codex | 2P2 1P3 → 1P3 → 0 | Accepted: 4 | +32/-8 lines | 5m 23s | Approved after 3 rounds
104
+ ```
105
+
106
+ Session data is stored in `.planpong/sessions/` (add to `.gitignore`).
107
+
108
+ ## License
109
+
110
+ MIT
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { createPlanpongServer } from "../src/mcp/server.js";
4
+ const server = createPlanpongServer();
5
+ const transport = new StdioServerTransport();
6
+ await server.connect(transport);
7
+ //# sourceMappingURL=planpong-mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planpong-mcp.js","sourceRoot":"","sources":["../../bin/planpong-mcp.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAE5D,MAAM,MAAM,GAAG,oBAAoB,EAAE,CAAC;AACtC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import { registerPlanCommand } from "../src/cli/commands/plan.js";
4
+ import { registerReviewCommand } from "../src/cli/commands/review.js";
5
+ const program = new Command();
6
+ program
7
+ .name("planpong")
8
+ .description("Multi-model plan review CLI — orchestrates AI agents for adversarial plan refinement")
9
+ .version("0.1.0");
10
+ registerPlanCommand(program);
11
+ registerReviewCommand(program);
12
+ program.parse();
13
+ //# sourceMappingURL=planpong.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planpong.js","sourceRoot":"","sources":["../../bin/planpong.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAEtE,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,UAAU,CAAC;KAChB,WAAW,CACV,sFAAsF,CACvF;KACA,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAC7B,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAE/B,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Command } from "commander";
2
+ export declare function registerPlanCommand(program: Command): void;
@@ -0,0 +1,128 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import { confirm } from "@inquirer/prompts";
4
+ import { loadConfig } from "../../config/loader.js";
5
+ import { getProvider, getAvailableProviders, } from "../../providers/registry.js";
6
+ import { runLoop } from "../../core/loop.js";
7
+ import { printBanner, printPlanGenerated, printFeedbackSummary, printRevisionSummary, printConverged, printMaxRounds, createSpinner, } from "../ui.js";
8
+ export function registerPlanCommand(program) {
9
+ program
10
+ .command("plan")
11
+ .description("Generate and review a plan through adversarial refinement")
12
+ .argument("<requirements>", "Requirements text or path to a .md/.txt file")
13
+ .option("--name <name>", "Plan filename slug (auto-generated if omitted)")
14
+ .option("--planner-provider <provider>", "Planner provider (claude, codex)")
15
+ .option("--planner-model <model>", "Planner model override")
16
+ .option("--planner-effort <effort>", "Planner effort level")
17
+ .option("--reviewer-provider <provider>", "Reviewer provider (claude, codex)")
18
+ .option("--reviewer-model <model>", "Reviewer model override")
19
+ .option("--reviewer-effort <effort>", "Reviewer effort level")
20
+ .option("--plans-dir <dir>", "Plans output directory")
21
+ .option("--max-rounds <n>", "Maximum review rounds")
22
+ .option("--autonomous", "Run without human-in-loop pauses")
23
+ .action(async (requirementsArg, opts) => {
24
+ printBanner();
25
+ const cwd = process.cwd();
26
+ // Resolve requirements: file path or inline text
27
+ let requirements;
28
+ if (requirementsArg.endsWith(".md") || requirementsArg.endsWith(".txt")) {
29
+ const filePath = resolve(cwd, requirementsArg);
30
+ requirements = readFileSync(filePath, "utf-8");
31
+ }
32
+ else {
33
+ requirements = requirementsArg;
34
+ }
35
+ // Load config with CLI overrides
36
+ const config = loadConfig({
37
+ cwd,
38
+ overrides: {
39
+ plannerProvider: opts.plannerProvider,
40
+ plannerModel: opts.plannerModel,
41
+ plannerEffort: opts.plannerEffort,
42
+ reviewerProvider: opts.reviewerProvider,
43
+ reviewerModel: opts.reviewerModel,
44
+ reviewerEffort: opts.reviewerEffort,
45
+ plansDir: opts.plansDir,
46
+ maxRounds: opts.maxRounds ? parseInt(opts.maxRounds, 10) : undefined,
47
+ autonomous: opts.autonomous,
48
+ },
49
+ });
50
+ // Check provider availability
51
+ const available = await getAvailableProviders();
52
+ const availableNames = available.map((p) => p.name);
53
+ const plannerAvailable = availableNames.includes(config.planner.provider);
54
+ const reviewerAvailable = availableNames.includes(config.reviewer.provider);
55
+ if (!plannerAvailable || !reviewerAvailable) {
56
+ const missing = [];
57
+ if (!plannerAvailable)
58
+ missing.push(`planner: ${config.planner.provider}`);
59
+ if (!reviewerAvailable)
60
+ missing.push(`reviewer: ${config.reviewer.provider}`);
61
+ console.error(`Error: Provider(s) not available: ${missing.join(", ")}`);
62
+ console.error(`Available: ${availableNames.join(", ") || "none detected"}`);
63
+ process.exit(1);
64
+ }
65
+ const plannerProvider = getProvider(config.planner.provider);
66
+ const reviewerProvider = getProvider(config.reviewer.provider);
67
+ if (!plannerProvider || !reviewerProvider) {
68
+ console.error("Error: Could not resolve provider instances.");
69
+ process.exit(1);
70
+ }
71
+ // Wire callbacks
72
+ const callbacks = {
73
+ async onPlanGenerated(planPath, _content) {
74
+ printPlanGenerated(planPath);
75
+ },
76
+ onReviewStarting(round) {
77
+ const spinner = createSpinner(`Round ${round}: Sending to reviewer (${config.reviewer.provider})...`);
78
+ // Store spinner so onReviewComplete can stop it
79
+ callbacks._reviewSpinner = spinner;
80
+ },
81
+ async onReviewComplete(round, feedback) {
82
+ callbacks._reviewSpinner?.stop();
83
+ printFeedbackSummary(round, feedback);
84
+ },
85
+ onRevisionStarting(round) {
86
+ const spinner = createSpinner(`Round ${round}: Planner revising (${config.planner.provider})...`);
87
+ callbacks._revisionSpinner = spinner;
88
+ },
89
+ async onRevisionComplete(round, revision) {
90
+ callbacks._revisionSpinner?.stop();
91
+ printRevisionSummary(round, revision);
92
+ },
93
+ onConverged(round, _feedback) {
94
+ printConverged(round);
95
+ },
96
+ onMaxRoundsReached(_round) {
97
+ printMaxRounds(config.max_rounds);
98
+ },
99
+ async onHashMismatch(planPath, _autonomous) {
100
+ const overwrite = await confirm({
101
+ message: `Plan file was modified externally (${planPath}). Overwrite with revision?`,
102
+ default: true,
103
+ });
104
+ return overwrite ? "overwrite" : "abort";
105
+ },
106
+ async confirmContinue(message) {
107
+ return confirm({ message, default: true });
108
+ },
109
+ };
110
+ try {
111
+ await runLoop({
112
+ requirements,
113
+ cwd,
114
+ config,
115
+ plannerProvider,
116
+ reviewerProvider,
117
+ planName: opts.name,
118
+ callbacks,
119
+ });
120
+ }
121
+ catch (err) {
122
+ const msg = err instanceof Error ? err.message : String(err);
123
+ console.error(`\nError: ${msg}`);
124
+ process.exit(1);
125
+ }
126
+ });
127
+ }
128
+ //# sourceMappingURL=plan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.js","sourceRoot":"","sources":["../../../../src/cli/commands/plan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { Command } from "commander";
2
+ export declare function registerReviewCommand(program: Command): void;
@@ -0,0 +1,156 @@
1
+ import { resolve } from "node:path";
2
+ import { confirm } from "@inquirer/prompts";
3
+ import { loadConfig } from "../../config/loader.js";
4
+ import { getProvider, getAvailableProviders, } from "../../providers/registry.js";
5
+ import { runReviewLoop, } from "../../core/loop.js";
6
+ import { printBanner, printPlanGenerated, printFeedbackSummary, printRevisionSummary, printConverged, printMaxRounds, createSpinner, } from "../ui.js";
7
+ export function registerReviewCommand(program) {
8
+ program
9
+ .command("review")
10
+ .description("Review an existing plan file through adversarial refinement")
11
+ .argument("<plan-file>", "Path to the plan markdown file")
12
+ .option("--planner-provider <provider>", "Planner provider (claude, codex)")
13
+ .option("--planner-model <model>", "Planner model override")
14
+ .option("--planner-effort <effort>", "Planner effort level")
15
+ .option("--reviewer-provider <provider>", "Reviewer provider (claude, codex)")
16
+ .option("--reviewer-model <model>", "Reviewer model override")
17
+ .option("--reviewer-effort <effort>", "Reviewer effort level")
18
+ .option("--max-rounds <n>", "Maximum review rounds")
19
+ .option("--autonomous", "Run without human-in-loop pauses (default for review)")
20
+ .option("--json", "Output result as JSON (for programmatic use)")
21
+ .action(async (planFileArg, opts) => {
22
+ const cwd = process.cwd();
23
+ const planPath = resolve(cwd, planFileArg);
24
+ const jsonOutput = opts.json ?? false;
25
+ // Default to autonomous for review command
26
+ const autonomous = opts.autonomous ?? true;
27
+ const config = loadConfig({
28
+ cwd,
29
+ overrides: {
30
+ plannerProvider: opts.plannerProvider,
31
+ plannerModel: opts.plannerModel,
32
+ plannerEffort: opts.plannerEffort,
33
+ reviewerProvider: opts.reviewerProvider,
34
+ reviewerModel: opts.reviewerModel,
35
+ reviewerEffort: opts.reviewerEffort,
36
+ maxRounds: opts.maxRounds ? parseInt(opts.maxRounds, 10) : undefined,
37
+ autonomous,
38
+ },
39
+ });
40
+ // Check provider availability
41
+ const available = await getAvailableProviders();
42
+ const availableNames = available.map((p) => p.name);
43
+ const plannerAvailable = availableNames.includes(config.planner.provider);
44
+ const reviewerAvailable = availableNames.includes(config.reviewer.provider);
45
+ if (!plannerAvailable || !reviewerAvailable) {
46
+ const missing = [];
47
+ if (!plannerAvailable)
48
+ missing.push(`planner: ${config.planner.provider}`);
49
+ if (!reviewerAvailable)
50
+ missing.push(`reviewer: ${config.reviewer.provider}`);
51
+ if (jsonOutput) {
52
+ console.log(JSON.stringify({
53
+ error: `Providers not available: ${missing.join(", ")}`,
54
+ }));
55
+ }
56
+ else {
57
+ console.error(`Error: Provider(s) not available: ${missing.join(", ")}`);
58
+ console.error(`Available: ${availableNames.join(", ") || "none detected"}`);
59
+ }
60
+ process.exit(1);
61
+ }
62
+ const plannerProvider = getProvider(config.planner.provider);
63
+ const reviewerProvider = getProvider(config.reviewer.provider);
64
+ if (!plannerProvider || !reviewerProvider) {
65
+ if (jsonOutput) {
66
+ console.log(JSON.stringify({ error: "Could not resolve provider instances" }));
67
+ }
68
+ else {
69
+ console.error("Error: Could not resolve provider instances.");
70
+ }
71
+ process.exit(1);
72
+ }
73
+ if (!jsonOutput) {
74
+ printBanner();
75
+ }
76
+ // Wire callbacks — quiet in JSON mode, verbose otherwise
77
+ const callbacks = {
78
+ async onPlanGenerated(path, _content) {
79
+ if (!jsonOutput)
80
+ printPlanGenerated(path);
81
+ },
82
+ onReviewStarting(round) {
83
+ if (!jsonOutput) {
84
+ const spinner = createSpinner(`Round ${round}: Sending to reviewer (${config.reviewer.provider})...`);
85
+ callbacks._reviewSpinner = spinner;
86
+ }
87
+ },
88
+ async onReviewComplete(round, feedback) {
89
+ if (!jsonOutput) {
90
+ callbacks._reviewSpinner?.stop();
91
+ printFeedbackSummary(round, feedback);
92
+ }
93
+ },
94
+ onRevisionStarting(round) {
95
+ if (!jsonOutput) {
96
+ const spinner = createSpinner(`Round ${round}: Planner revising (${config.planner.provider})...`);
97
+ callbacks._revisionSpinner = spinner;
98
+ }
99
+ },
100
+ async onRevisionComplete(round, revision) {
101
+ if (!jsonOutput) {
102
+ callbacks._revisionSpinner?.stop();
103
+ printRevisionSummary(round, revision);
104
+ }
105
+ },
106
+ onConverged(round, _feedback) {
107
+ if (!jsonOutput)
108
+ printConverged(round);
109
+ },
110
+ onMaxRoundsReached(_round) {
111
+ if (!jsonOutput)
112
+ printMaxRounds(config.max_rounds);
113
+ },
114
+ async onHashMismatch(path, _autonomous) {
115
+ if (autonomous)
116
+ return "overwrite";
117
+ const overwrite = await confirm({
118
+ message: `Plan file was modified externally (${path}). Overwrite with revision?`,
119
+ default: true,
120
+ });
121
+ return overwrite ? "overwrite" : "abort";
122
+ },
123
+ async confirmContinue(message) {
124
+ if (autonomous)
125
+ return true;
126
+ return confirm({ message, default: true });
127
+ },
128
+ };
129
+ let result;
130
+ try {
131
+ result = await runReviewLoop({
132
+ planPath,
133
+ cwd,
134
+ config,
135
+ plannerProvider,
136
+ reviewerProvider,
137
+ callbacks,
138
+ });
139
+ }
140
+ catch (err) {
141
+ const msg = err instanceof Error ? err.message : String(err);
142
+ if (jsonOutput) {
143
+ console.log(JSON.stringify({ error: msg }));
144
+ }
145
+ else {
146
+ console.error(`\nError: ${msg}`);
147
+ }
148
+ process.exit(1);
149
+ }
150
+ if (jsonOutput) {
151
+ console.log(JSON.stringify(result));
152
+ }
153
+ process.exit(result.status === "approved" ? 0 : 1);
154
+ });
155
+ }
156
+ //# sourceMappingURL=review.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review.js","sourceRoot":"","sources":["../../../../src/cli/commands/review.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { type Ora } from "ora";
2
+ import type { ReviewFeedback } from "../schemas/feedback.js";
3
+ import type { PlannerRevision } from "../schemas/revision.js";
4
+ export declare function printBanner(): void;
5
+ export declare function printPlanGenerated(planPath: string): void;
6
+ export declare function createSpinner(text: string): Ora;
7
+ export declare function printFeedbackSummary(round: number, feedback: ReviewFeedback): void;
8
+ export declare function printRevisionSummary(round: number, revision: PlannerRevision): void;
9
+ export declare function printConverged(round: number): void;
10
+ export declare function printMaxRounds(maxRounds: number): void;
11
+ export declare function printAborted(): void;
@@ -0,0 +1,65 @@
1
+ import chalk from "chalk";
2
+ import ora from "ora";
3
+ const SEVERITY_COLORS = {
4
+ P1: chalk.red.bold,
5
+ P2: chalk.yellow,
6
+ P3: chalk.blue,
7
+ };
8
+ const ACTION_COLORS = {
9
+ accepted: chalk.green,
10
+ rejected: chalk.red,
11
+ deferred: chalk.yellow,
12
+ };
13
+ export function printBanner() {
14
+ console.log(chalk.bold("\nplanpong") + chalk.dim(" — multi-model plan review\n"));
15
+ }
16
+ export function printPlanGenerated(planPath) {
17
+ console.log(chalk.green("Plan written to:"), planPath);
18
+ }
19
+ export function createSpinner(text) {
20
+ return ora({ text, color: "cyan" }).start();
21
+ }
22
+ export function printFeedbackSummary(round, feedback) {
23
+ const verdictColor = feedback.verdict === "needs_revision" ? chalk.yellow : chalk.green;
24
+ console.log(`\n${chalk.bold(`Round ${round} Review`)} — ${verdictColor(feedback.verdict)}`);
25
+ console.log(chalk.dim(feedback.summary));
26
+ if (feedback.issues.length === 0) {
27
+ console.log(chalk.green(" No issues found."));
28
+ return;
29
+ }
30
+ console.log();
31
+ for (const issue of feedback.issues) {
32
+ printIssue(issue);
33
+ }
34
+ }
35
+ function printIssue(issue) {
36
+ const colorFn = SEVERITY_COLORS[issue.severity] ?? chalk.white;
37
+ console.log(` ${colorFn(issue.severity)} ${chalk.bold(issue.id)}: ${issue.title}`);
38
+ console.log(chalk.dim(` ${issue.section}`));
39
+ }
40
+ export function printRevisionSummary(round, revision) {
41
+ console.log(`\n${chalk.bold(`Round ${round} Revision`)}`);
42
+ for (const resp of revision.responses) {
43
+ const colorFn = ACTION_COLORS[resp.action] ?? chalk.white;
44
+ const action = colorFn(resp.action.toUpperCase());
45
+ const rationale = resp.rationale.length > 100
46
+ ? resp.rationale.slice(0, 100) + "..."
47
+ : resp.rationale;
48
+ let line = ` ${resp.issue_id}: ${action}`;
49
+ if (resp.severity_dispute) {
50
+ line += chalk.magenta(` (${resp.severity_dispute.original}→${resp.severity_dispute.revised})`);
51
+ }
52
+ console.log(line);
53
+ console.log(chalk.dim(` ${rationale}`));
54
+ }
55
+ }
56
+ export function printConverged(round) {
57
+ console.log(chalk.green.bold(`\nPlan approved after ${round} round${round === 1 ? "" : "s"}.`));
58
+ }
59
+ export function printMaxRounds(maxRounds) {
60
+ console.log(chalk.yellow(`\nMax rounds (${maxRounds}) reached without convergence. Review the plan manually.`));
61
+ }
62
+ export function printAborted() {
63
+ console.log(chalk.dim("\nAborted by user."));
64
+ }
65
+ //# sourceMappingURL=ui.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui.js","sourceRoot":"","sources":["../../../src/cli/ui.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAiB,MAAM,KAAK,CAAC;AAIpC,MAAM,eAAe,GAA0C;IAC7D,EAAE,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI;IAClB,EAAE,EAAE,KAAK,CAAC,MAAM;IAChB,EAAE,EAAE,KAAK,CAAC,IAAI;CACf,CAAC;AAEF,MAAM,aAAa,GAA0C;IAC3D,QAAQ,EAAE,KAAK,CAAC,KAAK;IACrB,QAAQ,EAAE,KAAK,CAAC,GAAG;IACnB,QAAQ,EAAE,KAAK,CAAC,MAAM;CACvB,CAAC;AAEF,MAAM,UAAU,WAAW;IACzB,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,8BAA8B,CAAC,CACrE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IACjD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,kBAAkB,CAAC,EAAE,QAAQ,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,GAAG,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,KAAa,EACb,QAAwB;IAExB,MAAM,YAAY,GAChB,QAAQ,CAAC,OAAO,KAAK,gBAAgB,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;IAErE,OAAO,CAAC,GAAG,CACT,KAAK,KAAK,CAAC,IAAI,CAAC,SAAS,KAAK,SAAS,CAAC,MAAM,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAC/E,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IAEzC,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC,CAAC;QAC/C,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;QACpC,UAAU,CAAC,KAAK,CAAC,CAAC;IACpB,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,KAAoB;IACtC,MAAM,OAAO,GAAG,eAAe,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC;IAC/D,OAAO,CAAC,GAAG,CACT,KAAK,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,KAAK,CAAC,KAAK,EAAE,CACvE,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,KAAa,EACb,QAAyB;IAEzB,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,SAAS,KAAK,WAAW,CAAC,EAAE,CAAC,CAAC;IAE1D,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;QACtC,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC;QAC1D,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;QAClD,MAAM,SAAS,GACb,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,GAAG;YACzB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,KAAK;YACtC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;QAErB,IAAI,IAAI,GAAG,KAAK,IAAI,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QAC3C,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC1B,IAAI,IAAI,KAAK,CAAC,OAAO,CACnB,KAAK,IAAI,CAAC,gBAAgB,CAAC,QAAQ,IAAI,IAAI,CAAC,gBAAgB,CAAC,OAAO,GAAG,CACxE,CAAC;QACJ,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,SAAS,EAAE,CAAC,CAAC,CAAC;IAChD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,KAAK,CAAC,IAAI,CACd,yBAAyB,KAAK,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CACjE,CACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,SAAiB;IAC9C,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,MAAM,CACV,iBAAiB,SAAS,0DAA0D,CACrF,CACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC,CAAC;AAC/C,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { PlanpongConfig } from "../schemas/config.js";
2
+ export declare const DEFAULT_CONFIG: PlanpongConfig;
@@ -0,0 +1,12 @@
1
+ export const DEFAULT_CONFIG = {
2
+ planner: {
3
+ provider: "claude",
4
+ },
5
+ reviewer: {
6
+ provider: "codex",
7
+ },
8
+ plans_dir: "docs/plans",
9
+ max_rounds: 10,
10
+ human_in_loop: true,
11
+ };
12
+ //# sourceMappingURL=defaults.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../../src/config/defaults.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,cAAc,GAAmB;IAC5C,OAAO,EAAE;QACP,QAAQ,EAAE,QAAQ;KACnB;IACD,QAAQ,EAAE;QACR,QAAQ,EAAE,OAAO;KAClB;IACD,SAAS,EAAE,YAAY;IACvB,UAAU,EAAE,EAAE;IACd,aAAa,EAAE,IAAI;CACpB,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { type PlanpongConfig } from "../schemas/config.js";
2
+ export interface LoadConfigOptions {
3
+ cwd: string;
4
+ /** CLI overrides — sparse, merged on top of file + defaults */
5
+ overrides?: Partial<{
6
+ plannerProvider: string;
7
+ plannerModel: string;
8
+ plannerEffort: string;
9
+ reviewerProvider: string;
10
+ reviewerModel: string;
11
+ reviewerEffort: string;
12
+ plansDir: string;
13
+ maxRounds: number;
14
+ autonomous: boolean;
15
+ }>;
16
+ }
17
+ export declare function loadConfig(options: LoadConfigOptions): PlanpongConfig;