@jokerized/decksmith 0.9.4 → 0.9.5
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/dist/cli.js +81 -28
- package/dist/index.js +76 -26
- package/dist/mcp.js +76 -26
- package/dist/types/plan/codex.d.ts +15 -3
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -13788,9 +13788,9 @@ function number(flag, value) {
|
|
|
13788
13788
|
|
|
13789
13789
|
// src/plan/arc.ts
|
|
13790
13790
|
var ARC_ROLES = ["intro", "background", "limitations", "conclusion"];
|
|
13791
|
-
function requiredRoles(
|
|
13792
|
-
if (
|
|
13793
|
-
if (
|
|
13791
|
+
function requiredRoles(beatCount2) {
|
|
13792
|
+
if (beatCount2 >= 8) return ARC_ROLES;
|
|
13793
|
+
if (beatCount2 >= 5) return ["limitations", "conclusion"];
|
|
13794
13794
|
return [];
|
|
13795
13795
|
}
|
|
13796
13796
|
function paperArcRequested(prefs) {
|
|
@@ -14043,7 +14043,8 @@ DRAWING ARCHETYPES \u2014 reach here first
|
|
|
14043
14043
|
repeat. Leave it off only when the figure's whole layout is the
|
|
14044
14044
|
argument.
|
|
14045
14045
|
|
|
14046
|
-
grid A cols\xD7rows lattice
|
|
14046
|
+
grid A cols\xD7rows lattice (cols 2\u201324, rows 1\u201316) with one to four
|
|
14047
|
+
regions lit in turn \u2014 never a fifth. The
|
|
14047
14048
|
tell: A FIELD WITH NO ORDER \u2014 patches, windows, tokens, tiles,
|
|
14048
14049
|
receptive fields, masks, strides, a neighbourhood, a block-sparse
|
|
14049
14050
|
pattern. Regions are cell coordinates, so the lattice IS the
|
|
@@ -14935,6 +14936,10 @@ function stripNulls(node) {
|
|
|
14935
14936
|
var PLANNER_INVISIBLE = /* @__PURE__ */ new Set(["tilt"]);
|
|
14936
14937
|
function plannerInvisible(prefs) {
|
|
14937
14938
|
const hidden = new Set(PLANNER_INVISIBLE);
|
|
14939
|
+
if (prefs.images && !prefs.images.enabled) {
|
|
14940
|
+
hidden.add("illustration");
|
|
14941
|
+
hidden.add("backdrop");
|
|
14942
|
+
}
|
|
14938
14943
|
if (!paperArcRequested(prefs)) hidden.add("role");
|
|
14939
14944
|
if (!bespokeFor(prefs, designFor(prefs))) hidden.add("bespoke");
|
|
14940
14945
|
return hidden;
|
|
@@ -14966,7 +14971,7 @@ function schemaFor(prefs) {
|
|
|
14966
14971
|
plannerInvisible(prefs)
|
|
14967
14972
|
);
|
|
14968
14973
|
}
|
|
14969
|
-
var SCHEMA = schemaFor({
|
|
14974
|
+
var SCHEMA = schemaFor(prefsSchema.parse({}));
|
|
14970
14975
|
async function codexPlanner(source, opts = {}) {
|
|
14971
14976
|
const prefs = opts.prefs ?? prefsSchema.parse({});
|
|
14972
14977
|
const dir = await mkdtemp(join6(tmpdir(), "decksmith-plan-"));
|
|
@@ -14986,14 +14991,29 @@ async function codexPlanner(source, opts = {}) {
|
|
|
14986
14991
|
return readPlan(outPath, source, prefs);
|
|
14987
14992
|
};
|
|
14988
14993
|
const prompt = buildPrompt(source, prefs);
|
|
14989
|
-
|
|
14990
|
-
|
|
14991
|
-
|
|
14994
|
+
let first;
|
|
14995
|
+
let firstJson;
|
|
14996
|
+
let broken;
|
|
14997
|
+
try {
|
|
14998
|
+
first = await ask(prompt);
|
|
14999
|
+
firstJson = first;
|
|
15000
|
+
broken = varietyFindings(first, prefs.images, prefs.design);
|
|
15001
|
+
} catch (err) {
|
|
15002
|
+
if (!(err instanceof PlanRejected)) throw err;
|
|
15003
|
+
firstJson = err.plan;
|
|
15004
|
+
broken = err.problems;
|
|
15005
|
+
}
|
|
15006
|
+
if (first && broken.length === 0) return first;
|
|
14992
15007
|
opts.onRepair?.(broken);
|
|
14993
|
-
const second = await ask(repairPrompt(prompt,
|
|
15008
|
+
const second = await ask(repairPrompt(prompt, firstJson, broken, prefs.images.enabled)).catch(
|
|
15009
|
+
(err) => {
|
|
15010
|
+
throw err instanceof PlanRejected ? new Error(`Codex's plan is still refused after one repair. ${err.message}`) : err;
|
|
15011
|
+
}
|
|
15012
|
+
);
|
|
15013
|
+
const firstBeats = beatCount(firstJson);
|
|
14994
15014
|
const still = [
|
|
14995
|
-
...second.beats.length <
|
|
14996
|
-
`the repair returned ${second.beats.length} beats for a plan of ${
|
|
15015
|
+
...second.beats.length < firstBeats ? [
|
|
15016
|
+
`the repair returned ${second.beats.length} beats for a plan of ${firstBeats}; a repair changes shapes and may not drop beats.`
|
|
14997
15017
|
] : [],
|
|
14998
15018
|
...varietyFindings(second, prefs.images, prefs.design)
|
|
14999
15019
|
];
|
|
@@ -15008,21 +15028,32 @@ ${still.map((m) => ` ${m}`).join("\n")}`
|
|
|
15008
15028
|
await rm2(dir, { recursive: true, force: true });
|
|
15009
15029
|
}
|
|
15010
15030
|
}
|
|
15011
|
-
function repairPrompt(prompt, plan, broken) {
|
|
15031
|
+
function repairPrompt(prompt, plan, broken, images) {
|
|
15032
|
+
const moves = images ? "change archetypes, add stage beats with illustration briefs, give diagram beats a backdrop brief, redraw a panel as a hero-number or a kinetic claim where its point is a number or a claim," : "change archetypes, redraw a panel as a hero-number or a kinetic claim where its point is a number or a claim, cite only ids the source lists,";
|
|
15012
15033
|
return `${prompt}
|
|
15013
15034
|
|
|
15014
|
-
YOUR PREVIOUS STORYBOARD, BELOW,
|
|
15035
|
+
YOUR PREVIOUS STORYBOARD, BELOW, IS REFUSED FOR:
|
|
15015
15036
|
${broken.map((m) => ` - ${m}`).join("\n")}
|
|
15016
15037
|
|
|
15017
|
-
Return the whole storyboard again with these fixed. Keep every beat
|
|
15018
|
-
|
|
15019
|
-
|
|
15020
|
-
|
|
15021
|
-
reorder neighbours only as far as the fix needs. Never
|
|
15022
|
-
drop or merge beats: a repair with fewer beats than the plan below is refused.
|
|
15038
|
+
Return the whole storyboard again with these fixed. Keep every beat that is not
|
|
15039
|
+
named above as it is; ${moves} or reorder neighbours only as far as the fix
|
|
15040
|
+
needs. Never drop or merge beats: a repair with fewer beats than the plan below
|
|
15041
|
+
is refused.
|
|
15023
15042
|
|
|
15024
15043
|
${JSON.stringify(plan)}`;
|
|
15025
15044
|
}
|
|
15045
|
+
function beatCount(plan) {
|
|
15046
|
+
const beats = plan?.beats;
|
|
15047
|
+
return Array.isArray(beats) ? beats.length : 0;
|
|
15048
|
+
}
|
|
15049
|
+
var PlanRejected = class extends Error {
|
|
15050
|
+
constructor(message2, problems, plan) {
|
|
15051
|
+
super(message2);
|
|
15052
|
+
this.problems = problems;
|
|
15053
|
+
this.plan = plan;
|
|
15054
|
+
this.name = "PlanRejected";
|
|
15055
|
+
}
|
|
15056
|
+
};
|
|
15026
15057
|
async function readPlan(outPath, source, prefs) {
|
|
15027
15058
|
const raw2 = await readFile7(outPath, "utf8").catch(() => "");
|
|
15028
15059
|
if (raw2.trim() === "") {
|
|
@@ -15037,22 +15068,41 @@ async function readPlan(outPath, source, prefs) {
|
|
|
15037
15068
|
${raw2.slice(0, 200)}`
|
|
15038
15069
|
);
|
|
15039
15070
|
}
|
|
15040
|
-
const
|
|
15071
|
+
const plan = stripNulls(parsed);
|
|
15072
|
+
const result = storyboardSchema.safeParse(plan);
|
|
15041
15073
|
if (!result.success) {
|
|
15042
|
-
const issues = result.error.issues.map((i) =>
|
|
15043
|
-
throw new
|
|
15044
|
-
|
|
15074
|
+
const issues = result.error.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`);
|
|
15075
|
+
throw new PlanRejected(
|
|
15076
|
+
`Codex returned a storyboard that does not validate:
|
|
15077
|
+
${issues.map((i) => ` ${i}`).join("\n")}`,
|
|
15078
|
+
issues,
|
|
15079
|
+
plan
|
|
15080
|
+
);
|
|
15045
15081
|
}
|
|
15046
15082
|
if (!prefs.images.enabled) {
|
|
15047
15083
|
const pending = pendingIllustrations(result.data);
|
|
15048
15084
|
if (pending.length) {
|
|
15049
15085
|
const beats = [...new Set(pending.map((p) => p.beatId))].join(", ");
|
|
15050
|
-
|
|
15051
|
-
|
|
15086
|
+
const msg = `Codex asked for ${pending.length} illustration${pending.length === 1 ? "" : "s"} (${beats}) with images off. Pass --images to let the plan request pictures, or re-run without it.`;
|
|
15087
|
+
throw new PlanRejected(
|
|
15088
|
+
msg,
|
|
15089
|
+
[
|
|
15090
|
+
`${beats} asked for a picture with images off: remove every illustration and backdrop brief`
|
|
15091
|
+
],
|
|
15092
|
+
plan
|
|
15052
15093
|
);
|
|
15053
15094
|
}
|
|
15054
15095
|
}
|
|
15055
|
-
|
|
15096
|
+
try {
|
|
15097
|
+
assertRefsResolve(result.data, source, { pending: prefs.images.enabled ? "allow" : "refuse" });
|
|
15098
|
+
} catch (err) {
|
|
15099
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
15100
|
+
throw new PlanRejected(
|
|
15101
|
+
msg,
|
|
15102
|
+
msg.split("\n").map((l) => l.trim()).filter(Boolean),
|
|
15103
|
+
plan
|
|
15104
|
+
);
|
|
15105
|
+
}
|
|
15056
15106
|
return result.data;
|
|
15057
15107
|
}
|
|
15058
15108
|
function buildPrompt(source, prefs) {
|
|
@@ -27501,7 +27551,10 @@ program.command("ingest").description("Parse a document or a web page into sourc
|
|
|
27501
27551
|
imageFlags(
|
|
27502
27552
|
lookFlags(
|
|
27503
27553
|
planFlags(
|
|
27504
|
-
lengthFlags(program.command("plan")).description("Ask Codex for a storyboard. Read and edit the result before building.").argument("<source>", "source.json from ingest").requiredOption("-o, --out <file>", "where to write storyboard.json").option("--bespoke", "let the planner mark the beats a generated scene should draw")
|
|
27554
|
+
lengthFlags(program.command("plan")).description("Ask Codex for a storyboard. Read and edit the result before building.").argument("<source>", "source.json from ingest").requiredOption("-o, --out <file>", "where to write storyboard.json").option("--bespoke", "let the planner mark the beats a generated scene should draw").option(
|
|
27555
|
+
"--no-bespoke",
|
|
27556
|
+
"v2: plan for a build run with --no-bespoke (no bespoke hints in the prompt or schema)"
|
|
27557
|
+
)
|
|
27505
27558
|
)
|
|
27506
27559
|
)
|
|
27507
27560
|
).action(async (src, o) => {
|
|
@@ -27513,7 +27566,7 @@ imageFlags(
|
|
|
27513
27566
|
const planned = await codexPlanner(source, {
|
|
27514
27567
|
prefs,
|
|
27515
27568
|
onRepair: (broken) => {
|
|
27516
|
-
step("plan: the first plan
|
|
27569
|
+
step("plan: the first plan was refused, asking Codex to repair it \u2014");
|
|
27517
27570
|
for (const m of broken) step(`plan: ${m}`);
|
|
27518
27571
|
}
|
|
27519
27572
|
});
|
package/dist/index.js
CHANGED
|
@@ -16720,9 +16720,9 @@ ${issues}`);
|
|
|
16720
16720
|
|
|
16721
16721
|
// src/plan/arc.ts
|
|
16722
16722
|
var ARC_ROLES = ["intro", "background", "limitations", "conclusion"];
|
|
16723
|
-
function requiredRoles(
|
|
16724
|
-
if (
|
|
16725
|
-
if (
|
|
16723
|
+
function requiredRoles(beatCount2) {
|
|
16724
|
+
if (beatCount2 >= 8) return ARC_ROLES;
|
|
16725
|
+
if (beatCount2 >= 5) return ["limitations", "conclusion"];
|
|
16726
16726
|
return [];
|
|
16727
16727
|
}
|
|
16728
16728
|
function paperArcRequested(prefs) {
|
|
@@ -16975,7 +16975,8 @@ DRAWING ARCHETYPES \u2014 reach here first
|
|
|
16975
16975
|
repeat. Leave it off only when the figure's whole layout is the
|
|
16976
16976
|
argument.
|
|
16977
16977
|
|
|
16978
|
-
grid A cols\xD7rows lattice
|
|
16978
|
+
grid A cols\xD7rows lattice (cols 2\u201324, rows 1\u201316) with one to four
|
|
16979
|
+
regions lit in turn \u2014 never a fifth. The
|
|
16979
16980
|
tell: A FIELD WITH NO ORDER \u2014 patches, windows, tokens, tiles,
|
|
16980
16981
|
receptive fields, masks, strides, a neighbourhood, a block-sparse
|
|
16981
16982
|
pattern. Regions are cell coordinates, so the lattice IS the
|
|
@@ -17867,6 +17868,10 @@ function stripNulls(node) {
|
|
|
17867
17868
|
var PLANNER_INVISIBLE = /* @__PURE__ */ new Set(["tilt"]);
|
|
17868
17869
|
function plannerInvisible(prefs) {
|
|
17869
17870
|
const hidden = new Set(PLANNER_INVISIBLE);
|
|
17871
|
+
if (prefs.images && !prefs.images.enabled) {
|
|
17872
|
+
hidden.add("illustration");
|
|
17873
|
+
hidden.add("backdrop");
|
|
17874
|
+
}
|
|
17870
17875
|
if (!paperArcRequested(prefs)) hidden.add("role");
|
|
17871
17876
|
if (!bespokeFor(prefs, designFor(prefs))) hidden.add("bespoke");
|
|
17872
17877
|
return hidden;
|
|
@@ -17898,7 +17903,7 @@ function schemaFor(prefs) {
|
|
|
17898
17903
|
plannerInvisible(prefs)
|
|
17899
17904
|
);
|
|
17900
17905
|
}
|
|
17901
|
-
var SCHEMA = schemaFor({
|
|
17906
|
+
var SCHEMA = schemaFor(prefsSchema.parse({}));
|
|
17902
17907
|
async function codexPlanner(source, opts = {}) {
|
|
17903
17908
|
const prefs = opts.prefs ?? prefsSchema.parse({});
|
|
17904
17909
|
const dir = await mkdtemp(join10(tmpdir(), "decksmith-plan-"));
|
|
@@ -17918,14 +17923,29 @@ async function codexPlanner(source, opts = {}) {
|
|
|
17918
17923
|
return readPlan(outPath, source, prefs);
|
|
17919
17924
|
};
|
|
17920
17925
|
const prompt = buildPrompt(source, prefs);
|
|
17921
|
-
|
|
17922
|
-
|
|
17923
|
-
|
|
17926
|
+
let first;
|
|
17927
|
+
let firstJson;
|
|
17928
|
+
let broken;
|
|
17929
|
+
try {
|
|
17930
|
+
first = await ask(prompt);
|
|
17931
|
+
firstJson = first;
|
|
17932
|
+
broken = varietyFindings(first, prefs.images, prefs.design);
|
|
17933
|
+
} catch (err) {
|
|
17934
|
+
if (!(err instanceof PlanRejected)) throw err;
|
|
17935
|
+
firstJson = err.plan;
|
|
17936
|
+
broken = err.problems;
|
|
17937
|
+
}
|
|
17938
|
+
if (first && broken.length === 0) return first;
|
|
17924
17939
|
opts.onRepair?.(broken);
|
|
17925
|
-
const second = await ask(repairPrompt(prompt,
|
|
17940
|
+
const second = await ask(repairPrompt(prompt, firstJson, broken, prefs.images.enabled)).catch(
|
|
17941
|
+
(err) => {
|
|
17942
|
+
throw err instanceof PlanRejected ? new Error(`Codex's plan is still refused after one repair. ${err.message}`) : err;
|
|
17943
|
+
}
|
|
17944
|
+
);
|
|
17945
|
+
const firstBeats = beatCount(firstJson);
|
|
17926
17946
|
const still = [
|
|
17927
|
-
...second.beats.length <
|
|
17928
|
-
`the repair returned ${second.beats.length} beats for a plan of ${
|
|
17947
|
+
...second.beats.length < firstBeats ? [
|
|
17948
|
+
`the repair returned ${second.beats.length} beats for a plan of ${firstBeats}; a repair changes shapes and may not drop beats.`
|
|
17929
17949
|
] : [],
|
|
17930
17950
|
...varietyFindings(second, prefs.images, prefs.design)
|
|
17931
17951
|
];
|
|
@@ -17940,21 +17960,32 @@ ${still.map((m) => ` ${m}`).join("\n")}`
|
|
|
17940
17960
|
await rm4(dir, { recursive: true, force: true });
|
|
17941
17961
|
}
|
|
17942
17962
|
}
|
|
17943
|
-
function repairPrompt(prompt, plan, broken) {
|
|
17963
|
+
function repairPrompt(prompt, plan, broken, images) {
|
|
17964
|
+
const moves = images ? "change archetypes, add stage beats with illustration briefs, give diagram beats a backdrop brief, redraw a panel as a hero-number or a kinetic claim where its point is a number or a claim," : "change archetypes, redraw a panel as a hero-number or a kinetic claim where its point is a number or a claim, cite only ids the source lists,";
|
|
17944
17965
|
return `${prompt}
|
|
17945
17966
|
|
|
17946
|
-
YOUR PREVIOUS STORYBOARD, BELOW,
|
|
17967
|
+
YOUR PREVIOUS STORYBOARD, BELOW, IS REFUSED FOR:
|
|
17947
17968
|
${broken.map((m) => ` - ${m}`).join("\n")}
|
|
17948
17969
|
|
|
17949
|
-
Return the whole storyboard again with these fixed. Keep every beat
|
|
17950
|
-
|
|
17951
|
-
|
|
17952
|
-
|
|
17953
|
-
reorder neighbours only as far as the fix needs. Never
|
|
17954
|
-
drop or merge beats: a repair with fewer beats than the plan below is refused.
|
|
17970
|
+
Return the whole storyboard again with these fixed. Keep every beat that is not
|
|
17971
|
+
named above as it is; ${moves} or reorder neighbours only as far as the fix
|
|
17972
|
+
needs. Never drop or merge beats: a repair with fewer beats than the plan below
|
|
17973
|
+
is refused.
|
|
17955
17974
|
|
|
17956
17975
|
${JSON.stringify(plan)}`;
|
|
17957
17976
|
}
|
|
17977
|
+
function beatCount(plan) {
|
|
17978
|
+
const beats = plan?.beats;
|
|
17979
|
+
return Array.isArray(beats) ? beats.length : 0;
|
|
17980
|
+
}
|
|
17981
|
+
var PlanRejected = class extends Error {
|
|
17982
|
+
constructor(message2, problems, plan) {
|
|
17983
|
+
super(message2);
|
|
17984
|
+
this.problems = problems;
|
|
17985
|
+
this.plan = plan;
|
|
17986
|
+
this.name = "PlanRejected";
|
|
17987
|
+
}
|
|
17988
|
+
};
|
|
17958
17989
|
async function readPlan(outPath, source, prefs) {
|
|
17959
17990
|
const raw2 = await readFile12(outPath, "utf8").catch(() => "");
|
|
17960
17991
|
if (raw2.trim() === "") {
|
|
@@ -17969,22 +18000,41 @@ async function readPlan(outPath, source, prefs) {
|
|
|
17969
18000
|
${raw2.slice(0, 200)}`
|
|
17970
18001
|
);
|
|
17971
18002
|
}
|
|
17972
|
-
const
|
|
18003
|
+
const plan = stripNulls(parsed);
|
|
18004
|
+
const result = storyboardSchema.safeParse(plan);
|
|
17973
18005
|
if (!result.success) {
|
|
17974
|
-
const issues = result.error.issues.map((i) =>
|
|
17975
|
-
throw new
|
|
17976
|
-
|
|
18006
|
+
const issues = result.error.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`);
|
|
18007
|
+
throw new PlanRejected(
|
|
18008
|
+
`Codex returned a storyboard that does not validate:
|
|
18009
|
+
${issues.map((i) => ` ${i}`).join("\n")}`,
|
|
18010
|
+
issues,
|
|
18011
|
+
plan
|
|
18012
|
+
);
|
|
17977
18013
|
}
|
|
17978
18014
|
if (!prefs.images.enabled) {
|
|
17979
18015
|
const pending = pendingIllustrations(result.data);
|
|
17980
18016
|
if (pending.length) {
|
|
17981
18017
|
const beats = [...new Set(pending.map((p) => p.beatId))].join(", ");
|
|
17982
|
-
|
|
17983
|
-
|
|
18018
|
+
const msg = `Codex asked for ${pending.length} illustration${pending.length === 1 ? "" : "s"} (${beats}) with images off. Pass --images to let the plan request pictures, or re-run without it.`;
|
|
18019
|
+
throw new PlanRejected(
|
|
18020
|
+
msg,
|
|
18021
|
+
[
|
|
18022
|
+
`${beats} asked for a picture with images off: remove every illustration and backdrop brief`
|
|
18023
|
+
],
|
|
18024
|
+
plan
|
|
17984
18025
|
);
|
|
17985
18026
|
}
|
|
17986
18027
|
}
|
|
17987
|
-
|
|
18028
|
+
try {
|
|
18029
|
+
assertRefsResolve(result.data, source, { pending: prefs.images.enabled ? "allow" : "refuse" });
|
|
18030
|
+
} catch (err) {
|
|
18031
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
18032
|
+
throw new PlanRejected(
|
|
18033
|
+
msg,
|
|
18034
|
+
msg.split("\n").map((l) => l.trim()).filter(Boolean),
|
|
18035
|
+
plan
|
|
18036
|
+
);
|
|
18037
|
+
}
|
|
17988
18038
|
return result.data;
|
|
17989
18039
|
}
|
|
17990
18040
|
function buildPrompt(source, prefs) {
|
package/dist/mcp.js
CHANGED
|
@@ -15277,9 +15277,9 @@ function bespokeFor(prefs, design2) {
|
|
|
15277
15277
|
|
|
15278
15278
|
// src/plan/arc.ts
|
|
15279
15279
|
var ARC_ROLES = ["intro", "background", "limitations", "conclusion"];
|
|
15280
|
-
function requiredRoles(
|
|
15281
|
-
if (
|
|
15282
|
-
if (
|
|
15280
|
+
function requiredRoles(beatCount2) {
|
|
15281
|
+
if (beatCount2 >= 8) return ARC_ROLES;
|
|
15282
|
+
if (beatCount2 >= 5) return ["limitations", "conclusion"];
|
|
15283
15283
|
return [];
|
|
15284
15284
|
}
|
|
15285
15285
|
function paperArcRequested(prefs) {
|
|
@@ -15473,7 +15473,8 @@ DRAWING ARCHETYPES \u2014 reach here first
|
|
|
15473
15473
|
repeat. Leave it off only when the figure's whole layout is the
|
|
15474
15474
|
argument.
|
|
15475
15475
|
|
|
15476
|
-
grid A cols\xD7rows lattice
|
|
15476
|
+
grid A cols\xD7rows lattice (cols 2\u201324, rows 1\u201316) with one to four
|
|
15477
|
+
regions lit in turn \u2014 never a fifth. The
|
|
15477
15478
|
tell: A FIELD WITH NO ORDER \u2014 patches, windows, tokens, tiles,
|
|
15478
15479
|
receptive fields, masks, strides, a neighbourhood, a block-sparse
|
|
15479
15480
|
pattern. Regions are cell coordinates, so the lattice IS the
|
|
@@ -16323,6 +16324,10 @@ function stripNulls(node) {
|
|
|
16323
16324
|
var PLANNER_INVISIBLE = /* @__PURE__ */ new Set(["tilt"]);
|
|
16324
16325
|
function plannerInvisible(prefs) {
|
|
16325
16326
|
const hidden = new Set(PLANNER_INVISIBLE);
|
|
16327
|
+
if (prefs.images && !prefs.images.enabled) {
|
|
16328
|
+
hidden.add("illustration");
|
|
16329
|
+
hidden.add("backdrop");
|
|
16330
|
+
}
|
|
16326
16331
|
if (!paperArcRequested(prefs)) hidden.add("role");
|
|
16327
16332
|
if (!bespokeFor(prefs, designFor(prefs))) hidden.add("bespoke");
|
|
16328
16333
|
return hidden;
|
|
@@ -16354,7 +16359,7 @@ function schemaFor(prefs) {
|
|
|
16354
16359
|
plannerInvisible(prefs)
|
|
16355
16360
|
);
|
|
16356
16361
|
}
|
|
16357
|
-
var SCHEMA = schemaFor({
|
|
16362
|
+
var SCHEMA = schemaFor(prefsSchema.parse({}));
|
|
16358
16363
|
async function codexPlanner(source, opts = {}) {
|
|
16359
16364
|
const prefs = opts.prefs ?? prefsSchema.parse({});
|
|
16360
16365
|
const dir = await mkdtemp(join9(tmpdir2(), "decksmith-plan-"));
|
|
@@ -16374,14 +16379,29 @@ async function codexPlanner(source, opts = {}) {
|
|
|
16374
16379
|
return readPlan(outPath, source, prefs);
|
|
16375
16380
|
};
|
|
16376
16381
|
const prompt = buildPrompt(source, prefs);
|
|
16377
|
-
|
|
16378
|
-
|
|
16379
|
-
|
|
16382
|
+
let first;
|
|
16383
|
+
let firstJson;
|
|
16384
|
+
let broken;
|
|
16385
|
+
try {
|
|
16386
|
+
first = await ask(prompt);
|
|
16387
|
+
firstJson = first;
|
|
16388
|
+
broken = varietyFindings(first, prefs.images, prefs.design);
|
|
16389
|
+
} catch (err) {
|
|
16390
|
+
if (!(err instanceof PlanRejected)) throw err;
|
|
16391
|
+
firstJson = err.plan;
|
|
16392
|
+
broken = err.problems;
|
|
16393
|
+
}
|
|
16394
|
+
if (first && broken.length === 0) return first;
|
|
16380
16395
|
opts.onRepair?.(broken);
|
|
16381
|
-
const second = await ask(repairPrompt(prompt,
|
|
16396
|
+
const second = await ask(repairPrompt(prompt, firstJson, broken, prefs.images.enabled)).catch(
|
|
16397
|
+
(err) => {
|
|
16398
|
+
throw err instanceof PlanRejected ? new Error(`Codex's plan is still refused after one repair. ${err.message}`) : err;
|
|
16399
|
+
}
|
|
16400
|
+
);
|
|
16401
|
+
const firstBeats = beatCount(firstJson);
|
|
16382
16402
|
const still = [
|
|
16383
|
-
...second.beats.length <
|
|
16384
|
-
`the repair returned ${second.beats.length} beats for a plan of ${
|
|
16403
|
+
...second.beats.length < firstBeats ? [
|
|
16404
|
+
`the repair returned ${second.beats.length} beats for a plan of ${firstBeats}; a repair changes shapes and may not drop beats.`
|
|
16385
16405
|
] : [],
|
|
16386
16406
|
...varietyFindings(second, prefs.images, prefs.design)
|
|
16387
16407
|
];
|
|
@@ -16396,21 +16416,32 @@ ${still.map((m) => ` ${m}`).join("\n")}`
|
|
|
16396
16416
|
await rm4(dir, { recursive: true, force: true });
|
|
16397
16417
|
}
|
|
16398
16418
|
}
|
|
16399
|
-
function repairPrompt(prompt, plan, broken) {
|
|
16419
|
+
function repairPrompt(prompt, plan, broken, images) {
|
|
16420
|
+
const moves = images ? "change archetypes, add stage beats with illustration briefs, give diagram beats a backdrop brief, redraw a panel as a hero-number or a kinetic claim where its point is a number or a claim," : "change archetypes, redraw a panel as a hero-number or a kinetic claim where its point is a number or a claim, cite only ids the source lists,";
|
|
16400
16421
|
return `${prompt}
|
|
16401
16422
|
|
|
16402
|
-
YOUR PREVIOUS STORYBOARD, BELOW,
|
|
16423
|
+
YOUR PREVIOUS STORYBOARD, BELOW, IS REFUSED FOR:
|
|
16403
16424
|
${broken.map((m) => ` - ${m}`).join("\n")}
|
|
16404
16425
|
|
|
16405
|
-
Return the whole storyboard again with these fixed. Keep every beat
|
|
16406
|
-
|
|
16407
|
-
|
|
16408
|
-
|
|
16409
|
-
reorder neighbours only as far as the fix needs. Never
|
|
16410
|
-
drop or merge beats: a repair with fewer beats than the plan below is refused.
|
|
16426
|
+
Return the whole storyboard again with these fixed. Keep every beat that is not
|
|
16427
|
+
named above as it is; ${moves} or reorder neighbours only as far as the fix
|
|
16428
|
+
needs. Never drop or merge beats: a repair with fewer beats than the plan below
|
|
16429
|
+
is refused.
|
|
16411
16430
|
|
|
16412
16431
|
${JSON.stringify(plan)}`;
|
|
16413
16432
|
}
|
|
16433
|
+
function beatCount(plan) {
|
|
16434
|
+
const beats = plan?.beats;
|
|
16435
|
+
return Array.isArray(beats) ? beats.length : 0;
|
|
16436
|
+
}
|
|
16437
|
+
var PlanRejected = class extends Error {
|
|
16438
|
+
constructor(message2, problems, plan) {
|
|
16439
|
+
super(message2);
|
|
16440
|
+
this.problems = problems;
|
|
16441
|
+
this.plan = plan;
|
|
16442
|
+
this.name = "PlanRejected";
|
|
16443
|
+
}
|
|
16444
|
+
};
|
|
16414
16445
|
async function readPlan(outPath, source, prefs) {
|
|
16415
16446
|
const raw2 = await readFile9(outPath, "utf8").catch(() => "");
|
|
16416
16447
|
if (raw2.trim() === "") {
|
|
@@ -16425,22 +16456,41 @@ async function readPlan(outPath, source, prefs) {
|
|
|
16425
16456
|
${raw2.slice(0, 200)}`
|
|
16426
16457
|
);
|
|
16427
16458
|
}
|
|
16428
|
-
const
|
|
16459
|
+
const plan = stripNulls(parsed);
|
|
16460
|
+
const result = storyboardSchema.safeParse(plan);
|
|
16429
16461
|
if (!result.success) {
|
|
16430
|
-
const issues = result.error.issues.map((i) =>
|
|
16431
|
-
throw new
|
|
16432
|
-
|
|
16462
|
+
const issues = result.error.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`);
|
|
16463
|
+
throw new PlanRejected(
|
|
16464
|
+
`Codex returned a storyboard that does not validate:
|
|
16465
|
+
${issues.map((i) => ` ${i}`).join("\n")}`,
|
|
16466
|
+
issues,
|
|
16467
|
+
plan
|
|
16468
|
+
);
|
|
16433
16469
|
}
|
|
16434
16470
|
if (!prefs.images.enabled) {
|
|
16435
16471
|
const pending = pendingIllustrations(result.data);
|
|
16436
16472
|
if (pending.length) {
|
|
16437
16473
|
const beats = [...new Set(pending.map((p) => p.beatId))].join(", ");
|
|
16438
|
-
|
|
16439
|
-
|
|
16474
|
+
const msg = `Codex asked for ${pending.length} illustration${pending.length === 1 ? "" : "s"} (${beats}) with images off. Pass --images to let the plan request pictures, or re-run without it.`;
|
|
16475
|
+
throw new PlanRejected(
|
|
16476
|
+
msg,
|
|
16477
|
+
[
|
|
16478
|
+
`${beats} asked for a picture with images off: remove every illustration and backdrop brief`
|
|
16479
|
+
],
|
|
16480
|
+
plan
|
|
16440
16481
|
);
|
|
16441
16482
|
}
|
|
16442
16483
|
}
|
|
16443
|
-
|
|
16484
|
+
try {
|
|
16485
|
+
assertRefsResolve(result.data, source, { pending: prefs.images.enabled ? "allow" : "refuse" });
|
|
16486
|
+
} catch (err) {
|
|
16487
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
16488
|
+
throw new PlanRejected(
|
|
16489
|
+
msg,
|
|
16490
|
+
msg.split("\n").map((l) => l.trim()).filter(Boolean),
|
|
16491
|
+
plan
|
|
16492
|
+
);
|
|
16493
|
+
}
|
|
16444
16494
|
return result.data;
|
|
16445
16495
|
}
|
|
16446
16496
|
function buildPrompt(source, prefs) {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { type Prefs } from "../prefs.js";
|
|
2
2
|
import { type Source, type Storyboard } from "../types.js";
|
|
3
3
|
/** The schema for one run. `role` is present only when the paper arc was asked for. */
|
|
4
|
-
export declare function schemaFor(prefs: Pick<Prefs, "genre" | "bespoke" | "design">
|
|
4
|
+
export declare function schemaFor(prefs: Pick<Prefs, "genre" | "bespoke" | "design"> & {
|
|
5
|
+
images?: Prefs["images"];
|
|
6
|
+
}): unknown;
|
|
5
7
|
/**
|
|
6
|
-
* The default-preferences schema,
|
|
7
|
-
*
|
|
8
|
+
* The default-preferences schema, still exported: `general` hides `role`, and
|
|
9
|
+
* images default off, so it hides the picture briefs too (0.9.5).
|
|
8
10
|
*/
|
|
9
11
|
export declare const SCHEMA: unknown;
|
|
10
12
|
export interface CodexOptions {
|
|
@@ -47,6 +49,16 @@ export interface RunnerArgs {
|
|
|
47
49
|
/** What the planner needs from the outside world: a prompt in, a final message out. */
|
|
48
50
|
export type Runner = (args: RunnerArgs) => Promise<void>;
|
|
49
51
|
export declare function codexPlanner(source: Source, opts?: CodexOptions): Promise<Storyboard>;
|
|
52
|
+
/**
|
|
53
|
+
* A plan Codex answered that this source cannot build — out of the schema's
|
|
54
|
+
* bounds, a picture brief with images off, an id the source lacks — with what
|
|
55
|
+
* is wrong and the JSON it came as, for the one repair round.
|
|
56
|
+
*/
|
|
57
|
+
export declare class PlanRejected extends Error {
|
|
58
|
+
readonly problems: string[];
|
|
59
|
+
readonly plan: unknown;
|
|
60
|
+
constructor(message: string, problems: string[], plan: unknown);
|
|
61
|
+
}
|
|
50
62
|
/**
|
|
51
63
|
* The `codex` command line for a run, and the environment it needs.
|
|
52
64
|
*
|