planpong 0.5.6 → 0.6.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 +47 -10
- package/dist/bin/planpong.js +13 -1
- package/dist/bin/planpong.js.map +1 -1
- package/dist/src/cli/commands/init.d.ts +53 -0
- package/dist/src/cli/commands/init.js +221 -0
- package/dist/src/cli/commands/init.js.map +1 -0
- package/dist/src/cli/ui.js +11 -19
- package/dist/src/cli/ui.js.map +1 -1
- package/dist/src/config/loader.d.ts +5 -0
- package/dist/src/config/loader.js +21 -1
- package/dist/src/config/loader.js.map +1 -1
- package/dist/src/config/mutate.d.ts +26 -0
- package/dist/src/config/mutate.js +45 -32
- package/dist/src/config/mutate.js.map +1 -1
- package/dist/src/core/convergence.js +1 -1
- package/dist/src/core/convergence.js.map +1 -1
- package/dist/src/core/operations.d.ts +44 -1
- package/dist/src/core/operations.js +110 -37
- package/dist/src/core/operations.js.map +1 -1
- package/dist/src/core/presentation.d.ts +39 -0
- package/dist/src/core/presentation.js +132 -0
- package/dist/src/core/presentation.js.map +1 -0
- package/dist/src/core/round-state.d.ts +15 -0
- package/dist/src/core/round-state.js +49 -0
- package/dist/src/core/round-state.js.map +1 -0
- package/dist/src/core/session.d.ts +1 -0
- package/dist/src/core/session.js +60 -1
- package/dist/src/core/session.js.map +1 -1
- package/dist/src/mcp/server.js +6 -6
- package/dist/src/mcp/server.js.map +1 -1
- package/dist/src/mcp/tools/get-feedback.d.ts +1 -2
- package/dist/src/mcp/tools/get-feedback.js +154 -56
- package/dist/src/mcp/tools/get-feedback.js.map +1 -1
- package/dist/src/mcp/tools/record-revision.d.ts +0 -6
- package/dist/src/mcp/tools/record-revision.js +170 -95
- package/dist/src/mcp/tools/record-revision.js.map +1 -1
- package/dist/src/mcp/tools/revise.d.ts +1 -7
- package/dist/src/mcp/tools/revise.js +126 -90
- package/dist/src/mcp/tools/revise.js.map +1 -1
- package/dist/src/mcp/tools/status.js +18 -1
- package/dist/src/mcp/tools/status.js.map +1 -1
- package/dist/src/providers/claude.d.ts +22 -1
- package/dist/src/providers/claude.js +10 -10
- package/dist/src/providers/claude.js.map +1 -1
- package/dist/src/providers/codex.d.ts +12 -1
- package/dist/src/providers/codex.js +6 -3
- package/dist/src/providers/codex.js.map +1 -1
- package/dist/src/providers/gemini.d.ts +58 -0
- package/dist/src/providers/gemini.js +169 -0
- package/dist/src/providers/gemini.js.map +1 -0
- package/dist/src/providers/registry.js +7 -1
- package/dist/src/providers/registry.js.map +1 -1
- package/dist/src/providers/shared.d.ts +16 -0
- package/dist/src/providers/shared.js +22 -0
- package/dist/src/providers/shared.js.map +1 -0
- package/dist/src/providers/types.d.ts +1 -1
- package/dist/src/schemas/metrics.d.ts +14 -14
- package/dist/src/schemas/metrics.js +13 -2
- package/dist/src/schemas/metrics.js.map +1 -1
- package/dist/src/schemas/session.d.ts +2 -2
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -18,14 +18,18 @@ You need at least **one AI CLI** installed and authenticated:
|
|
|
18
18
|
|
|
19
19
|
- **Claude Code** — `npm install -g @anthropic-ai/claude-code` (Anthropic API key or Max subscription)
|
|
20
20
|
- **Codex CLI** — `npm install -g @openai/codex` (OpenAI API key)
|
|
21
|
+
- **Gemini CLI** — `npm install -g @google/gemini-cli` (Google account auth — run `gemini` once to authenticate)
|
|
21
22
|
|
|
22
|
-
If
|
|
23
|
+
If multiple are installed, planpong uses one for planning and a different one for reviewing (configurable). If only one is available, it auto-fallbacks to using that CLI for both roles.
|
|
24
|
+
|
|
25
|
+
> **Note on gemini as reviewer:** the gemini CLI does not expose a stable session-resume mechanism, so reviewer rounds run without persistent context. Expect noticeably slower per-round wall time than claude or codex when gemini is the reviewer. The first time you load a config that selects gemini as reviewer, planpong prints a one-line warning to stderr.
|
|
23
26
|
|
|
24
27
|
Verify your CLI works:
|
|
25
28
|
|
|
26
29
|
```sh
|
|
27
30
|
claude --version # or
|
|
28
|
-
codex --version
|
|
31
|
+
codex --version # or
|
|
32
|
+
gemini --version
|
|
29
33
|
```
|
|
30
34
|
|
|
31
35
|
Planpong shells out to these CLIs — no API keys are configured in planpong itself.
|
|
@@ -36,6 +40,14 @@ Planpong shells out to these CLIs — no API keys are configured in planpong its
|
|
|
36
40
|
npm install -g planpong
|
|
37
41
|
```
|
|
38
42
|
|
|
43
|
+
Then run the interactive setup wizard:
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
planpong init
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The wizard auto-detects which AI CLIs you have installed, lets you pick a planner + reviewer, and writes a working `planpong.yaml` for the current project. You can re-run it any time to tweak settings — only changed keys are written.
|
|
50
|
+
|
|
39
51
|
## Setup (Claude Code MCP)
|
|
40
52
|
|
|
41
53
|
Add planpong as an MCP server so Claude Code can use it as a native tool:
|
|
@@ -69,8 +81,11 @@ Review my plan at docs/plans/my-feature.md using planpong
|
|
|
69
81
|
Or use the slash commands (auto-installed with the MCP server):
|
|
70
82
|
|
|
71
83
|
```
|
|
72
|
-
/planpong:review docs/plans/my-feature.md
|
|
73
|
-
/planpong:review_interactive docs/plans/my-feature.md
|
|
84
|
+
/planpong:review docs/plans/my-feature.md # autonomous — runs to completion
|
|
85
|
+
/planpong:review_interactive docs/plans/my-feature.md # pauses between rounds for your input
|
|
86
|
+
/planpong:status <session_id> # current state and round history
|
|
87
|
+
/planpong:sessions # list all review sessions in this project
|
|
88
|
+
/planpong:report <session_id> # detailed phase-specific report (direction confidence, risk register, round history)
|
|
74
89
|
```
|
|
75
90
|
|
|
76
91
|
### Via CLI
|
|
@@ -81,11 +96,11 @@ planpong review docs/plans/my-feature.md
|
|
|
81
96
|
|
|
82
97
|
## Configuration
|
|
83
98
|
|
|
84
|
-
Optional.
|
|
99
|
+
Optional. Run `planpong init` to generate this interactively, or create `planpong.yaml` in your project root by hand:
|
|
85
100
|
|
|
86
101
|
```yaml
|
|
87
102
|
planner:
|
|
88
|
-
provider: claude # claude or
|
|
103
|
+
provider: claude # claude, codex, or gemini
|
|
89
104
|
model: claude-opus-4-6 # provider-specific model name
|
|
90
105
|
effort: high # reasoning effort level
|
|
91
106
|
reviewer:
|
|
@@ -95,28 +110,40 @@ reviewer:
|
|
|
95
110
|
max_rounds: 10
|
|
96
111
|
plans_dir: docs/plans
|
|
97
112
|
revision_mode: full # full or edits
|
|
98
|
-
planner_mode:
|
|
113
|
+
planner_mode: inline # inline or external (see below)
|
|
99
114
|
```
|
|
100
115
|
|
|
101
|
-
All fields are optional. Defaults: claude (planner) + codex (reviewer), 10 rounds, `docs/plans/` directory
|
|
116
|
+
All fields are optional. Defaults: claude (planner) + codex (reviewer), 10 rounds, `docs/plans/` directory, `planner_mode: inline`, `revision_mode: full`, `human_in_loop: true`.
|
|
117
|
+
|
|
118
|
+
### Planner mode: inline vs external
|
|
119
|
+
|
|
120
|
+
`planner_mode` is the most consequential operational choice. It decides who actually rewrites the plan after each round of feedback:
|
|
121
|
+
|
|
122
|
+
- **`inline` (default)** — when you're driving planpong from Claude Code, *you* are the planner. Planpong returns the reviewer's issues; Claude reads the plan, edits it directly, and reports its accept/reject/defer decisions back via `planpong_record_revision`. No second model is invoked, so revisions are fast and use the conversational context Claude already has.
|
|
123
|
+
- **`external`** — planpong shells out to the configured planner provider (e.g. another `claude -p` or `codex exec` invocation) to produce the revision. Use this when running planpong outside Claude Code (CLI flow), or when you want a different model to plan than the one orchestrating.
|
|
124
|
+
|
|
125
|
+
Inline is the right default for the Claude-Code-as-orchestrator workflow; external is the right default for `planpong review` from a plain shell.
|
|
102
126
|
|
|
103
127
|
### Viewing and changing config
|
|
104
128
|
|
|
105
129
|
```sh
|
|
106
130
|
planpong config # show resolved config with source annotations
|
|
107
131
|
planpong config path # print path to active config file
|
|
132
|
+
planpong config keys # list all keys with valid values, types, and defaults
|
|
133
|
+
planpong config get <key> # print a single resolved value
|
|
108
134
|
planpong config set <key> <value> # set a config value
|
|
109
135
|
```
|
|
110
136
|
|
|
111
137
|
Examples:
|
|
112
138
|
|
|
113
139
|
```sh
|
|
114
|
-
planpong config set reviewer.
|
|
140
|
+
planpong config set reviewer.provider gemini
|
|
141
|
+
planpong config set reviewer.model gemini-2.5-pro
|
|
115
142
|
planpong config set max_rounds 5
|
|
116
143
|
planpong config set planner_mode inline
|
|
117
144
|
```
|
|
118
145
|
|
|
119
|
-
Valid keys: `planner.provider`, `planner.model`, `planner.effort`, `reviewer.provider`, `reviewer.model`, `reviewer.effort`, `plans_dir`, `max_rounds`, `human_in_loop`, `revision_mode`, `planner_mode`.
|
|
146
|
+
Valid keys: `planner.provider`, `planner.model`, `planner.effort`, `reviewer.provider`, `reviewer.model`, `reviewer.effort`, `plans_dir`, `max_rounds`, `human_in_loop`, `revision_mode`, `planner_mode`. Run `planpong config keys` for the canonical list with descriptions.
|
|
120
147
|
|
|
121
148
|
### Config via MCP
|
|
122
149
|
|
|
@@ -125,6 +152,16 @@ Two MCP tools are available for programmatic config access:
|
|
|
125
152
|
- **`planpong_get_config`** — returns resolved config, file path, version, and per-key source provenance
|
|
126
153
|
- **`planpong_set_config`** — dry-run by default (`confirm: false`); pass `confirm: true` to write
|
|
127
154
|
|
|
155
|
+
### MCP API notes
|
|
156
|
+
|
|
157
|
+
Planpong's MCP tools are designed to be safe under retries, duplicated calls, and orchestrator restarts:
|
|
158
|
+
|
|
159
|
+
- **`planpong_revise` and `planpong_record_revision` require `expected_round`.** Pass the round number returned by the most recent `planpong_get_feedback`. Stale calls (round mismatched lower) and out-of-order calls (mismatched higher) return precise errors instead of double-charging the planner.
|
|
160
|
+
- **Tool calls are replay-safe.** Calling `planpong_get_feedback` twice before the round's revision returns the existing feedback with `idempotent_replay: true` instead of re-invoking the reviewer. The same applies to `planpong_revise` and `planpong_record_revision` when the round's response artifact already exists.
|
|
161
|
+
- **Per-session lock.** Mutating MCP tools acquire an exclusive lock at `.planpong/sessions/<id>/lock` so two overlapping clients cannot both advance the same session.
|
|
162
|
+
|
|
163
|
+
Most users driving planpong through Claude Code never see these primitives — the slash commands and the orchestrator's instructions handle them. They matter if you're building an external MCP client.
|
|
164
|
+
|
|
128
165
|
## What it produces
|
|
129
166
|
|
|
130
167
|
Planpong updates your plan file in-place and adds a status line tracking the review:
|
package/dist/bin/planpong.js
CHANGED
|
@@ -6,6 +6,7 @@ import { Command } from "commander";
|
|
|
6
6
|
import { registerPlanCommand } from "../src/cli/commands/plan.js";
|
|
7
7
|
import { registerReviewCommand } from "../src/cli/commands/review.js";
|
|
8
8
|
import { registerConfigCommand } from "../src/cli/commands/config.js";
|
|
9
|
+
import { registerInitCommand } from "../src/cli/commands/init.js";
|
|
9
10
|
// Read version from the installed package.json so `planpong --version`
|
|
10
11
|
// always reflects the actual installed version. Hardcoding it here
|
|
11
12
|
// drifts every time we cut a release.
|
|
@@ -43,9 +44,20 @@ const program = new Command();
|
|
|
43
44
|
program
|
|
44
45
|
.name("planpong")
|
|
45
46
|
.description("Multi-model plan review CLI — orchestrates AI agents for adversarial plan refinement")
|
|
46
|
-
.version(readPackageVersion())
|
|
47
|
+
.version(readPackageVersion())
|
|
48
|
+
.addHelpText("after", `
|
|
49
|
+
Quick reference:
|
|
50
|
+
planpong init Interactive first-run setup wizard
|
|
51
|
+
planpong config Show current config values and sources
|
|
52
|
+
planpong config keys List all settings with valid values and defaults
|
|
53
|
+
planpong config get <key> Get a single setting
|
|
54
|
+
planpong config set <key> <value> Change a setting
|
|
55
|
+
|
|
56
|
+
planpong review <plan-file> Start adversarial review of a plan
|
|
57
|
+
planpong plan <requirements> Generate a plan and review it`);
|
|
47
58
|
registerPlanCommand(program);
|
|
48
59
|
registerReviewCommand(program);
|
|
49
60
|
registerConfigCommand(program);
|
|
61
|
+
registerInitCommand(program);
|
|
50
62
|
program.parse();
|
|
51
63
|
//# sourceMappingURL=planpong.js.map
|
package/dist/bin/planpong.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"planpong.js","sourceRoot":"","sources":["../../bin/planpong.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"planpong.js","sourceRoot":"","sources":["../../bin/planpong.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAElE,uEAAuE;AACvE,mEAAmE;AACnE,sCAAsC;AACtC,EAAE;AACF,wEAAwE;AACxE,mEAAmE;AACnE,sEAAsE;AACtE,8BAA8B;AAC9B,SAAS,kBAAkB;IACzB,IAAI,CAAC;QACH,IAAI,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QACnD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3B,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;YAC7C,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAGtD,CAAC;gBACF,IAAI,GAAG,CAAC,IAAI,KAAK,UAAU,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;oBAC/D,OAAO,GAAG,CAAC,OAAO,CAAC;gBACrB,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,8DAA8D;YAChE,CAAC;YACD,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;YAC7B,IAAI,MAAM,KAAK,IAAI;gBAAE,MAAM;YAC3B,IAAI,GAAG,MAAM,CAAC;QAChB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,2BAA2B;IAC7B,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,UAAU,CAAC;KAChB,WAAW,CACV,sFAAsF,CACvF;KACA,OAAO,CAAC,kBAAkB,EAAE,CAAC;KAC7B,WAAW,CACV,OAAO,EACP;;;;;;;;;6DASyD,CAC1D,CAAC;AAEJ,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAC7B,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAC/B,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAC/B,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAE7B,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
import { type BatchPick } from "../../config/mutate.js";
|
|
3
|
+
export interface WizardAnswers {
|
|
4
|
+
plannerProvider: string;
|
|
5
|
+
plannerModel: string;
|
|
6
|
+
reviewerProvider: string;
|
|
7
|
+
reviewerModel: string;
|
|
8
|
+
maxRounds: number;
|
|
9
|
+
plansDir: string;
|
|
10
|
+
plannerMode: "inline" | "external";
|
|
11
|
+
}
|
|
12
|
+
export interface DiskSnapshot {
|
|
13
|
+
planner?: {
|
|
14
|
+
provider?: string;
|
|
15
|
+
model?: string;
|
|
16
|
+
};
|
|
17
|
+
reviewer?: {
|
|
18
|
+
provider?: string;
|
|
19
|
+
model?: string;
|
|
20
|
+
};
|
|
21
|
+
max_rounds?: number;
|
|
22
|
+
plans_dir?: string;
|
|
23
|
+
planner_mode?: "inline" | "external";
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Read planpong.yaml directly into a partial snapshot. Unlike loadConfig(),
|
|
27
|
+
* this does NOT merge defaults — fields the user never wrote remain
|
|
28
|
+
* undefined so the wizard can omit them from the batch write.
|
|
29
|
+
*/
|
|
30
|
+
export declare function readDiskSnapshot(cwd: string): DiskSnapshot;
|
|
31
|
+
/**
|
|
32
|
+
* Pure formatter for the post-write summary. The auth reminder appears
|
|
33
|
+
* whenever gemini is picked for any role; it is intentionally a static
|
|
34
|
+
* message rather than a probe of auth state.
|
|
35
|
+
*/
|
|
36
|
+
export declare function formatPostWriteSummary(answers: WizardAnswers): string;
|
|
37
|
+
/**
|
|
38
|
+
* Convert the wizard's answer object plus the on-disk-file snapshot into
|
|
39
|
+
* the batch picks list. Omits keys whose answer matches the on-disk value
|
|
40
|
+
* so the wizard never writes a default into an existing yaml the user
|
|
41
|
+
* didn't touch. Output order is stable to keep diff output predictable.
|
|
42
|
+
*/
|
|
43
|
+
export declare function answersToPicks(answers: WizardAnswers, disk: DiskSnapshot): BatchPick[];
|
|
44
|
+
/**
|
|
45
|
+
* Detect whether stdin is a real TTY. Node sets `isTTY` to `true` for a TTY
|
|
46
|
+
* and leaves it `undefined` (NOT `false`) for pipes/redirects, so a strict
|
|
47
|
+
* `=== false` check would silently let the wizard fall through to inquirer
|
|
48
|
+
* and hang on the first prompt.
|
|
49
|
+
*/
|
|
50
|
+
export declare function isInteractiveTty(stdin: {
|
|
51
|
+
isTTY?: boolean;
|
|
52
|
+
}): boolean;
|
|
53
|
+
export declare function registerInitCommand(program: Command): void;
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { parse as parseYaml } from "yaml";
|
|
4
|
+
import { select, input, confirm } from "@inquirer/prompts";
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
import { setConfigValuesBatch, } from "../../config/mutate.js";
|
|
7
|
+
import { getAllProviders, getInstallHint, } from "../../providers/registry.js";
|
|
8
|
+
const CONFIG_FILENAMES = [
|
|
9
|
+
"planpong.yaml",
|
|
10
|
+
"planpong.yml",
|
|
11
|
+
".planpong.yaml",
|
|
12
|
+
".planpong.yml",
|
|
13
|
+
];
|
|
14
|
+
const GEMINI_REVIEWER_INLINE_WARNING = "warning: gemini reviewer rounds run without persistent session resumption.\n" +
|
|
15
|
+
" expect noticeably slower per-round wall time than claude/codex.\n" +
|
|
16
|
+
" tracked: see Future work in docs/plans/gemini-and-init-wizard.md";
|
|
17
|
+
/**
|
|
18
|
+
* Read planpong.yaml directly into a partial snapshot. Unlike loadConfig(),
|
|
19
|
+
* this does NOT merge defaults — fields the user never wrote remain
|
|
20
|
+
* undefined so the wizard can omit them from the batch write.
|
|
21
|
+
*/
|
|
22
|
+
export function readDiskSnapshot(cwd) {
|
|
23
|
+
for (const filename of CONFIG_FILENAMES) {
|
|
24
|
+
const candidate = join(cwd, filename);
|
|
25
|
+
if (existsSync(candidate)) {
|
|
26
|
+
const raw = readFileSync(candidate, "utf-8");
|
|
27
|
+
return parseYaml(raw) ?? {};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return {};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Pure formatter for the post-write summary. The auth reminder appears
|
|
34
|
+
* whenever gemini is picked for any role; it is intentionally a static
|
|
35
|
+
* message rather than a probe of auth state.
|
|
36
|
+
*/
|
|
37
|
+
export function formatPostWriteSummary(answers) {
|
|
38
|
+
const lines = [];
|
|
39
|
+
lines.push("");
|
|
40
|
+
lines.push("Run 'planpong review <plan-file>' to start a review, or", " 'planpong plan <requirements>' to generate a new plan.");
|
|
41
|
+
if (answers.plannerProvider === "gemini" ||
|
|
42
|
+
answers.reviewerProvider === "gemini") {
|
|
43
|
+
lines.push("");
|
|
44
|
+
lines.push("Note: gemini requires Google account auth. Run `gemini` once", " before invoking planpong if you haven't already.");
|
|
45
|
+
}
|
|
46
|
+
return lines.join("\n");
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Convert the wizard's answer object plus the on-disk-file snapshot into
|
|
50
|
+
* the batch picks list. Omits keys whose answer matches the on-disk value
|
|
51
|
+
* so the wizard never writes a default into an existing yaml the user
|
|
52
|
+
* didn't touch. Output order is stable to keep diff output predictable.
|
|
53
|
+
*/
|
|
54
|
+
export function answersToPicks(answers, disk) {
|
|
55
|
+
const picks = [];
|
|
56
|
+
const add = (key, answer, diskValue) => {
|
|
57
|
+
if (answer === diskValue)
|
|
58
|
+
return;
|
|
59
|
+
picks.push({ key, rawValue: String(answer) });
|
|
60
|
+
};
|
|
61
|
+
add("planner.provider", answers.plannerProvider, disk.planner?.provider);
|
|
62
|
+
add("planner.model", answers.plannerModel, disk.planner?.model);
|
|
63
|
+
add("reviewer.provider", answers.reviewerProvider, disk.reviewer?.provider);
|
|
64
|
+
add("reviewer.model", answers.reviewerModel, disk.reviewer?.model);
|
|
65
|
+
add("max_rounds", answers.maxRounds, disk.max_rounds);
|
|
66
|
+
add("plans_dir", answers.plansDir, disk.plans_dir);
|
|
67
|
+
add("planner_mode", answers.plannerMode, disk.planner_mode);
|
|
68
|
+
return picks;
|
|
69
|
+
}
|
|
70
|
+
async function probeProviders() {
|
|
71
|
+
const all = getAllProviders();
|
|
72
|
+
return Promise.all(all.map(async (p) => ({ provider: p, available: await p.isAvailable() })));
|
|
73
|
+
}
|
|
74
|
+
function printDetectionTable(statuses) {
|
|
75
|
+
console.log(chalk.bold("\nDetected CLIs:"));
|
|
76
|
+
for (const s of statuses) {
|
|
77
|
+
const mark = s.available ? chalk.green("✓") : chalk.dim("✗");
|
|
78
|
+
const name = s.provider.name.padEnd(8);
|
|
79
|
+
if (s.available) {
|
|
80
|
+
console.log(` ${mark} ${name}available`);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
console.log(` ${mark} ${name}${chalk.dim("not installed — " + getInstallHint(s.provider.name))}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
console.log();
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Detect whether stdin is a real TTY. Node sets `isTTY` to `true` for a TTY
|
|
90
|
+
* and leaves it `undefined` (NOT `false`) for pipes/redirects, so a strict
|
|
91
|
+
* `=== false` check would silently let the wizard fall through to inquirer
|
|
92
|
+
* and hang on the first prompt.
|
|
93
|
+
*/
|
|
94
|
+
export function isInteractiveTty(stdin) {
|
|
95
|
+
return stdin.isTTY === true;
|
|
96
|
+
}
|
|
97
|
+
async function runWizard(cwd) {
|
|
98
|
+
if (!isInteractiveTty(process.stdin)) {
|
|
99
|
+
process.stderr.write("planpong init must run interactively. Use 'planpong config set <key> <value>' for scripted setup.\n");
|
|
100
|
+
process.exitCode = 1;
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
console.log(chalk.bold("\nplanpong init") + chalk.dim(" — first-run setup\n"));
|
|
104
|
+
const statuses = await probeProviders();
|
|
105
|
+
printDetectionTable(statuses);
|
|
106
|
+
const installed = statuses.filter((s) => s.available);
|
|
107
|
+
if (installed.length === 0) {
|
|
108
|
+
console.error(chalk.red("No supported AI CLIs are installed."), "Install at least one of:");
|
|
109
|
+
for (const s of statuses) {
|
|
110
|
+
console.error(` - ${getInstallHint(s.provider.name)}`);
|
|
111
|
+
}
|
|
112
|
+
process.exitCode = 1;
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const disk = readDiskSnapshot(cwd);
|
|
116
|
+
const installedChoices = installed.map((s) => ({
|
|
117
|
+
name: s.provider.name,
|
|
118
|
+
value: s.provider.name,
|
|
119
|
+
}));
|
|
120
|
+
const plannerProvider = await select({
|
|
121
|
+
message: "Planner provider:",
|
|
122
|
+
choices: installedChoices,
|
|
123
|
+
default: disk.planner?.provider ?? installedChoices[0].value,
|
|
124
|
+
});
|
|
125
|
+
const plannerModelChoices = (statuses.find((s) => s.provider.name === plannerProvider)?.provider.getModels() ?? []).map((m) => ({ name: m, value: m }));
|
|
126
|
+
const plannerModel = await select({
|
|
127
|
+
message: "Planner model:",
|
|
128
|
+
choices: plannerModelChoices,
|
|
129
|
+
default: disk.planner?.model ?? plannerModelChoices[0]?.value,
|
|
130
|
+
});
|
|
131
|
+
const reviewerProvider = await select({
|
|
132
|
+
message: "Reviewer provider:",
|
|
133
|
+
choices: installedChoices,
|
|
134
|
+
default: disk.reviewer?.provider ?? installedChoices[0].value,
|
|
135
|
+
});
|
|
136
|
+
if (reviewerProvider === plannerProvider) {
|
|
137
|
+
console.log(chalk.yellow(" note: planner and reviewer use the same provider. Adversarial signal is reduced when both roles share a model lineage."));
|
|
138
|
+
}
|
|
139
|
+
const reviewerModelChoices = (statuses.find((s) => s.provider.name === reviewerProvider)?.provider.getModels() ?? []).map((m) => ({ name: m, value: m }));
|
|
140
|
+
const reviewerModel = await select({
|
|
141
|
+
message: "Reviewer model:",
|
|
142
|
+
choices: reviewerModelChoices,
|
|
143
|
+
default: disk.reviewer?.model ?? reviewerModelChoices[0]?.value,
|
|
144
|
+
});
|
|
145
|
+
const maxRoundsRaw = await input({
|
|
146
|
+
message: "Maximum review rounds:",
|
|
147
|
+
default: String(disk.max_rounds ?? 10),
|
|
148
|
+
validate: (v) => {
|
|
149
|
+
const n = Number(v);
|
|
150
|
+
return Number.isInteger(n) && n >= 1 && n <= 50
|
|
151
|
+
? true
|
|
152
|
+
: "Enter an integer between 1 and 50.";
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
const plansDir = await input({
|
|
156
|
+
message: "Plans directory:",
|
|
157
|
+
default: disk.plans_dir ?? "docs/plans",
|
|
158
|
+
});
|
|
159
|
+
const plannerMode = (await select({
|
|
160
|
+
message: "Planner mode:",
|
|
161
|
+
choices: [
|
|
162
|
+
{ name: "inline (you act as the planner)", value: "inline" },
|
|
163
|
+
{ name: "external (route revisions through the planner provider)", value: "external" },
|
|
164
|
+
],
|
|
165
|
+
default: disk.planner_mode ?? "inline",
|
|
166
|
+
}));
|
|
167
|
+
if (reviewerProvider === "gemini") {
|
|
168
|
+
console.log("\n" + chalk.yellow(GEMINI_REVIEWER_INLINE_WARNING) + "\n");
|
|
169
|
+
}
|
|
170
|
+
const answers = {
|
|
171
|
+
plannerProvider,
|
|
172
|
+
plannerModel,
|
|
173
|
+
reviewerProvider,
|
|
174
|
+
reviewerModel,
|
|
175
|
+
maxRounds: Number(maxRoundsRaw),
|
|
176
|
+
plansDir,
|
|
177
|
+
plannerMode,
|
|
178
|
+
};
|
|
179
|
+
const picks = answersToPicks(answers, disk);
|
|
180
|
+
if (picks.length === 0) {
|
|
181
|
+
console.log(chalk.dim("No changes — your planpong.yaml already matches these answers."));
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
console.log(chalk.bold("\nProposed changes:"));
|
|
185
|
+
for (const p of picks) {
|
|
186
|
+
console.log(` ${p.key.padEnd(20)} → ${p.rawValue}`);
|
|
187
|
+
}
|
|
188
|
+
const proceed = await confirm({
|
|
189
|
+
message: existsSync(join(cwd, "planpong.yaml"))
|
|
190
|
+
? "Update planpong.yaml with these changes?"
|
|
191
|
+
: "Write planpong.yaml in this directory?",
|
|
192
|
+
default: true,
|
|
193
|
+
});
|
|
194
|
+
if (!proceed) {
|
|
195
|
+
console.log(chalk.dim("Cancelled, no changes written."));
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const result = setConfigValuesBatch(cwd, picks);
|
|
199
|
+
console.log(chalk.green(result.created ? "Created" : "Updated"), result.configPath);
|
|
200
|
+
console.log(formatPostWriteSummary(answers));
|
|
201
|
+
}
|
|
202
|
+
export function registerInitCommand(program) {
|
|
203
|
+
program
|
|
204
|
+
.command("init")
|
|
205
|
+
.description("Interactive setup wizard — produces a working planpong.yaml")
|
|
206
|
+
.action(async () => {
|
|
207
|
+
try {
|
|
208
|
+
await runWizard(process.cwd());
|
|
209
|
+
}
|
|
210
|
+
catch (err) {
|
|
211
|
+
const e = err;
|
|
212
|
+
if (e?.name === "ExitPromptError") {
|
|
213
|
+
console.log(chalk.dim("\nAborted, no changes written."));
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
console.error(chalk.red("Error:"), e?.message ?? String(err));
|
|
217
|
+
process.exitCode = 1;
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../../../src/cli/commands/init.ts"],"names":[],"mappings":"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"}
|
package/dist/src/cli/ui.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import ora from "ora";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
P3: chalk.blue,
|
|
7
|
-
};
|
|
3
|
+
import { severityFromFeedback } from "../core/operations.js";
|
|
4
|
+
import { formatFeedbackDisplay } from "../core/presentation.js";
|
|
5
|
+
import { getReviewPhase } from "../prompts/reviewer.js";
|
|
8
6
|
const ACTION_COLORS = {
|
|
9
7
|
accepted: chalk.green,
|
|
10
8
|
rejected: chalk.red,
|
|
@@ -22,20 +20,14 @@ export function createSpinner(text) {
|
|
|
22
20
|
export function printFeedbackSummary(round, feedback) {
|
|
23
21
|
const verdictColor = feedback.verdict === "needs_revision" ? chalk.yellow : chalk.green;
|
|
24
22
|
console.log(`\n${chalk.bold(`Round ${round} Review`)} — ${verdictColor(feedback.verdict)}`);
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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}`));
|
|
23
|
+
const display = formatFeedbackDisplay({
|
|
24
|
+
round,
|
|
25
|
+
phase: getReviewPhase(round),
|
|
26
|
+
verdict: feedback.verdict,
|
|
27
|
+
severity: severityFromFeedback(feedback),
|
|
28
|
+
feedback,
|
|
29
|
+
});
|
|
30
|
+
console.log(display.markdown);
|
|
39
31
|
}
|
|
40
32
|
export function printRevisionSummary(round, revision) {
|
|
41
33
|
console.log(`\n${chalk.bold(`Round ${round} Revision`)}`);
|
package/dist/src/cli/ui.js.map
CHANGED
|
@@ -1 +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;
|
|
1
|
+
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../../../src/cli/ui.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { type PlanpongConfig } from "../schemas/config.js";
|
|
2
|
+
/**
|
|
3
|
+
* Reset the gemini-reviewer-warning gate. Test-only — the gate is a process-
|
|
4
|
+
* lifetime singleton in production so the warning fires exactly once.
|
|
5
|
+
*/
|
|
6
|
+
export declare function __resetGeminiReviewerWarningForTesting(): void;
|
|
2
7
|
/**
|
|
3
8
|
* Search upward from `cwd` for a config file path.
|
|
4
9
|
* Returns the absolute path or null if no file is found.
|
|
@@ -3,6 +3,24 @@ import { join } from "node:path";
|
|
|
3
3
|
import { parse as parseYaml } from "yaml";
|
|
4
4
|
import { PlanpongConfigSchema, } from "../schemas/config.js";
|
|
5
5
|
import { DEFAULT_CONFIG } from "./defaults.js";
|
|
6
|
+
let geminiReviewerWarningFired = false;
|
|
7
|
+
/**
|
|
8
|
+
* Reset the gemini-reviewer-warning gate. Test-only — the gate is a process-
|
|
9
|
+
* lifetime singleton in production so the warning fires exactly once.
|
|
10
|
+
*/
|
|
11
|
+
export function __resetGeminiReviewerWarningForTesting() {
|
|
12
|
+
geminiReviewerWarningFired = false;
|
|
13
|
+
}
|
|
14
|
+
function maybeEmitGeminiReviewerWarning(config) {
|
|
15
|
+
if (geminiReviewerWarningFired)
|
|
16
|
+
return;
|
|
17
|
+
if (config.reviewer.provider !== "gemini")
|
|
18
|
+
return;
|
|
19
|
+
geminiReviewerWarningFired = true;
|
|
20
|
+
process.stderr.write("warning: gemini reviewer rounds run without persistent session resumption.\n" +
|
|
21
|
+
" expect noticeably slower per-round wall time than claude/codex.\n" +
|
|
22
|
+
" tracked: see Future work in docs/plans/gemini-and-init-wizard.md\n");
|
|
23
|
+
}
|
|
6
24
|
const CONFIG_FILENAMES = [
|
|
7
25
|
"planpong.yaml",
|
|
8
26
|
"planpong.yml",
|
|
@@ -81,6 +99,8 @@ export function loadConfig(options) {
|
|
|
81
99
|
fileConfig.planner_mode ??
|
|
82
100
|
DEFAULT_CONFIG.planner_mode,
|
|
83
101
|
};
|
|
84
|
-
|
|
102
|
+
const parsed = PlanpongConfigSchema.parse(merged);
|
|
103
|
+
maybeEmitGeminiReviewerWarning(parsed);
|
|
104
|
+
return parsed;
|
|
85
105
|
}
|
|
86
106
|
//# sourceMappingURL=loader.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/config/loader.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/config/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -13,10 +13,36 @@ export interface SetConfigResult {
|
|
|
13
13
|
after: unknown;
|
|
14
14
|
created: boolean;
|
|
15
15
|
}
|
|
16
|
+
export interface BatchPick {
|
|
17
|
+
key: string;
|
|
18
|
+
rawValue: string;
|
|
19
|
+
}
|
|
20
|
+
export interface BatchPickResult {
|
|
21
|
+
key: string;
|
|
22
|
+
before: unknown;
|
|
23
|
+
after: unknown;
|
|
24
|
+
}
|
|
25
|
+
export interface SetConfigValuesBatchResult {
|
|
26
|
+
configPath: string;
|
|
27
|
+
created: boolean;
|
|
28
|
+
results: BatchPickResult[];
|
|
29
|
+
}
|
|
16
30
|
export declare function isValidKey(key: string): key is ValidKey;
|
|
17
31
|
export declare function getValidKeys(): readonly string[];
|
|
18
32
|
export declare function getKeyMetadata(): readonly KeyMeta[];
|
|
19
33
|
export declare function getKeyMeta(key: string): KeyMeta | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* Apply many key/value picks to the project's planpong.yaml in one atomic
|
|
36
|
+
* write. Validates every pick (key allowlist, type coercion, merged-config
|
|
37
|
+
* schema) before any disk mutation, so a failing pick aborts the entire
|
|
38
|
+
* batch with the on-disk file byte-identical to its prior state.
|
|
39
|
+
*
|
|
40
|
+
* The single-key `setConfigValue` is a thin wrapper over this; the wizard
|
|
41
|
+
* flow calls this directly with all picks accumulated in memory.
|
|
42
|
+
*/
|
|
43
|
+
export declare function setConfigValuesBatch(cwd: string, picks: BatchPick[], opts?: {
|
|
44
|
+
dryRun?: boolean;
|
|
45
|
+
}): SetConfigValuesBatchResult;
|
|
20
46
|
export declare function setConfigValue(cwd: string, key: string, rawValue: string, opts?: {
|
|
21
47
|
dryRun?: boolean;
|
|
22
48
|
}): SetConfigResult;
|