@pmelab/gtd 21.0.0 → 21.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/.claude-plugin/plugin.json +1 -1
- package/README.md +11 -9
- package/claude/hooks/drive.ts +3 -1
- package/claude/hooks/judge.ts +18 -4
- package/claude/hooks/register.tsx +10 -7
- package/dist/gtd.bundle.mjs +102 -35
- package/package.json +1 -1
- package/schema.json +3 -3
package/README.md
CHANGED
|
@@ -414,20 +414,22 @@ noted in steps 3 and 4 below.
|
|
|
414
414
|
users only; model `haiku`, `--model <name>` overrides) and reuses its login.
|
|
415
415
|
With no `--provider`, `gtd judge run` picks jev when `TYPESAFE_API_KEY` is
|
|
416
416
|
set and non-empty and no `--model` is given, else llm — never falling back
|
|
417
|
-
across them;
|
|
418
|
-
|
|
419
|
-
judge without editing the driver (flags
|
|
420
|
-
|
|
421
|
-
stdout when they cannot answer
|
|
417
|
+
across them; the `GTD_JUDGE_PROVIDER` / `GTD_JUDGE_MODEL` environment
|
|
418
|
+
variables, a user-level `~/.config/gtd/judge.json` `{ provider, model }`, and
|
|
419
|
+
a `.gtdrc` `judge:` key choose the judge without editing the driver (flags
|
|
420
|
+
win over all three, in that order); `--model` with `--provider fixed`/`jev`
|
|
421
|
+
is refused. jev and llm exit 1 with nothing on stdout when they cannot answer
|
|
422
|
+
every question):
|
|
422
423
|
- Every red round after the first: was the failure identical, new, or
|
|
423
424
|
progress?
|
|
424
425
|
- After you review: is each of your notes an edit, a question, a nit or
|
|
425
426
|
praise?
|
|
426
427
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
428
|
+
gtd itself never calls a judge: `gtd loop`, the Claude Code mod and the
|
|
429
|
+
reference driver answer these through `gtd judge run` (auto selection: jev
|
|
430
|
+
when `TYPESAFE_API_KEY` is set, else `llm` via `claude`, default model haiku,
|
|
431
|
+
`--model <name>` overrides); if that fails it shows you the message and
|
|
432
|
+
stops. **The `llm` provider's `p` is self-reported by the model, not a
|
|
431
433
|
measured probability, so a confidently wrong verdict can clear the 0.7 floor
|
|
432
434
|
and skip a gate unattended.**
|
|
433
435
|
|
package/claude/hooks/drive.ts
CHANGED
|
@@ -119,7 +119,9 @@ async function act(
|
|
|
119
119
|
|
|
120
120
|
async function message(io: Io, b: Beat, beat: number, judged: string | undefined): Promise<Acted> {
|
|
121
121
|
const verdict = b.judge && judged !== b.state ? await io.judge() : undefined
|
|
122
|
-
|
|
122
|
+
// An unanswered judge gate never lands on its own, opening beat included:
|
|
123
|
+
// that would take the conservative default unseen.
|
|
124
|
+
if (verdict || (beat === 1 && !b.judge)) return { verdict }
|
|
123
125
|
// Any later beat is a gate this run produced and the human has not read yet.
|
|
124
126
|
const stop: Stop = { kind: "gate", text: b.content ?? "", ...where(b) }
|
|
125
127
|
if (b.judge) stop.isJudge = true
|
package/claude/hooks/judge.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
1
|
+
// A judge gate is answered by `gtd judge run`, except where its own
|
|
2
|
+
// configuration would pick the `llm` provider: that one is answered by a
|
|
3
|
+
// subagent instead of `claude -p`. A port of src/judges/providers/llm.ts
|
|
4
|
+
// (which needs Node, which a mod has not): claude/hooks/judge.test.ts pins the
|
|
5
|
+
// prompt to gtd's own, so the two cannot drift apart unnoticed.
|
|
5
6
|
|
|
6
7
|
type Question = {
|
|
7
8
|
id: string
|
|
@@ -14,6 +15,19 @@ export type Judgment = { state?: Record<string, string>; questions: Question[] }
|
|
|
14
15
|
|
|
15
16
|
type Verdict = { id: string; answer: string | number; p: number }
|
|
16
17
|
|
|
18
|
+
// The env a `gtd judge run` spawn adds to the inherited one, or `undefined` to
|
|
19
|
+
// put the gate to the in-session subagent. A provider configured only in a
|
|
20
|
+
// file is invisible here, so no variable and no key means the llm, as `gtd
|
|
21
|
+
// judge run`'s own automatic pick does.
|
|
22
|
+
export function judgeRunEnv(env: {
|
|
23
|
+
provider?: string | undefined
|
|
24
|
+
key?: string | undefined
|
|
25
|
+
}): Record<string, string> | undefined {
|
|
26
|
+
const provider = env.provider || undefined
|
|
27
|
+
if (provider === "llm" || (provider === undefined && !env.key)) return undefined
|
|
28
|
+
return env.key ? { TYPESAFE_API_KEY: env.key } : {}
|
|
29
|
+
}
|
|
30
|
+
|
|
17
31
|
export const JUDGE_SYSTEM =
|
|
18
32
|
"You are a strict, impartial judge. Answer each question from the supplied evidence alone.\n" +
|
|
19
33
|
"Reply only with the structured answer; never use tools or ask questions."
|
|
@@ -9,7 +9,7 @@ import type { Io, Turn, TurnEnd } from "./drive"
|
|
|
9
9
|
import { doors, enter } from "./doors"
|
|
10
10
|
import { subagentModel } from "./models"
|
|
11
11
|
import { personaSpec, resumable } from "./persona"
|
|
12
|
-
import { JUDGE_SYSTEM, judgePrompt, toVerdicts } from "./judge"
|
|
12
|
+
import { JUDGE_SYSTEM, judgePrompt, judgeRunEnv, toVerdicts } from "./judge"
|
|
13
13
|
import type { Judgment } from "./judge"
|
|
14
14
|
import { catchFrom, throwTo } from "./handoff"
|
|
15
15
|
import { documents } from "./schema"
|
|
@@ -153,13 +153,16 @@ function io($: $): Io {
|
|
|
153
153
|
},
|
|
154
154
|
judge: () =>
|
|
155
155
|
docs($).judge(async (doc, j) => {
|
|
156
|
-
const
|
|
157
|
-
|
|
156
|
+
const env = judgeRunEnv({
|
|
157
|
+
provider: await $.env.get("GTD_JUDGE_PROVIDER"),
|
|
158
|
+
key: (await $.env.get("TYPESAFE_API_KEY")) || (await $.env.get("TYPESAFE_AI_KEY")),
|
|
159
|
+
})
|
|
160
|
+
if (env === undefined) return judgeInSession($, j)
|
|
158
161
|
try {
|
|
159
|
-
const r = await $.process.run(["gtd", "judge", "run"
|
|
162
|
+
const r = await $.process.run(["gtd", "judge", "run"], {
|
|
160
163
|
cwd: root,
|
|
161
164
|
stdin: doc,
|
|
162
|
-
env
|
|
165
|
+
env,
|
|
163
166
|
timeoutMs: TEN_MINUTES,
|
|
164
167
|
})
|
|
165
168
|
return r.exitCode === 0 && r.stdout.trim() ? r.stdout : undefined
|
|
@@ -511,8 +514,8 @@ async function writer($: $, prompt: string) {
|
|
|
511
514
|
return delegate($, SHIPPER, prompt, model, "Your final answer, exactly as you would print it.")
|
|
512
515
|
}
|
|
513
516
|
|
|
514
|
-
//
|
|
515
|
-
//
|
|
517
|
+
// Where `gtd judge run` would pick its llm, a judge gate is put to a small
|
|
518
|
+
// model as that provider does, but as a subagent of this session. Any doubt leaves the
|
|
516
519
|
// gate to the person, which routes the workflow its cautious way.
|
|
517
520
|
async function judgeInSession($: $, j: Judgment) {
|
|
518
521
|
try {
|
package/dist/gtd.bundle.mjs
CHANGED
|
@@ -49676,9 +49676,9 @@ const UiSchema = Struct({
|
|
|
49676
49676
|
format: optional$2(String$.annotations({ description: "Shell command run after every UI write, before it resolves ($GTD_FILE is the written file's absolute path). A non-zero exit or missing binary never reverts the write or refuses it — it's reported to the client as a notice naming the command and its exit code. Absent means no command runs at all." }))
|
|
49677
49677
|
}).annotations({ description: "Settings for `gtd ui`: where it listens, and optional TLS." });
|
|
49678
49678
|
const JudgeSchema = Struct({
|
|
49679
|
-
provider: optional$2(Literal("fixed", "jev", "llm").annotations({ description: "Judge provider `gtd judge run` uses when no --provider flag and no
|
|
49680
|
-
model: optional$2(String$.annotations({ description: "Model for provider llm, used when no --model flag and no
|
|
49681
|
-
}).annotations({ description: "Which judge `gtd judge run` uses, when no flag
|
|
49679
|
+
provider: optional$2(Literal("fixed", "jev", "llm").annotations({ description: "Judge provider `gtd judge run` uses when no --provider flag, no GTD_JUDGE_PROVIDER and no user-level judge.json says. Absent means auto: jev when TYPESAFE_API_KEY is set, otherwise llm." })),
|
|
49680
|
+
model: optional$2(String$.annotations({ description: "Model for provider llm, used when no --model flag, no GTD_JUDGE_MODEL and no user-level judge.json says. Pairing it with another provider is an error." }))
|
|
49681
|
+
}).annotations({ description: "Which judge `gtd judge run` uses, when no flag, GTD_JUDGE_* variable or user-level judge.json says." });
|
|
49682
49682
|
const ConfigSchema = Struct({
|
|
49683
49683
|
vars: optional$2(Unknown.annotations({ jsonSchema: varsJsonSchema })),
|
|
49684
49684
|
env: optional$2(Unknown.annotations({ jsonSchema: envJsonSchema })),
|
|
@@ -57748,23 +57748,73 @@ const envProvider = (env) => {
|
|
|
57748
57748
|
return value;
|
|
57749
57749
|
};
|
|
57750
57750
|
const checkPairing = (resolved) => resolved.model !== void 0 && resolved.provider !== void 0 && resolved.provider !== "llm" ? fail(`a model only applies to provider llm, not ${resolved.provider}`) : resolved;
|
|
57751
|
+
const userConfigPath = (env) => {
|
|
57752
|
+
const xdg = env["XDG_CONFIG_HOME"];
|
|
57753
|
+
if (xdg) return `${xdg}/gtd/judge.json`;
|
|
57754
|
+
const home = env["HOME"];
|
|
57755
|
+
return home ? `${home}/.config/gtd/judge.json` : void 0;
|
|
57756
|
+
};
|
|
57757
|
+
const readText = async (path) => {
|
|
57758
|
+
try {
|
|
57759
|
+
return await readFile(path, "utf8");
|
|
57760
|
+
} catch (e) {
|
|
57761
|
+
if (e.code === "ENOENT") return void 0;
|
|
57762
|
+
return fail(`cannot read ${path}: ${e instanceof Error ? e.message : String(e)}`);
|
|
57763
|
+
}
|
|
57764
|
+
};
|
|
57765
|
+
const parseObject = (path, text) => {
|
|
57766
|
+
let json;
|
|
57767
|
+
try {
|
|
57768
|
+
json = JSON.parse(text);
|
|
57769
|
+
} catch {
|
|
57770
|
+
return fail(`${path} is not valid JSON`);
|
|
57771
|
+
}
|
|
57772
|
+
return typeof json === "object" && json !== null && !Array.isArray(json) ? json : fail(`${path} must be a JSON object`);
|
|
57773
|
+
};
|
|
57774
|
+
const decodeUserConfig = (path, text) => {
|
|
57775
|
+
const { provider, model, ...rest } = parseObject(path, text);
|
|
57776
|
+
const [extra] = Object.keys(rest);
|
|
57777
|
+
if (extra !== void 0) return fail(`${path}: unknown key "${extra}"`);
|
|
57778
|
+
if (provider !== void 0 && !PROVIDERS.includes(provider)) return fail(`${path}: "provider" must be one of ${PROVIDERS.join(", ")}`);
|
|
57779
|
+
if (model !== void 0 && typeof model !== "string") return fail(`${path}: "model" must be a string`);
|
|
57780
|
+
return {
|
|
57781
|
+
provider,
|
|
57782
|
+
model
|
|
57783
|
+
};
|
|
57784
|
+
};
|
|
57785
|
+
const readUserConfig = async (env) => {
|
|
57786
|
+
const path = userConfigPath(env);
|
|
57787
|
+
const text = path === void 0 ? void 0 : await readText(path);
|
|
57788
|
+
return path === void 0 || text === void 0 ? void 0 : decodeUserConfig(path, text);
|
|
57789
|
+
};
|
|
57751
57790
|
/**
|
|
57752
57791
|
* Per field, the first one set wins: flag, then `GTD_JUDGE_PROVIDER` /
|
|
57753
|
-
* `GTD_JUDGE_MODEL` (empty counts as unset), then `.gtdrc`
|
|
57754
|
-
* provider/model pairing is checked on the resolved pair,
|
|
57755
|
-
* supplied each half.
|
|
57792
|
+
* `GTD_JUDGE_MODEL` (empty counts as unset), then the user file, then `.gtdrc`
|
|
57793
|
+
* `judge:`. The provider/model pairing is checked on the resolved pair,
|
|
57794
|
+
* whichever layer supplied each half.
|
|
57756
57795
|
*/
|
|
57757
|
-
const selectJudge = ({ provider, model, configured, env }) => {
|
|
57758
|
-
const
|
|
57759
|
-
|
|
57760
|
-
|
|
57761
|
-
|
|
57762
|
-
|
|
57796
|
+
const selectJudge = ({ provider, model, configured, env }, user) => {
|
|
57797
|
+
const layers = [
|
|
57798
|
+
{
|
|
57799
|
+
provider,
|
|
57800
|
+
model
|
|
57801
|
+
},
|
|
57802
|
+
{
|
|
57803
|
+
provider: envProvider(env),
|
|
57804
|
+
model: env["GTD_JUDGE_MODEL"] || void 0
|
|
57805
|
+
},
|
|
57806
|
+
user ?? {},
|
|
57807
|
+
configured ?? {}
|
|
57808
|
+
];
|
|
57809
|
+
return checkPairing({
|
|
57810
|
+
provider: layers.find((l) => l.provider !== void 0)?.provider,
|
|
57811
|
+
model: layers.find((l) => l.model !== void 0)?.model
|
|
57812
|
+
});
|
|
57763
57813
|
};
|
|
57764
57814
|
/** The only place auto selection lives; it never falls back across providers. */
|
|
57765
|
-
const answererFor = (opts) => {
|
|
57815
|
+
const answererFor = async (opts) => {
|
|
57766
57816
|
const { answers, env, cwd } = opts;
|
|
57767
|
-
const { provider, model } = selectJudge(opts);
|
|
57817
|
+
const { provider, model } = selectJudge(opts, await readUserConfig(env));
|
|
57768
57818
|
if (provider === "fixed") return fixed({
|
|
57769
57819
|
answersPath: answers,
|
|
57770
57820
|
env
|
|
@@ -57785,7 +57835,7 @@ const runJudge = async (opts) => {
|
|
|
57785
57835
|
}
|
|
57786
57836
|
const { questions, state } = doc ?? {};
|
|
57787
57837
|
if (!Array.isArray(questions)) return fail("stdin has no \"questions\" array");
|
|
57788
|
-
const verdicts = await answererFor(opts)(questions, typeof state === "object" && state !== null ? state : {});
|
|
57838
|
+
const verdicts = await (await answererFor(opts))(questions, typeof state === "object" && state !== null ? state : {});
|
|
57789
57839
|
return JSON.stringify(verdicts) + "\n";
|
|
57790
57840
|
};
|
|
57791
57841
|
//#endregion
|
|
@@ -75762,7 +75812,8 @@ const Beat = Struct({
|
|
|
75762
75812
|
model: optional$2(String$),
|
|
75763
75813
|
system: optional$2(String$),
|
|
75764
75814
|
validate: optional$2(String$),
|
|
75765
|
-
label: optional$2(String$)
|
|
75815
|
+
label: optional$2(String$),
|
|
75816
|
+
judge: optional$2(String$)
|
|
75766
75817
|
});
|
|
75767
75818
|
const Land = Struct({
|
|
75768
75819
|
schema: Number$,
|
|
@@ -75958,10 +76009,11 @@ const gitRoot = gen(function* () {
|
|
|
75958
76009
|
if (exit.code !== 0) return yield* fail$7(/* @__PURE__ */ new Error("not inside a git repository"));
|
|
75959
76010
|
return exit.stdout.trim();
|
|
75960
76011
|
});
|
|
75961
|
-
const gtd = (ctx, args) => flatMap$4(ctx.host.spawn({
|
|
76012
|
+
const gtd = (ctx, args, stdin) => flatMap$4(ctx.host.spawn({
|
|
75962
76013
|
command: ctx.gtd[0],
|
|
75963
76014
|
args: [...ctx.gtd.slice(1), ...args],
|
|
75964
76015
|
cwd: ctx.root,
|
|
76016
|
+
...stdin === void 0 ? {} : { stdin },
|
|
75965
76017
|
output: "capture"
|
|
75966
76018
|
}), (exit) => exit.code === 0 ? succeed$3(exit.stdout) : fail$7(/* @__PURE__ */ new Error(`\`gtd ${args.join(" ")}\` failed (exit ${exit.code})\n${exit.stderr.trimEnd()}`)));
|
|
75967
76019
|
const readBeat = (ctx) => flatMap$4(gtd(ctx, ["next", "--json"]), (stdout) => fromEither(decodeBeat(stdout)));
|
|
@@ -76044,29 +76096,41 @@ const runScript = (ctx, content) => as(ctx.host.spawn({
|
|
|
76044
76096
|
output: { log: ctx.log }
|
|
76045
76097
|
}), LAND);
|
|
76046
76098
|
const stop = (ctx, sgr, headline, prose) => as(zipRight$1(ctx.host.appendLog(ctx.log, prose), rest(ctx, sgr, headline)), "stop");
|
|
76047
|
-
const
|
|
76048
|
-
|
|
76099
|
+
const judgeGate = (ctx, doc) => gtd(ctx, ["judge", "run"], doc.judge).pipe(flatMap$4((verdict) => gtd(ctx, [
|
|
76100
|
+
"judge",
|
|
76101
|
+
"answer",
|
|
76102
|
+
"--json"
|
|
76103
|
+
], verdict)), tap(() => ctx.host.say(` ${paint(ctx.host, "2", "⚖ judged")}\n`)), catchAll((error) => as(ctx.host.appendLog(ctx.log, `${error.message}\n`), void 0)));
|
|
76104
|
+
const messageBeat = (ctx, beat, doc, judged) => gen(function* () {
|
|
76105
|
+
const isJudge = doc.judge !== void 0 && doc.judge !== "";
|
|
76106
|
+
const landing = isJudge && judged !== doc.state ? yield* judgeGate(ctx, doc) : void 0;
|
|
76107
|
+
if (landing !== void 0) return {
|
|
76108
|
+
...LAND,
|
|
76109
|
+
landing
|
|
76110
|
+
};
|
|
76111
|
+
if (beat === 1 && !isJudge) return LAND;
|
|
76049
76112
|
const label = doc.label === void 0 ? "" : ` (${doc.label})`;
|
|
76050
|
-
return stop(ctx, "33", `your turn — ${doc.state}${label}`, doc.content);
|
|
76051
|
-
};
|
|
76052
|
-
const kindBeat = (ctx, beat, doc) => {
|
|
76113
|
+
return yield* stop(ctx, "33", `your turn — ${doc.state}${label}`, doc.content);
|
|
76114
|
+
});
|
|
76115
|
+
const kindBeat = (ctx, beat, doc, judged) => {
|
|
76053
76116
|
switch (doc.kind) {
|
|
76054
76117
|
case "stalled": return zipRight$1(ctx.host.appendLog(ctx.log, doc.content), fail$7(new Error(doc.content.trimEnd())));
|
|
76055
|
-
case "message": return messageBeat(ctx, beat, doc);
|
|
76118
|
+
case "message": return messageBeat(ctx, beat, doc, judged);
|
|
76056
76119
|
case "capture": return succeed$3(LAND);
|
|
76057
76120
|
case "script": return runScript(ctx, doc.content);
|
|
76058
76121
|
case "prompt": return promptBeat(ctx, doc);
|
|
76059
76122
|
default: return fail$7(/* @__PURE__ */ new Error(`unknown beat kind "${doc.kind}"`));
|
|
76060
76123
|
}
|
|
76061
76124
|
};
|
|
76062
|
-
const runBeat = (ctx, beat, doc) => beat > 1 && doc.idle ? flatMap$4(gtd(ctx, ["next"]), (message) => stop(ctx, "32", `done — ${doc.state}`, message)) : kindBeat(ctx, beat, doc);
|
|
76125
|
+
const runBeat = (ctx, beat, doc, judged) => beat > 1 && doc.idle ? flatMap$4(gtd(ctx, ["next"]), (message) => stop(ctx, "32", `done — ${doc.state}`, message)) : kindBeat(ctx, beat, doc, judged);
|
|
76063
76126
|
const costFlags = (outcome) => outcome.cost > 0 ? [`--cost=${outcome.cost.toFixed(6)}`, ...outcome.model === void 0 ? [] : [`--model=${outcome.model}`]] : [];
|
|
76064
76127
|
const land = (ctx, outcome) => gen(function* () {
|
|
76065
|
-
const
|
|
76128
|
+
const landed = outcome.landing ?? (yield* gtd(ctx, [
|
|
76066
76129
|
"land",
|
|
76067
76130
|
"--json",
|
|
76068
76131
|
...costFlags(outcome)
|
|
76069
|
-
]))
|
|
76132
|
+
]));
|
|
76133
|
+
const doc = yield* fromEither(decodeLand(landed));
|
|
76070
76134
|
const exit = yield* ctx.host.spawn({
|
|
76071
76135
|
command: "sh",
|
|
76072
76136
|
args: [],
|
|
@@ -76106,11 +76170,13 @@ const runLoop = (options) => gen(function* () {
|
|
|
76106
76170
|
log: resolve(root, doc.log)
|
|
76107
76171
|
};
|
|
76108
76172
|
yield* host.resetLog(ctx.log);
|
|
76173
|
+
let judged;
|
|
76109
76174
|
for (let beat = 1;; beat++) {
|
|
76110
76175
|
if (beat > 1) doc = yield* readBeat(ctx);
|
|
76111
76176
|
yield* header(ctx, beat, doc);
|
|
76112
|
-
const outcome = yield* runBeat(ctx, beat, doc);
|
|
76177
|
+
const outcome = yield* runBeat(ctx, beat, doc, judged);
|
|
76113
76178
|
if (outcome === "stop" || (yield* land(ctx, outcome))) return;
|
|
76179
|
+
judged = outcome.landing === void 0 ? void 0 : doc.state;
|
|
76114
76180
|
}
|
|
76115
76181
|
});
|
|
76116
76182
|
//#endregion
|
|
@@ -76897,8 +76963,8 @@ const FLAGS = [
|
|
|
76897
76963
|
valueHint: "<name>",
|
|
76898
76964
|
help: [
|
|
76899
76965
|
"(gtd judge run only) the answerer: fixed | jev | llm;",
|
|
76900
|
-
"omitted: GTD_JUDGE_PROVIDER, then .
|
|
76901
|
-
"when TYPESAFE_API_KEY is set, else llm"
|
|
76966
|
+
"omitted: GTD_JUDGE_PROVIDER, then judge.json, then .gtdrc",
|
|
76967
|
+
"judge:, then jev when TYPESAFE_API_KEY is set, else llm"
|
|
76902
76968
|
]
|
|
76903
76969
|
},
|
|
76904
76970
|
{
|
|
@@ -76936,7 +77002,8 @@ const FLAGS = [
|
|
|
76936
77002
|
help: [
|
|
76937
77003
|
"(gtd land, with --cost) tag that cost's model",
|
|
76938
77004
|
"(gtd judge run, llm answerer) the claude model; omitted:",
|
|
76939
|
-
"GTD_JUDGE_MODEL, then .gtdrc judge:, then
|
|
77005
|
+
"GTD_JUDGE_MODEL, then judge.json, then .gtdrc judge:, then",
|
|
77006
|
+
"haiku"
|
|
76940
77007
|
]
|
|
76941
77008
|
},
|
|
76942
77009
|
{
|
|
@@ -77336,11 +77403,11 @@ const COMMAND_ROWS = [
|
|
|
77336
77403
|
"does not cover are left out. --provider jev asks TypeSafe",
|
|
77337
77404
|
"(TYPESAFE_API_KEY). --provider llm asks the `claude` CLI",
|
|
77338
77405
|
"on PATH (Claude Code only), model haiku unless --model.",
|
|
77339
|
-
"No --provider: GTD_JUDGE_PROVIDER, then
|
|
77340
|
-
"provider, else jev when
|
|
77341
|
-
"model is given, else llm;
|
|
77342
|
-
"
|
|
77343
|
-
"
|
|
77406
|
+
"No --provider: GTD_JUDGE_PROVIDER, then ~/.config/gtd/",
|
|
77407
|
+
"judge.json, then .gtdrc judge: provider, else jev when",
|
|
77408
|
+
"TYPESAFE_API_KEY is set and no model is given, else llm;",
|
|
77409
|
+
"--model likewise falls back to GTD_JUDGE_MODEL, then the",
|
|
77410
|
+
"file's and judge:'s model. Needs no repository. jev and",
|
|
77344
77411
|
"llm exit 1 when they cannot answer every question, with",
|
|
77345
77412
|
"nothing on stdout"
|
|
77346
77413
|
]
|
package/package.json
CHANGED
package/schema.json
CHANGED
|
@@ -36,15 +36,15 @@
|
|
|
36
36
|
"jev",
|
|
37
37
|
"llm"
|
|
38
38
|
],
|
|
39
|
-
"description": "Judge provider `gtd judge run` uses when no --provider flag and no
|
|
39
|
+
"description": "Judge provider `gtd judge run` uses when no --provider flag, no GTD_JUDGE_PROVIDER and no user-level judge.json says. Absent means auto: jev when TYPESAFE_API_KEY is set, otherwise llm."
|
|
40
40
|
},
|
|
41
41
|
"model": {
|
|
42
42
|
"type": "string",
|
|
43
|
-
"description": "Model for provider llm, used when no --model flag and no
|
|
43
|
+
"description": "Model for provider llm, used when no --model flag, no GTD_JUDGE_MODEL and no user-level judge.json says. Pairing it with another provider is an error."
|
|
44
44
|
}
|
|
45
45
|
},
|
|
46
46
|
"additionalProperties": false,
|
|
47
|
-
"description": "Which judge `gtd judge run` uses, when no flag
|
|
47
|
+
"description": "Which judge `gtd judge run` uses, when no flag, GTD_JUDGE_* variable or user-level judge.json says."
|
|
48
48
|
},
|
|
49
49
|
"modes": {
|
|
50
50
|
"type": "object",
|