jev-planner 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +481 -2
- package/config.schema.json +264 -0
- package/dist/bin.cjs +19 -0
- package/dist/bin.d.cts +1 -0
- package/dist/bin.d.mts +1 -0
- package/dist/bin.mjs +20 -0
- package/dist/index.cjs +12 -0
- package/dist/index.d.cts +566 -0
- package/dist/index.d.mts +566 -0
- package/dist/index.mjs +2 -0
- package/dist/jev-CIzG0Rhl.mjs +2685 -0
- package/dist/jev-aqxfEUdB.cjs +2756 -0
- package/llms.txt +206 -0
- package/package.json +77 -5
package/llms.txt
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# jev-planner
|
|
2
|
+
|
|
3
|
+
> A CLI, and the library behind it, that writes a coding plan with two or more
|
|
4
|
+
> AIs and a judge. Each agent — Codex and Claude Code by default; DeepSeek,
|
|
5
|
+
> Kimi and GLM too — drafts a plan for the same task, and Jev — TypeSafe's
|
|
6
|
+
> typed judge — scores the drafts, orders a cross-review when one would help,
|
|
7
|
+
> picks the stronger plan and the agent that writes the final version, and
|
|
8
|
+
> decides when a plan needs no merge at all. Every agent runs read-only. Node >=
|
|
9
|
+
> 20.19. MIT. Ships ESM and CommonJS with type declarations.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
npm install -g jev-planner
|
|
14
|
+
|
|
15
|
+
or, without installing, `npx jev-planner "<coding task>"`. It needs each
|
|
16
|
+
selected agent CLI installed and logged in (`codex` and `claude` by default),
|
|
17
|
+
each selected chat API's key (`DEEPSEEK_API_KEY`, `MOONSHOT_API_KEY`,
|
|
18
|
+
`ZAI_API_KEY`), and `TYPESAFE_API_KEY` for Jev. `jev-planner doctor` checks
|
|
19
|
+
them; `jev-planner --help` lists every agent id.
|
|
20
|
+
|
|
21
|
+
## Minimal working example
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
jev-planner doctor
|
|
25
|
+
jev-planner "Add rate limiting to the public API" -o PLAN.md
|
|
26
|
+
jev-planner --agents claude,deepseek,glm --model glm=glm-4.6 "Add a CSV export"
|
|
27
|
+
jev-planner --model codex=gpt-5.6-terra --effort codex=low "Add a CSV export"
|
|
28
|
+
jev-planner --agents codex:sol,codex:terra --model terra=gpt-5.6-terra "Add a CSV export"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The plan goes to stdout, or to the file given with `-o`; progress goes to
|
|
32
|
+
stderr. `--json` prints `{ plan, verdict, finalizer, selected?, debate?, timings, cost }`
|
|
33
|
+
instead. Every round's plans are also written as the run goes, to `round1/`,
|
|
34
|
+
`round2/`, …, `final/` in a new `.jev-planner/<UTC start time>/` folder in
|
|
35
|
+
the repository (git-ignored by its own `.gitignore`). `--rounds-dir <path>`
|
|
36
|
+
writes them there instead; `--no-rounds` writes none.
|
|
37
|
+
|
|
38
|
+
`--mode balanced` (the default) lets Jev skip a round the plan does not need: a
|
|
39
|
+
cross-review runs only while Jev rates the chance that one would materially
|
|
40
|
+
improve the plan at 0.65 or more, and the merge is skipped when Jev rates one
|
|
41
|
+
cross-reviewed plan 0.7 or more to stand alone. `--mode ultra` always runs the
|
|
42
|
+
first cross-review, runs a second when Jev asks, and merges unless
|
|
43
|
+
`--finalizer none` keeps the reviewed plan Jev rates stronger. `--mode fast` has
|
|
44
|
+
Jev judge each draft alone as it arrives and answers with the first it rates 0.5
|
|
45
|
+
or more, stopping the other agents; when it accepts none, the drafts are merged
|
|
46
|
+
with no cross-review. `--straggler-grace <seconds>` is how long a balanced or
|
|
47
|
+
fast round waits for the agents still working once half (rounded up) have
|
|
48
|
+
answered.
|
|
49
|
+
|
|
50
|
+
`--review-mode debate` (experimental) runs the first review as critiques and
|
|
51
|
+
replies: each agent lists numbered objections to every other plan, each author
|
|
52
|
+
accepts or rejects the ones to its own and revises it, and Jev rules on the
|
|
53
|
+
rejected ones in its usual call. `--claim-checks` implies it, and has agent CLIs
|
|
54
|
+
check the disputed claims about the repository before Jev rules.
|
|
55
|
+
|
|
56
|
+
A `jev-planner.json` in the repository (the `--cwd` folder, or the current one)
|
|
57
|
+
sets up every run there; `--config <path>` reads another, `--no-config` none.
|
|
58
|
+
Its keys follow the flags, and a flag given on the command line wins:
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"$schema": "https://jev-planner.com/config.schema.json",
|
|
63
|
+
"agents": { "codex": { "model": "gpt-5.6-sol", "effort": "high" }, "claude": {} },
|
|
64
|
+
"mode": "ultra",
|
|
65
|
+
"runsDir": "planner-runs",
|
|
66
|
+
"task": "Add rate limiting to the public API"
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The same flow from code:
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
import { PROVIDERS, Planner, TypeSafeJevJudge } from 'jev-planner'
|
|
74
|
+
|
|
75
|
+
const secrets = ['TYPESAFE_API_KEY', ...PROVIDERS.flatMap((p) => p.secretEnv)]
|
|
76
|
+
const agents = PROVIDERS.filter((p) => ['codex', 'deepseek'].includes(p.id)).map((p) =>
|
|
77
|
+
p.create({ env: process.env, omitEnv: secrets }),
|
|
78
|
+
)
|
|
79
|
+
const planner = new Planner(agents, new TypeSafeJevJudge())
|
|
80
|
+
const { plan, verdict, finalizer } = await planner.plan({
|
|
81
|
+
task: 'Add rate limiting to the public API',
|
|
82
|
+
cwd: process.cwd(),
|
|
83
|
+
timeoutMs: 600_000,
|
|
84
|
+
})
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## API
|
|
88
|
+
|
|
89
|
+
The planner comes from `packages/core`, an internal package bundled into this one, so
|
|
90
|
+
everything below is imported from `jev-planner`. This package adds Jev.
|
|
91
|
+
|
|
92
|
+
| Export | Kind | What it does |
|
|
93
|
+
| ---------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
94
|
+
| `TypeSafeJevJudge` | class | A `PlanJudge` named `Jev`, backed by `@typesafe-ai/sdk`; reads `TYPESAFE_API_KEY` |
|
|
95
|
+
| `Planner` | class | `new Planner(agents, judge).plan(options)`: two or more agents draft, cross-review, finalize |
|
|
96
|
+
| `DEFAULT_STRAGGLER_GRACE_MS` | const | 90_000: what a `balanced` or `fast` round waits for a straggler before going on without it |
|
|
97
|
+
| `PROVIDERS` | const | Every built-in `Provider`: `codex`, `claude`, `deepseek`, `kimi`, `glm` |
|
|
98
|
+
| `DEFAULT_AGENTS` | const | The ids used without `--agents`: `['codex', 'claude']` |
|
|
99
|
+
| `cliProvider` | function | Builds a `Provider` for an agent CLI run read-only in the repository |
|
|
100
|
+
| `openAICompatibleProvider` | function | Builds a `Provider` for an OpenAI-compatible chat API, sent a repo snapshot |
|
|
101
|
+
| `runDoctor` | function | `runDoctor(cwd, providers, env?)` runs each provider's checks |
|
|
102
|
+
| `ProcessError` | class | Thrown when an agent CLI exits non-zero, is killed, or times out |
|
|
103
|
+
| `TaskValidationError` | class | Thrown by `plan` before any call when the task is empty or a placeholder |
|
|
104
|
+
| `Provider` | type | `{ id, label, kind, secretEnv, effort, create(setup), doctor(cwd, env) }`, one AI |
|
|
105
|
+
| `AgentSetup` | type | `{ name?, label?, model?, effort?, omitEnv, env, fetch? }`, what `Provider.create` is given; `name` defaults to the id |
|
|
106
|
+
| `CliProviderConfig` | type | `{ id, label, command, args({ model?, effort? }), effort?, events?, sessions?, auth? }`, `cliProvider`'s input |
|
|
107
|
+
| `OpenAICompatibleConfig` | type | `{ id, label, baseUrl, apiKeyEnv, model }`, `openAICompatibleProvider`'s input |
|
|
108
|
+
| `ProcessResult` | type | `{ stdout, stderr }` of a finished agent process |
|
|
109
|
+
| `CheckResult` | type | `{ name, ok, detail }`, one `runDoctor` check |
|
|
110
|
+
| `AgentName` | type | `string`: a provider id, or a name given to one (`codex:sol` is `sol`) |
|
|
111
|
+
| `AgentRequest` | type | `{ prompt, resumePrompt?, session?, effort?, cwd, timeoutMs, onProgress?, signal? }`, what a `PlanningAgent` is given |
|
|
112
|
+
| `AgentSession` | type | `{ id? }`: one agent's conversation, carried from its draft to its later calls in a run |
|
|
113
|
+
| `PlanningAgent` | type | `{ name, label, readsRepository?, generate(request) }`, the agent interface `Planner` drives |
|
|
114
|
+
| `JudgedPlan` | type | `{ agent, label, plan }`, one plan as the judge sees it |
|
|
115
|
+
| `PlanJudge` | type | `{ name, judge({ task, plans, stage, disputes?, model? }) }`, returns a `Verdict`; `stage` is `'solo'`, `'draft'` or `'review'`; `name` labels its stage messages |
|
|
116
|
+
| `Verdict` | type | Scores and confidences, the stronger plan (an agent or `tie`), the finalizer, and `disputes?` rulings |
|
|
117
|
+
| `PlanMode` | type | `'fast'` (the first draft the judge accepts alone), `'balanced'` (the judge skips the rounds a plan does not need) or `'ultra'` (always cross-reviews) |
|
|
118
|
+
| `PlanOptions` | type | `{ task, cwd, timeoutMs, mode?, maxReviewRounds?, reviewMode?, claimChecks?, stragglerGraceMs?, judgeModel?, finalizer?, selectStronger?, allowAnyTask?, resume?, reviewEfforts?, onStage?, onAgentProgress?, onRound? }` |
|
|
119
|
+
| `PlanResult` | type | `{ plan, verdict, finalizer, selected?, drafts, debate?, timings, cost }`; `drafts` maps agent name to its last plan |
|
|
120
|
+
| `PlanCost` | type | `{ mode, reviewMode, reviewRounds, synthesized, agentCalls, judgeCalls, dropped }`, what the run spent |
|
|
121
|
+
| `PlanRound` | type | `{ round, stage, plans, verdict?, timings, selected?, artifacts?, debate? }`, one round as `onRound` receives it |
|
|
122
|
+
| `ReviewMode` | type | `'standard'` (revise against every plan) or `'debate'` (critiques, replies, the judge rules on disputes; experimental) |
|
|
123
|
+
| `Objection` | type | `{ id, critic, target, claim, why, repo }`, one numbered objection from a critique |
|
|
124
|
+
| `Reply` | type | `{ id, author, decision: 'accept' \ |
|
|
125
|
+
| `ClaimCheck` | type | `{ checker, result: 'confirm' \ |
|
|
126
|
+
| `Dispute` | type | `{ id, target, critics, objections, claim, reasons, rejections, repo, check? }`, a rejected objection for the judge |
|
|
127
|
+
| `DisputeRuling` | type | `{ id, choice: 'critic' \ |
|
|
128
|
+
| `RoundDebate` | type | `{ objections, replies?, unanswered?, disputes?, overflow?, claimChecks? }`, a debate's state after a round |
|
|
129
|
+
| `RoundTimings` | type | `{ totalMs, agents, judgeMs? }`: one round, and each agent call and judge call in it, in ms |
|
|
130
|
+
| `RunTimings` | type | `{ totalMs, rounds }`: the whole run, and each round's `RoundTimings` with its `round` and `stage` |
|
|
131
|
+
|
|
132
|
+
## Mistakes to avoid
|
|
133
|
+
|
|
134
|
+
- **Treating a run as free.** With N agents one plan is N + 1 to 3N + 1 agent
|
|
135
|
+
calls — `--mode ultra` spends 2N + 1, or 3N + 1 with a second review (2N or
|
|
136
|
+
3N with `--finalizer none` when Jev names a stronger plan), and `--mode fast`
|
|
137
|
+
N or N + 1 — and one Jev call per judged round (in fast
|
|
138
|
+
mode, per draft judged alone), each billed to the account or key it runs
|
|
139
|
+
under. Run `jev-planner doctor` first rather than a real task to check the
|
|
140
|
+
setup.
|
|
141
|
+
- **Reaching for `--mode ultra` to make a plan better.** It buys every round
|
|
142
|
+
whether or not it changes the plan. `balanced` runs the same rounds whenever Jev
|
|
143
|
+
says they would help, so `ultra` mostly buys the ones it says would not.
|
|
144
|
+
- **Using `--mode fast` for a plan that matters.** An accepted plan is one
|
|
145
|
+
agent's draft that no other agent has read, and the quickest agent is judged
|
|
146
|
+
first. An agent it stops has still billed what it used. It rejects
|
|
147
|
+
`--review-mode debate` and `--claim-checks`, since it has no review.
|
|
148
|
+
- **Expecting `--review-mode debate` to be cheaper.** Its review is a
|
|
149
|
+
critique and a reply from each agent, 2N calls where a cross-review is N,
|
|
150
|
+
plus one per agent that checks a claim with `--claim-checks`. The checks
|
|
151
|
+
need two agent CLIs; with chat APIs alone they are skipped.
|
|
152
|
+
- **Sending a template as the task.** A placeholder — `TODO`, `<coding task>`,
|
|
153
|
+
`{{task}}`, text with no letters — is rejected with `TaskValidationError`
|
|
154
|
+
before any billed call. Pass `--allow-any-task` (`allowAnyTask: true` in the
|
|
155
|
+
API) only when that text really is the task.
|
|
156
|
+
- **Giving the task two ways.** The task comes from the arguments, from `-f`,
|
|
157
|
+
from the config's `task` or `taskFile`, or from stdin — passing both
|
|
158
|
+
arguments and `-f` is an error, and so is piping a task while the config
|
|
159
|
+
has one.
|
|
160
|
+
- **Expecting `Planner` to read `jev-planner.json`.** Only the CLI reads it;
|
|
161
|
+
from code, pass `PlanOptions`. A flag beats the config, and each boolean has
|
|
162
|
+
a `--no-` form (`--no-json`, `--no-verbose`) to turn off what it turns on.
|
|
163
|
+
- **Putting a key in `jev-planner.json`.** It is meant to be committed, so a
|
|
164
|
+
key such as `apiKey` or `token` is rejected; keys stay in the environment.
|
|
165
|
+
A discovered file cannot set `cwd` either: only a file passed with `--config`
|
|
166
|
+
can.
|
|
167
|
+
- **Expecting the agents to edit code.** All run read-only; the output is a
|
|
168
|
+
plan, not a change. The CLI itself writes only the rounds folder
|
|
169
|
+
(`.jev-planner/` unless `--rounds-dir` or `--no-rounds`) and `-o`'s file.
|
|
170
|
+
- **Expecting a chat API agent to see the whole repository.** `deepseek`,
|
|
171
|
+
`kimi` and `glm` get only the tracked file list and the top-level docs and
|
|
172
|
+
manifests; the agent CLIs read the code itself. Pair an API agent with a CLI
|
|
173
|
+
agent for a task that depends on code.
|
|
174
|
+
- **Passing `--model`, `--effort`, `--review-effort` or `--finalizer` for an
|
|
175
|
+
agent not in `--agents`.** All are rejected; name the agent in `--agents`
|
|
176
|
+
too. They take the agent's name: with `--agents codex:sol,codex:terra`,
|
|
177
|
+
`--model codex=…` is rejected and `--model sol=…` is right. `--effort` and `--review-effort` are for the agent CLIs only (`codex`,
|
|
178
|
+
`claude`); the chat APIs reject them.
|
|
179
|
+
- **Listing a provider twice without names.** `--agents codex,codex` is
|
|
180
|
+
rejected; write `codex:sol,codex:terra`. Two named agents with the same
|
|
181
|
+
model and effort get a warning, as their drafts may barely differ. They
|
|
182
|
+
share one quota and call it at once, and a rate limit (429) fails the run.
|
|
183
|
+
- **Hand-building two agents of one provider without names.** Pass `name` to
|
|
184
|
+
`Provider.create`, and keep every agent's `label` unique: the peer reviews
|
|
185
|
+
and Jev tell the plans apart by label.
|
|
186
|
+
- **Hand-building agents without `omitEnv`.** `Provider.create` needs the
|
|
187
|
+
variables to strip from agent subprocesses; pass every provider's
|
|
188
|
+
`secretEnv` and `TYPESAFE_API_KEY`, as the CLI does.
|
|
189
|
+
- **Being surprised by saved sessions.** Each agent CLI keeps its draft's
|
|
190
|
+
session and continues it in its later calls, so the review and synthesis
|
|
191
|
+
start with what it already read. The sessions stay in `~/.codex/sessions`
|
|
192
|
+
and `~/.claude/projects`, and Claude's show in its `/resume` list. Pass
|
|
193
|
+
`--no-resume` (`resume: false`) to keep none.
|
|
194
|
+
- **A short `--timeout`.** It applies to each agent call, not the whole run,
|
|
195
|
+
and defaults to 600 seconds; a large repository needs most of it.
|
|
196
|
+
|
|
197
|
+
## Docs
|
|
198
|
+
|
|
199
|
+
- Documentation site: https://jev-planner.com/ — every page is also raw
|
|
200
|
+
markdown at the same URL plus `.md`
|
|
201
|
+
- Index for an agent: https://jev-planner.com/llms.txt, and
|
|
202
|
+
https://jev-planner.com/llms-full.txt for every page in one fetch
|
|
203
|
+
- README: `node_modules/jev-planner/README.md`, or
|
|
204
|
+
https://github.com/rxova/jev-planner/tree/main/packages/jev-planner#readme
|
|
205
|
+
- Package: https://www.npmjs.com/package/jev-planner
|
|
206
|
+
- Source: https://github.com/rxova/jev-planner
|
package/package.json
CHANGED
|
@@ -1,12 +1,84 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jev-planner",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Collaborative coding plans from Codex and Claude, arbitrated by TypeSafe Jev.",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"cli",
|
|
8
|
+
"planning",
|
|
9
|
+
"implementation-plan",
|
|
10
|
+
"codex",
|
|
11
|
+
"claude",
|
|
12
|
+
"claude-code",
|
|
13
|
+
"jev",
|
|
14
|
+
"typesafe",
|
|
15
|
+
"ai-agents",
|
|
16
|
+
"llm"
|
|
17
|
+
],
|
|
5
18
|
"license": "MIT",
|
|
6
19
|
"author": "Jonatan Kruszewski",
|
|
20
|
+
"sideEffects": false,
|
|
21
|
+
"bin": {
|
|
22
|
+
"jev-planner": "./dist/bin.mjs"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist",
|
|
26
|
+
"llms.txt",
|
|
27
|
+
"config.schema.json"
|
|
28
|
+
],
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"import": {
|
|
32
|
+
"types": "./dist/index.d.mts",
|
|
33
|
+
"default": "./dist/index.mjs"
|
|
34
|
+
},
|
|
35
|
+
"require": {
|
|
36
|
+
"types": "./dist/index.d.cts",
|
|
37
|
+
"default": "./dist/index.cjs"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"./package.json": "./package.json"
|
|
41
|
+
},
|
|
42
|
+
"main": "./dist/index.cjs",
|
|
43
|
+
"module": "./dist/index.mjs",
|
|
44
|
+
"types": "./dist/index.d.cts",
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=20.19.0"
|
|
47
|
+
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"@typesafe-ai/sdk": "^0.6.0"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@arethetypeswrong/cli": "^0.18.5",
|
|
53
|
+
"@repo/config": "0.0.0",
|
|
54
|
+
"@rxova/planner-core": "0.0.0",
|
|
55
|
+
"@types/node": "^26.6.1",
|
|
56
|
+
"@vitest/coverage-v8": "^5.0.1",
|
|
57
|
+
"publint": "^0.3.24",
|
|
58
|
+
"tsdown": "^0.23.0",
|
|
59
|
+
"tsx": "^4.23.13",
|
|
60
|
+
"typescript": "6.0.3",
|
|
61
|
+
"vitest": "^5.0.1"
|
|
62
|
+
},
|
|
63
|
+
"publishConfig": {
|
|
64
|
+
"access": "public"
|
|
65
|
+
},
|
|
7
66
|
"repository": {
|
|
8
67
|
"type": "git",
|
|
9
|
-
"url": "git+https://github.com/rxova/jev-
|
|
68
|
+
"url": "git+https://github.com/rxova/jev-planner.git",
|
|
69
|
+
"directory": "packages/jev-planner"
|
|
70
|
+
},
|
|
71
|
+
"bugs": {
|
|
72
|
+
"url": "https://github.com/rxova/jev-planner/issues"
|
|
10
73
|
},
|
|
11
|
-
"
|
|
12
|
-
|
|
74
|
+
"homepage": "https://jev-planner.com",
|
|
75
|
+
"scripts": {
|
|
76
|
+
"build": "tsdown",
|
|
77
|
+
"dev": "tsx src/bin.ts",
|
|
78
|
+
"typecheck": "tsc --noEmit",
|
|
79
|
+
"test": "vitest run --coverage",
|
|
80
|
+
"test:watch": "vitest",
|
|
81
|
+
"check:exports": "publint --strict && attw --pack .",
|
|
82
|
+
"pack:smoke": "node --import tsx ../tooling/src/pack-smoke/pack-smoke.ts"
|
|
83
|
+
}
|
|
84
|
+
}
|