@lingjingai/scriptctl 0.11.3 → 0.11.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 +17 -2
- package/dist/cli.js.map +1 -1
- package/dist/common.d.ts +1 -1
- package/dist/common.js +29 -14
- package/dist/common.js.map +1 -1
- package/dist/domain/direct-core.d.ts +13 -8
- package/dist/domain/direct-core.js +53 -13
- package/dist/domain/direct-core.js.map +1 -1
- package/dist/domain/script-core.d.ts +1 -0
- package/dist/domain/script-core.js +11 -2
- package/dist/domain/script-core.js.map +1 -1
- package/dist/help-text.js +2 -2
- package/dist/infra/providers.js +16 -0
- package/dist/infra/providers.js.map +1 -1
- package/dist/usecases/direct.d.ts +5 -3
- package/dist/usecases/direct.js +416 -566
- package/dist/usecases/direct.js.map +1 -1
- package/dist/usecases/parse.d.ts +15 -0
- package/dist/usecases/parse.js +324 -0
- package/dist/usecases/parse.js.map +1 -0
- package/dist/usecases/script.js +25 -3
- package/dist/usecases/script.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `scriptctl parse` — 实验性、与 direct 完全解耦的入库路径。
|
|
3
|
+
*
|
|
4
|
+
* 设计原则:md 是唯一真相源。subagent 写好一个 md 工作区(每集正文 md + 人物/场景/
|
|
5
|
+
* 道具/发声源 md + 可选 梗概.md/元信息.md),parse 确定性地解析、装配成 script,校验
|
|
6
|
+
* 通过后(`--publish`)直接写进 ScriptOutputStore。出问题就改 md 重跑——不经 direct 的
|
|
7
|
+
* inspect/patch/export,也不写 direct 的 run_state / directDir / source.txt。
|
|
8
|
+
*
|
|
9
|
+
* 依赖只触及更底层:domain(md 解析/装配、校验)+ infra(输出 store)+ common。
|
|
10
|
+
* 不 import 任何 sibling usecase(direct.ts / script.ts),可随时整体移除。
|
|
11
|
+
*/
|
|
12
|
+
import * as fs from "node:fs";
|
|
13
|
+
import * as path from "node:path";
|
|
14
|
+
import { CliError, EXIT_INPUT, EXIT_NEEDS_AGENT, EXIT_OK, PARSE_MD_SPEC, WORLDVIEW_VALUES, exists, readText, sha256Text, writeJson, } from "../common.js";
|
|
15
|
+
import { cleanName, mergeEpisodeResults, parseAssetDoc, parseMarkdownBatch } from "../domain/direct-core.js";
|
|
16
|
+
import { validateScript } from "../domain/script-core.js";
|
|
17
|
+
import { LocalScriptOutputStore } from "../infra/local-script-output-store.js";
|
|
18
|
+
import { RemoteScriptOutputStore } from "../infra/script-output-api.js";
|
|
19
|
+
import { ScriptOutputApiError, resolveOutputMode } from "../infra/script-output-store.js";
|
|
20
|
+
function strOf(v) {
|
|
21
|
+
return v === null || v === undefined ? "" : String(v);
|
|
22
|
+
}
|
|
23
|
+
function isDict(v) {
|
|
24
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
25
|
+
}
|
|
26
|
+
function asList(v) {
|
|
27
|
+
return Array.isArray(v) ? v : [];
|
|
28
|
+
}
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// md 工作区布局
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
const _EP_FILE_RE = /^ep[_-]?0*(\d+)\.(?:md|markdown)$/i;
|
|
33
|
+
const ASSET_DOC_SPECS = [
|
|
34
|
+
{ kind: "actors", names: ["人物.md", "角色.md", "characters.md", "actors.md"] },
|
|
35
|
+
{ kind: "locations", names: ["场景.md", "地点.md", "locations.md"] },
|
|
36
|
+
{ kind: "props", names: ["道具.md", "props.md"] },
|
|
37
|
+
{ kind: "speakers", names: ["发声源.md", "speakers.md"] },
|
|
38
|
+
];
|
|
39
|
+
const SYNOPSIS_DOC_NAMES = ["梗概.md", "全文梗概.md", "synopsis.md"];
|
|
40
|
+
const META_DOC_NAMES = ["元信息.md", "meta.md"];
|
|
41
|
+
function firstExisting(dir, names) {
|
|
42
|
+
for (const n of names) {
|
|
43
|
+
const p = path.join(dir, n);
|
|
44
|
+
if (exists(p) && fs.statSync(p).isFile())
|
|
45
|
+
return p;
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
function collectEpisodeMdFiles(dir) {
|
|
50
|
+
if (!exists(dir) || !fs.statSync(dir).isDirectory())
|
|
51
|
+
return [];
|
|
52
|
+
const out = [];
|
|
53
|
+
for (const name of fs.readdirSync(dir)) {
|
|
54
|
+
const m = _EP_FILE_RE.exec(name);
|
|
55
|
+
if (!m)
|
|
56
|
+
continue;
|
|
57
|
+
const full = path.join(dir, name);
|
|
58
|
+
if (!fs.statSync(full).isFile())
|
|
59
|
+
continue;
|
|
60
|
+
out.push({ path: full, episode: parseInt(m[1], 10) });
|
|
61
|
+
}
|
|
62
|
+
out.sort((a, b) => a.episode - b.episode);
|
|
63
|
+
return out;
|
|
64
|
+
}
|
|
65
|
+
// Whole-script metadata from 元信息.md: worldview / style / title / 主角.
|
|
66
|
+
function parseMetaDoc(text) {
|
|
67
|
+
const out = {};
|
|
68
|
+
for (const line of text.split(/\r?\n/)) {
|
|
69
|
+
const m = /^\s*[-*]?\s*(title|worldview|style|protagonists|标题|世界观|风格|主角|主角列表)\s*[::]\s*(.+?)\s*$/i.exec(line);
|
|
70
|
+
if (!m)
|
|
71
|
+
continue;
|
|
72
|
+
const key = m[1].toLowerCase();
|
|
73
|
+
const val = m[2].trim();
|
|
74
|
+
if (!val)
|
|
75
|
+
continue;
|
|
76
|
+
if (key === "title" || key === "标题")
|
|
77
|
+
out.title = val;
|
|
78
|
+
else if (key === "worldview" || key === "世界观")
|
|
79
|
+
out.worldview = val;
|
|
80
|
+
else if (key === "style" || key === "风格")
|
|
81
|
+
out.style = val;
|
|
82
|
+
else if (key === "protagonists" || key === "主角" || key === "主角列表") {
|
|
83
|
+
out.protagonists = val.split(/[,,、]/).map((s) => s.trim()).filter(Boolean);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return out;
|
|
87
|
+
}
|
|
88
|
+
function summarizeIssues(issues) {
|
|
89
|
+
if (issues.length === 0)
|
|
90
|
+
return [];
|
|
91
|
+
const counts = {};
|
|
92
|
+
for (const item of issues) {
|
|
93
|
+
const sev = strOf(item["severity"]);
|
|
94
|
+
counts[sev] = (counts[sev] ?? 0) + 1;
|
|
95
|
+
}
|
|
96
|
+
const parts = Object.entries(counts).sort(([a], [b]) => a.localeCompare(b)).map(([sev, c]) => `${sev}: ${c}`);
|
|
97
|
+
const first = issues[0];
|
|
98
|
+
return [parts.join("; "), `first: ${first["code"]} - ${first["summary"]}`];
|
|
99
|
+
}
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
// 输出 store(直接从 infra 建,不依赖 usecases/script.ts)
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
function makeOutputStore(opts) {
|
|
104
|
+
const mode = resolveOutputMode().mode;
|
|
105
|
+
try {
|
|
106
|
+
return mode === "local"
|
|
107
|
+
? LocalScriptOutputStore.fromEnv(strOf(opts["workspace_path"]).trim() || undefined)
|
|
108
|
+
: RemoteScriptOutputStore.fromEnv(strOf(opts["project_group_no"]).trim() || null);
|
|
109
|
+
}
|
|
110
|
+
catch (exc) {
|
|
111
|
+
const raw = exc instanceof Error ? exc.message : String(exc);
|
|
112
|
+
throw new CliError("PARSE PUBLISH BLOCKED: 输出未配置", "Output store not configured.", {
|
|
113
|
+
exitCode: EXIT_INPUT,
|
|
114
|
+
required: [mode === "local" ? "SCRIPTCTL_OUTPUT_DIR" : "gateway 配置(AWB_BASE_URL / ACCESS_KEY / project-group-no)"],
|
|
115
|
+
received: [raw],
|
|
116
|
+
nextSteps: ["运行 `scriptctl doctor` 检查输出配置。"],
|
|
117
|
+
errorCode: "SCRIPT_API_CONFIG_MISSING",
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
async function currentRevisionOrZero(client) {
|
|
122
|
+
try {
|
|
123
|
+
// getRevision() returns `{ revision: N } | null`, not a bare number.
|
|
124
|
+
const revision = await client.getRevision();
|
|
125
|
+
if (!revision)
|
|
126
|
+
return 0;
|
|
127
|
+
return Number(revision["revision"] ?? 0);
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return 0;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// 稳定序列化(键递归排序),用于 requestId 幂等哈希。
|
|
134
|
+
function sortDeep(value) {
|
|
135
|
+
if (Array.isArray(value))
|
|
136
|
+
return value.map(sortDeep);
|
|
137
|
+
if (value && typeof value === "object") {
|
|
138
|
+
const out = {};
|
|
139
|
+
for (const k of Object.keys(value).sort())
|
|
140
|
+
out[k] = sortDeep(value[k]);
|
|
141
|
+
return out;
|
|
142
|
+
}
|
|
143
|
+
return value;
|
|
144
|
+
}
|
|
145
|
+
// ---------------------------------------------------------------------------
|
|
146
|
+
// command_parse
|
|
147
|
+
// ---------------------------------------------------------------------------
|
|
148
|
+
export async function commandParse(opts) {
|
|
149
|
+
if (opts["spec"]) {
|
|
150
|
+
return [{ title: "PARSE SPEC: md 工作区写法", body: PARSE_MD_SPEC }, EXIT_OK];
|
|
151
|
+
}
|
|
152
|
+
const workspace = strOf(opts["workspace_path"] || "workspace");
|
|
153
|
+
const args = asList(opts["_args"]);
|
|
154
|
+
const mdDir = strOf(opts["md_dir"] || args[0] || path.join(workspace, "parse"));
|
|
155
|
+
if (!exists(mdDir) || !fs.statSync(mdDir).isDirectory()) {
|
|
156
|
+
throw new CliError("PARSE BLOCKED: md workspace not found", "md workspace not found.", {
|
|
157
|
+
exitCode: EXIT_INPUT,
|
|
158
|
+
required: ["a directory with per-episode 正文 md + 人物/场景/道具/发声源 md"],
|
|
159
|
+
received: [mdDir],
|
|
160
|
+
nextSteps: ["Pass the md workspace dir: scriptctl parse <dir>. Run `scriptctl parse --spec` for the format."],
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
let episodesDir = strOf(opts["episodes_dir"]).trim();
|
|
164
|
+
if (!episodesDir) {
|
|
165
|
+
const sub = path.join(mdDir, "episodes");
|
|
166
|
+
episodesDir = exists(sub) && fs.statSync(sub).isDirectory() ? sub : mdDir;
|
|
167
|
+
}
|
|
168
|
+
const bodyFiles = collectEpisodeMdFiles(episodesDir);
|
|
169
|
+
if (bodyFiles.length === 0) {
|
|
170
|
+
throw new CliError("PARSE BLOCKED: no episode md found", "no episode md found.", {
|
|
171
|
+
exitCode: EXIT_INPUT,
|
|
172
|
+
required: ["per-episode body md named like ep_001.md"],
|
|
173
|
+
received: [episodesDir],
|
|
174
|
+
nextSteps: ["Add per-episode 正文 md (ep_001.md, ep_002.md, ...). Run `scriptctl parse --spec` for the format."],
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
// 每类资产各自一份;正文 md 不登资产。汇成一个 bible fragment。
|
|
178
|
+
const bible = { actors: [], locations: [], props: [], speakers: [], state_definitions: [] };
|
|
179
|
+
const assetDocsFound = [];
|
|
180
|
+
for (const spec of ASSET_DOC_SPECS) {
|
|
181
|
+
const p = firstExisting(mdDir, spec.names);
|
|
182
|
+
if (!p)
|
|
183
|
+
continue;
|
|
184
|
+
assetDocsFound.push(path.basename(p));
|
|
185
|
+
const parsed = parseAssetDoc(readText(p), spec.kind);
|
|
186
|
+
for (const key of ["actors", "locations", "props", "speakers", "state_definitions"]) {
|
|
187
|
+
bible[key].push(...asList(parsed[key]));
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// 可选全文梗概(梗概.md);去掉开头的 `# 梗概` 标题行。
|
|
191
|
+
let globalSynopsis = "";
|
|
192
|
+
const synPath = firstExisting(mdDir, SYNOPSIS_DOC_NAMES);
|
|
193
|
+
if (synPath)
|
|
194
|
+
globalSynopsis = readText(synPath).replace(/^\s*#\s+\S[^\n]*\n/, "").trim();
|
|
195
|
+
// 可选整部元信息(元信息.md):worldview / style / title / 主角。
|
|
196
|
+
const metaPath = firstExisting(mdDir, META_DOC_NAMES);
|
|
197
|
+
const meta = metaPath ? parseMetaDoc(readText(metaPath)) : {};
|
|
198
|
+
// 解析每集正文 md(确定性,无 LLM)。
|
|
199
|
+
const results = [];
|
|
200
|
+
for (const file of bodyFiles) {
|
|
201
|
+
try {
|
|
202
|
+
results.push(parseMarkdownBatch(readText(file.path), { episode: file.episode, part: 1 }, { fragmentMode: true }));
|
|
203
|
+
}
|
|
204
|
+
catch (exc) {
|
|
205
|
+
const e = exc;
|
|
206
|
+
throw new CliError("PARSE BLOCKED: episode md invalid", "episode md invalid.", {
|
|
207
|
+
exitCode: EXIT_INPUT,
|
|
208
|
+
required: ["per-episode 正文 md following `scriptctl parse --spec`"],
|
|
209
|
+
received: [`${path.basename(file.path)}: ${(e?.message ?? "").slice(0, 200)}`],
|
|
210
|
+
nextSteps: ["Fix the episode md and re-run parse."],
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
results.sort((a, b) => Number(a["episode"] ?? 0) - Number(b["episode"] ?? 0));
|
|
215
|
+
// 把登记的资产折进第一集 result,描述/状态随之进入装配;名字全局去重,
|
|
216
|
+
// bible-first 让登记表(规范)描述优先于正文里隐含的引用。
|
|
217
|
+
if (results.length > 0) {
|
|
218
|
+
const first = results[0];
|
|
219
|
+
for (const key of ["actors", "locations", "props", "speakers", "state_definitions"]) {
|
|
220
|
+
first[key] = [...asList(bible[key]), ...asList(first[key])];
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
const title = meta.title || strOf(opts["title"]).trim() || path.basename(path.resolve(mdDir));
|
|
224
|
+
const script = mergeEpisodeResults(results, title);
|
|
225
|
+
if (globalSynopsis)
|
|
226
|
+
script["synopsis"] = globalSynopsis;
|
|
227
|
+
if (meta.worldview) {
|
|
228
|
+
if (!WORLDVIEW_VALUES.includes(meta.worldview)) {
|
|
229
|
+
throw new CliError("PARSE BLOCKED: worldview 非法", "Invalid worldview in 元信息.md.", {
|
|
230
|
+
exitCode: EXIT_INPUT,
|
|
231
|
+
required: [`worldview: 取枚举之一 ${WORLDVIEW_VALUES.join(" / ")}`],
|
|
232
|
+
received: [`worldview: ${meta.worldview}`],
|
|
233
|
+
nextSteps: ["改 元信息.md 的 worldview 为合法枚举值,再重跑 parse。"],
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
script["worldview"] = meta.worldview;
|
|
237
|
+
script["worldview_raw"] = meta.worldview;
|
|
238
|
+
}
|
|
239
|
+
if (meta.style)
|
|
240
|
+
script["style"] = meta.style;
|
|
241
|
+
// role_type 由 元信息.md `主角:` 驱动;两边都 cleanName 后比对,避免注解/空白把主角误判成配角。
|
|
242
|
+
if (meta.protagonists && meta.protagonists.length > 0) {
|
|
243
|
+
const leads = new Set(meta.protagonists.map((n) => cleanName(n)));
|
|
244
|
+
for (const actor of asList(script["actors"])) {
|
|
245
|
+
actor["role_type"] = leads.has(cleanName(strOf(actor["actor_name"]))) ? "主角" : "配角";
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
// 产物落在 parse 自己的位置(不写 directDir / run_state / source.txt)。
|
|
249
|
+
const scriptPath = path.join(mdDir, "script.json");
|
|
250
|
+
writeJson(scriptPath, script);
|
|
251
|
+
const validation = validateScript(workspace, null, { requireSource: false, scriptData: script, persist: false });
|
|
252
|
+
const passed = Boolean(validation["passed"]);
|
|
253
|
+
const stats = validation["stats"] ?? {};
|
|
254
|
+
const blockingOrError = Boolean(validation["has_blocking"]) ||
|
|
255
|
+
asList(validation["issues"]).some((it) => isDict(it) && (it["severity"] === "blocking" || it["severity"] === "error"));
|
|
256
|
+
// --publish:md → 校验 → 直接入库。校验不过就报问题、不发布,让 agent 改 md 重跑。
|
|
257
|
+
if (opts["publish"]) {
|
|
258
|
+
if (blockingOrError) {
|
|
259
|
+
return [{
|
|
260
|
+
title: "PARSE PUBLISH BLOCKED: 校验未过,改 md 后重跑",
|
|
261
|
+
result: [`asset docs: ${assetDocsFound.join(" / ") || "(none)"}`, "validation: needs repair"],
|
|
262
|
+
artifacts: [scriptPath],
|
|
263
|
+
issues: summarizeIssues(asList(validation["issues"])),
|
|
264
|
+
next: ["按 issue 直接改对应的 ep_*.md / 人物·场景·道具·发声源.md / 元信息.md,再重跑 `scriptctl parse <dir> --publish`。"],
|
|
265
|
+
}, EXIT_NEEDS_AGENT];
|
|
266
|
+
}
|
|
267
|
+
const client = makeOutputStore(opts);
|
|
268
|
+
const baseRevision = await currentRevisionOrZero(client);
|
|
269
|
+
const scriptHash = sha256Text(JSON.stringify(sortDeep(script)));
|
|
270
|
+
const requestId = strOf(opts["request_id"]).trim() || `scriptctl-parse:${scriptHash}`;
|
|
271
|
+
let replaceRes;
|
|
272
|
+
try {
|
|
273
|
+
replaceRes = await client.replaceScript({ requestId, baseRevision, script, source: "ctl" });
|
|
274
|
+
}
|
|
275
|
+
catch (exc) {
|
|
276
|
+
if (exc instanceof ScriptOutputApiError) {
|
|
277
|
+
const conflict = /版本冲突|revision/i.test(exc.message);
|
|
278
|
+
throw new CliError("PARSE PUBLISH BLOCKED: 入库写入失败", conflict ? "Script has been updated by another revision; reload and retry." : exc.message, {
|
|
279
|
+
exitCode: EXIT_INPUT,
|
|
280
|
+
required: ["可写入的 ScriptOutputStore"],
|
|
281
|
+
received: [exc.message],
|
|
282
|
+
nextSteps: conflict ? ["剧本已被其他写入更新,重跑 parse --publish。"] : ["检查输出配置后重试。"],
|
|
283
|
+
errorCode: conflict ? "SCRIPT_REVISION_CONFLICT" : "SCRIPT_API_WRITE_FAILED",
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
throw exc;
|
|
287
|
+
}
|
|
288
|
+
return [{
|
|
289
|
+
title: "PARSE PUBLISHED: 剧本已入库",
|
|
290
|
+
result: [
|
|
291
|
+
`episodes: ${stats["episodes"] ?? results.length}`,
|
|
292
|
+
`scenes: ${stats["scenes"] ?? 0}`,
|
|
293
|
+
`actions: ${stats["actions"] ?? 0}`,
|
|
294
|
+
`worldview: ${meta.worldview || "(unset)"}`,
|
|
295
|
+
`base_revision: ${baseRevision}`,
|
|
296
|
+
`revision: ${replaceRes["revision"]}`,
|
|
297
|
+
`idempotent: ${replaceRes["idempotent"] ?? false}`,
|
|
298
|
+
],
|
|
299
|
+
artifacts: [scriptPath],
|
|
300
|
+
next: ["剧本已入库。若发现问题,直接改 md 再 `scriptctl parse <dir> --publish` 覆盖。"],
|
|
301
|
+
}, EXIT_OK];
|
|
302
|
+
}
|
|
303
|
+
return [{
|
|
304
|
+
title: passed
|
|
305
|
+
? "PARSE COMPLETE: 已生成 script.json(加 --publish 直接入库)"
|
|
306
|
+
: "PARSE NEEDS AGENT: 校验有问题,直接改 md 再 parse",
|
|
307
|
+
result: [
|
|
308
|
+
`episodes: ${stats["episodes"] ?? results.length}`,
|
|
309
|
+
`scenes: ${stats["scenes"] ?? 0}`,
|
|
310
|
+
`actions: ${stats["actions"] ?? 0}`,
|
|
311
|
+
`asset docs: ${assetDocsFound.join(" / ") || "(none)"}`,
|
|
312
|
+
`worldview: ${meta.worldview || "(unset)"}`,
|
|
313
|
+
`style: ${meta.style || "(unset)"}`,
|
|
314
|
+
`synopsis: ${globalSynopsis ? "yes" : "no"}`,
|
|
315
|
+
`validation: ${passed ? "passed" : "needs repair"}`,
|
|
316
|
+
],
|
|
317
|
+
artifacts: [scriptPath],
|
|
318
|
+
issues: summarizeIssues(asList(validation["issues"])),
|
|
319
|
+
next: passed
|
|
320
|
+
? ["加 `--publish` 直接入库。"]
|
|
321
|
+
: ["按 issue 直接改对应的 md(ep_*.md / 资产 md / 元信息.md),再重跑 parse。"],
|
|
322
|
+
}, passed ? EXIT_OK : EXIT_NEEDS_AGENT];
|
|
323
|
+
}
|
|
324
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/usecases/parse.ts"],"names":[],"mappings":"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"}
|
package/dist/usecases/script.js
CHANGED
|
@@ -825,6 +825,7 @@ async function commandStateRefs(opts, plan = false) {
|
|
|
825
825
|
export async function commandExport(opts) {
|
|
826
826
|
const workspace = strOf(opts["workspace_path"] || "workspace");
|
|
827
827
|
const force = Boolean(opts["force"]);
|
|
828
|
+
const allowIncomplete = Boolean(opts["allow_incomplete"]);
|
|
828
829
|
const scriptPath = path.join(directDir(workspace), "script.initial.json");
|
|
829
830
|
if (!exists(scriptPath)) {
|
|
830
831
|
throw new CliError("EXPORT BLOCKED: script.initial.json not found", "script.initial.json not found.", {
|
|
@@ -845,8 +846,29 @@ export async function commandExport(opts) {
|
|
|
845
846
|
};
|
|
846
847
|
return [report, EXIT_NEEDS_AGENT];
|
|
847
848
|
}
|
|
849
|
+
const heldOut = asList(state["held_out_episodes"]).map((n) => Number(n)).filter((n) => !Number.isNaN(n));
|
|
850
|
+
// A run with terminally-blocked (content-filtered) episodes can still ship the
|
|
851
|
+
// completed ones, but only when the operator explicitly opts in. This also
|
|
852
|
+
// bypasses the review/validation gates for the gaps those held-out episodes
|
|
853
|
+
// create (e.g. episode-number discontinuities).
|
|
854
|
+
if (heldOut.length > 0 && !allowIncomplete) {
|
|
855
|
+
const report = {
|
|
856
|
+
title: "EXPORT BLOCKED: Episodes held out",
|
|
857
|
+
result: [
|
|
858
|
+
"script.initial.json was not exported.",
|
|
859
|
+
`held out (terminal): ${heldOut.join(", ")}`,
|
|
860
|
+
],
|
|
861
|
+
artifacts: [path.join(directDir(workspace), "run_state.json")],
|
|
862
|
+
next: [
|
|
863
|
+
"Provide the missing episodes with `direct override ep_NNN --from <file>` then rerun init,",
|
|
864
|
+
"or export the completed episodes with `direct export --allow-incomplete`.",
|
|
865
|
+
],
|
|
866
|
+
};
|
|
867
|
+
return [report, EXIT_NEEDS_AGENT];
|
|
868
|
+
}
|
|
869
|
+
const incompleteOverride = allowIncomplete && heldOut.length > 0;
|
|
848
870
|
const missingReview = reviewBlockers(state);
|
|
849
|
-
if (missingReview.length > 0) {
|
|
871
|
+
if (missingReview.length > 0 && !incompleteOverride) {
|
|
850
872
|
const report = {
|
|
851
873
|
title: "EXPORT BLOCKED: Agent review incomplete",
|
|
852
874
|
result: ["script.initial.json was not exported.", `missing review: ${missingReview.join(", ")}`],
|
|
@@ -858,7 +880,7 @@ export async function commandExport(opts) {
|
|
|
858
880
|
const validation = validateScript(workspace, scriptPath);
|
|
859
881
|
const blockingOrError = Boolean(validation["has_blocking"]) ||
|
|
860
882
|
asList(validation["issues"]).some((it) => isDict(it) && (it["severity"] === "blocking" || it["severity"] === "error"));
|
|
861
|
-
if (!validation["passed"] && (!force || blockingOrError)) {
|
|
883
|
+
if (!validation["passed"] && (!force || blockingOrError) && !incompleteOverride) {
|
|
862
884
|
const title = force
|
|
863
885
|
? "EXPORT BLOCKED: Validation errors require repair"
|
|
864
886
|
: "EXPORT BLOCKED: Validation needs agent repair";
|
|
@@ -924,7 +946,7 @@ export async function commandExport(opts) {
|
|
|
924
946
|
});
|
|
925
947
|
await syncValidationResult(remoteSession, validation, revision);
|
|
926
948
|
const outputLabel = remoteSession.artifactLabel;
|
|
927
|
-
updateRunState(workspace, { status: "exported", output_path: outputLabel });
|
|
949
|
+
updateRunState(workspace, { status: "exported", output_path: outputLabel, exported_incomplete: incompleteOverride, held_out_episodes: heldOut });
|
|
928
950
|
const report = {
|
|
929
951
|
title: "EXPORT COMPLETE: Final script stored in DB",
|
|
930
952
|
result: [
|