@lingjingai/scriptctl 0.1.0 → 0.2.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 +71 -0
- package/dist/cli.js +305 -396
- package/dist/cli.js.map +1 -1
- package/dist/domain/asset-registry.d.ts +141 -0
- package/dist/domain/asset-registry.js +318 -0
- package/dist/domain/asset-registry.js.map +1 -0
- package/dist/domain/collision-detector.d.ts +83 -0
- package/dist/domain/collision-detector.js +248 -0
- package/dist/domain/collision-detector.js.map +1 -0
- package/dist/domain/direct-core.d.ts +13 -1
- package/dist/domain/direct-core.js +14 -4
- package/dist/domain/direct-core.js.map +1 -1
- package/dist/domain/script-core.d.ts +11 -0
- package/dist/domain/script-core.js +34 -19
- package/dist/domain/script-core.js.map +1 -1
- package/dist/help-text.js +283 -0
- package/dist/help-text.js.map +1 -1
- package/dist/infra/converters.js +21 -7
- package/dist/infra/converters.js.map +1 -1
- package/dist/infra/default-writing-prompt.d.ts +31 -0
- package/dist/infra/default-writing-prompt.js +50 -0
- package/dist/infra/default-writing-prompt.js.map +1 -0
- package/dist/infra/default-writing-prompt.md +115 -0
- package/dist/infra/gemini-writer.d.ts +107 -0
- package/dist/infra/gemini-writer.js +207 -0
- package/dist/infra/gemini-writer.js.map +1 -0
- package/dist/infra/providers.d.ts +36 -0
- package/dist/infra/providers.js +186 -2
- package/dist/infra/providers.js.map +1 -1
- package/dist/usecases/episode.d.ts +47 -0
- package/dist/usecases/episode.js +1188 -0
- package/dist/usecases/episode.js.map +1 -0
- package/dist/usecases/script.d.ts +6 -2
- package/dist/usecases/script.js +4 -4
- package/dist/usecases/script.js.map +1 -1
- package/package.json +4 -4
package/dist/cli.js
CHANGED
|
@@ -1,433 +1,342 @@
|
|
|
1
|
+
import { Command, CommanderError } from "commander";
|
|
1
2
|
import { CliError, EXIT_OK, EXIT_USAGE } from "./common.js";
|
|
2
3
|
import { getHelp } from "./help-text.js";
|
|
3
4
|
import { loadLocalEnv } from "./infra/env.js";
|
|
4
5
|
import { emit, emitError } from "./output.js";
|
|
5
6
|
import { commandInit, commandInspect, commandValidate, } from "./usecases/direct.js";
|
|
6
7
|
import { commandDoctor } from "./usecases/doctor.js";
|
|
8
|
+
import { commandEpisodeBatch, commandEpisodeDraft, commandEpisodeInit, commandEpisodeMerge, commandEpisodePush, commandEpisodeStatus, } from "./usecases/episode.js";
|
|
7
9
|
import { commandExport, commandScriptAction, commandScriptContext, commandScriptDialogue, commandScriptInspect, commandScriptPatch, commandScriptSpeaker, commandScriptState, commandScriptValidate, } from "./usecases/script.js";
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
"
|
|
11
|
-
"script.
|
|
12
|
-
"script.state.describe",
|
|
13
|
-
"script.state.refs",
|
|
14
|
-
"script.
|
|
15
|
-
"script.state.
|
|
16
|
-
"script.
|
|
17
|
-
"script.
|
|
18
|
-
"script.
|
|
19
|
-
"
|
|
20
|
-
"script.action.transition-set",
|
|
21
|
-
"script.action.transition-clear",
|
|
22
|
-
"script.speaker.add",
|
|
23
|
-
"script.dialogue.speakers",
|
|
24
|
-
"script.dialogue.overlap",
|
|
10
|
+
const KNOWN_COMMANDS = new Set([
|
|
11
|
+
"doctor",
|
|
12
|
+
"direct", "direct.init", "direct.validate", "direct.inspect", "direct.export",
|
|
13
|
+
"script", "script.inspect", "script.validate", "script.patch",
|
|
14
|
+
"script.state", "script.state.add", "script.state.rename", "script.state.describe",
|
|
15
|
+
"script.state.refs", "script.state.delete-plan", "script.state.delete-apply",
|
|
16
|
+
"script.context", "script.context.set", "script.context.clear",
|
|
17
|
+
"script.action", "script.action.state-change", "script.action.state-remove",
|
|
18
|
+
"script.action.transition-set", "script.action.transition-clear",
|
|
19
|
+
"script.speaker", "script.speaker.add",
|
|
20
|
+
"script.dialogue", "script.dialogue.speakers", "script.dialogue.overlap",
|
|
21
|
+
"episode", "episode.init", "episode.draft", "episode.batch", "episode.status", "episode.merge", "episode.push",
|
|
25
22
|
]);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
opts[name] = true;
|
|
52
|
-
i += 1;
|
|
53
|
-
continue;
|
|
54
|
-
}
|
|
55
|
-
let value;
|
|
56
|
-
if (eqIdx >= 0) {
|
|
57
|
-
value = token.slice(eqIdx + 1);
|
|
58
|
-
i += 1;
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
if (i + 1 >= argv.length) {
|
|
62
|
-
throw new CliError("USAGE ERROR: Invalid arguments", "Invalid arguments.", {
|
|
63
|
-
exitCode: EXIT_USAGE,
|
|
64
|
-
required: [`Run: scriptctl ${command.join(" ")} --help`],
|
|
65
|
-
received: [`option --${rawName} requires a value`],
|
|
66
|
-
nextSteps: [`Run: scriptctl ${command.join(" ")} --help`],
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
value = argv[i + 1];
|
|
70
|
-
i += 2;
|
|
71
|
-
}
|
|
72
|
-
if (arraySet.has(name)) {
|
|
73
|
-
if (!Array.isArray(opts[name]))
|
|
74
|
-
opts[name] = [];
|
|
75
|
-
opts[name].push(value);
|
|
76
|
-
}
|
|
77
|
-
else if (valueSet.has(name)) {
|
|
78
|
-
opts[name] = value;
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
// Allow unknown options for forward-compat but record verbatim
|
|
82
|
-
opts[name] = value;
|
|
83
|
-
}
|
|
84
|
-
continue;
|
|
85
|
-
}
|
|
86
|
-
positionals.push(token);
|
|
87
|
-
i += 1;
|
|
23
|
+
// Groups are command nodes that exist only to host subcommands. Extra non-flag tokens
|
|
24
|
+
// after a group path indicate an unknown subcommand (e.g. `direct nope` → error).
|
|
25
|
+
// Leaves are real commands that can accept positional arguments (e.g. `episode draft <n>`).
|
|
26
|
+
const GROUP_COMMANDS = new Set([
|
|
27
|
+
"direct",
|
|
28
|
+
"script",
|
|
29
|
+
"script.state",
|
|
30
|
+
"script.context",
|
|
31
|
+
"script.action",
|
|
32
|
+
"script.speaker",
|
|
33
|
+
"script.dialogue",
|
|
34
|
+
"episode",
|
|
35
|
+
]);
|
|
36
|
+
function extractLeadingPath(args) {
|
|
37
|
+
// Collect leading non-flag tokens, then take only as many as form the longest known
|
|
38
|
+
// command prefix. Trailing tokens are treated as either:
|
|
39
|
+
// - positional arguments (when the matched node is a leaf, e.g. `episode draft 1`)
|
|
40
|
+
// - unknown subcommands (when the matched node is a group, e.g. `direct nope`)
|
|
41
|
+
const allNonFlag = [];
|
|
42
|
+
for (const tok of args) {
|
|
43
|
+
if (tok.startsWith("-"))
|
|
44
|
+
break;
|
|
45
|
+
allNonFlag.push(tok);
|
|
46
|
+
if (allNonFlag.length >= 5)
|
|
47
|
+
break;
|
|
88
48
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (!(required in opts)) {
|
|
94
|
-
throw new CliError("USAGE ERROR: Invalid arguments", "Invalid arguments.", {
|
|
95
|
-
exitCode: EXIT_USAGE,
|
|
96
|
-
required: [`Run: scriptctl ${command.join(" ")} --help`],
|
|
97
|
-
received: [`missing --${required.replace(/_/g, "-")}`],
|
|
98
|
-
nextSteps: [`Run: scriptctl ${command.join(" ")} --help`],
|
|
99
|
-
});
|
|
100
|
-
}
|
|
49
|
+
const matchLen = longestKnownPrefix(allNonFlag);
|
|
50
|
+
if (matchLen === 0) {
|
|
51
|
+
// No known command at all — return up to 3 tokens for a readable error.
|
|
52
|
+
return allNonFlag.slice(0, 3);
|
|
101
53
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
54
|
+
const matchedKey = allNonFlag.slice(0, matchLen).join(".");
|
|
55
|
+
const isGroup = GROUP_COMMANDS.has(matchedKey);
|
|
56
|
+
if (isGroup && allNonFlag.length > matchLen) {
|
|
57
|
+
// Group + extra tokens = unknown subcommand. Return the truncated path so the
|
|
58
|
+
// validator (knownLen < cmdPath.length) reports an error.
|
|
59
|
+
return allNonFlag.slice(0, Math.min(allNonFlag.length, 3));
|
|
106
60
|
}
|
|
107
|
-
return
|
|
108
|
-
}
|
|
109
|
-
function aliasRename(camel) {
|
|
110
|
-
// argparse used dest="from"; we keep TS field also "from"
|
|
111
|
-
return camel;
|
|
61
|
+
return allNonFlag.slice(0, matchLen);
|
|
112
62
|
}
|
|
113
|
-
function
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
flags: [],
|
|
118
|
-
values: ["source_path", "workspace_path", "provider", "model", "concurrency", "batch_mode", "batch_target_lines", "batch_max_chars", "batch_min_lines"],
|
|
119
|
-
arrays: [],
|
|
120
|
-
required: ["source_path"],
|
|
121
|
-
defaults: { workspace_path: "workspace", provider: "anthropic", concurrency: "30", batch_mode: "episode", batch_target_lines: "36", batch_max_chars: "1800", batch_min_lines: "12" },
|
|
122
|
-
acceptsPositionals: false,
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
if (k === "direct.validate") {
|
|
126
|
-
return {
|
|
127
|
-
flags: [],
|
|
128
|
-
values: ["workspace_path", "script_path"],
|
|
129
|
-
arrays: [],
|
|
130
|
-
required: [],
|
|
131
|
-
defaults: { workspace_path: "workspace" },
|
|
132
|
-
acceptsPositionals: false,
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
if (k === "direct.inspect") {
|
|
136
|
-
return {
|
|
137
|
-
flags: [],
|
|
138
|
-
values: ["workspace_path", "target", "id", "episode"],
|
|
139
|
-
arrays: [],
|
|
140
|
-
required: ["target"],
|
|
141
|
-
defaults: { workspace_path: "workspace" },
|
|
142
|
-
acceptsPositionals: false,
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
if (k === "direct.export") {
|
|
146
|
-
return {
|
|
147
|
-
flags: ["force"],
|
|
148
|
-
values: ["workspace_path", "output_path", "project_group_no", "request_id"],
|
|
149
|
-
arrays: [],
|
|
150
|
-
required: [],
|
|
151
|
-
defaults: { workspace_path: "workspace", output_path: "output" },
|
|
152
|
-
acceptsPositionals: false,
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
if (k === "script.inspect") {
|
|
156
|
-
return {
|
|
157
|
-
flags: [],
|
|
158
|
-
values: ["script_path", "workspace_path", "project_group_no", "target", "id"],
|
|
159
|
-
arrays: [],
|
|
160
|
-
required: [],
|
|
161
|
-
defaults: { workspace_path: "workspace", target: "summary" },
|
|
162
|
-
acceptsPositionals: false,
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
if (k === "script.validate") {
|
|
166
|
-
return {
|
|
167
|
-
flags: [],
|
|
168
|
-
values: ["script_path", "workspace_path", "project_group_no"],
|
|
169
|
-
arrays: [],
|
|
170
|
-
required: [],
|
|
171
|
-
defaults: { workspace_path: "workspace" },
|
|
172
|
-
acceptsPositionals: false,
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
if (k === "script.patch") {
|
|
176
|
-
return {
|
|
177
|
-
flags: [],
|
|
178
|
-
values: ["script_path", "workspace_path", "project_group_no", "request_id", "patch"],
|
|
179
|
-
arrays: [],
|
|
180
|
-
required: ["patch"],
|
|
181
|
-
defaults: { workspace_path: "workspace" },
|
|
182
|
-
acceptsPositionals: false,
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
if (k.startsWith("script.state.")) {
|
|
186
|
-
const sub = command[2];
|
|
187
|
-
const values = ["script_path", "workspace_path", "project_group_no", "request_id"];
|
|
188
|
-
const required = [];
|
|
189
|
-
const defaults = { workspace_path: "workspace" };
|
|
190
|
-
if (sub === "add" || sub === "rename") {
|
|
191
|
-
values.push("name");
|
|
192
|
-
required.push("name");
|
|
193
|
-
}
|
|
194
|
-
if (sub === "describe") {
|
|
195
|
-
values.push("description");
|
|
196
|
-
required.push("description");
|
|
197
|
-
}
|
|
198
|
-
if (sub === "add") {
|
|
199
|
-
values.push("description", "state_id");
|
|
200
|
-
defaults["description"] = "";
|
|
201
|
-
}
|
|
202
|
-
if (sub === "delete-apply") {
|
|
203
|
-
values.push("strategy", "replacement");
|
|
204
|
-
required.push("strategy");
|
|
205
|
-
}
|
|
206
|
-
return { flags: [], values, arrays: [], required, defaults, acceptsPositionals: true };
|
|
207
|
-
}
|
|
208
|
-
if (k.startsWith("script.context.")) {
|
|
209
|
-
const sub = command[2];
|
|
210
|
-
const values = ["script_path", "workspace_path", "project_group_no", "request_id"];
|
|
211
|
-
const required = [];
|
|
212
|
-
if (sub === "set") {
|
|
213
|
-
values.push("state");
|
|
214
|
-
required.push("state");
|
|
215
|
-
}
|
|
216
|
-
return {
|
|
217
|
-
flags: [],
|
|
218
|
-
values,
|
|
219
|
-
arrays: [],
|
|
220
|
-
required,
|
|
221
|
-
defaults: { workspace_path: "workspace" },
|
|
222
|
-
acceptsPositionals: true,
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
if (k.startsWith("script.action.")) {
|
|
226
|
-
const sub = command[2];
|
|
227
|
-
const values = ["script_path", "workspace_path", "project_group_no", "request_id"];
|
|
228
|
-
const required = [];
|
|
229
|
-
const defaults = { workspace_path: "workspace" };
|
|
230
|
-
if (sub === "state-change") {
|
|
231
|
-
values.push("to", "from", "effective");
|
|
232
|
-
required.push("to");
|
|
233
|
-
defaults["effective"] = "after";
|
|
234
|
-
}
|
|
235
|
-
if (sub === "transition-set") {
|
|
236
|
-
values.push("process", "contrast");
|
|
237
|
-
required.push("process", "contrast");
|
|
238
|
-
}
|
|
239
|
-
return { flags: [], values, arrays: [], required, defaults, acceptsPositionals: true };
|
|
240
|
-
}
|
|
241
|
-
if (k === "script.speaker.add") {
|
|
242
|
-
return {
|
|
243
|
-
flags: [],
|
|
244
|
-
values: ["script_path", "workspace_path", "project_group_no", "request_id", "kind", "name", "source_id", "voice_desc", "speaker_id"],
|
|
245
|
-
arrays: [],
|
|
246
|
-
required: ["kind", "name"],
|
|
247
|
-
defaults: { workspace_path: "workspace", voice_desc: "" },
|
|
248
|
-
acceptsPositionals: true,
|
|
249
|
-
};
|
|
250
|
-
}
|
|
251
|
-
if (k === "script.dialogue.speakers") {
|
|
252
|
-
return {
|
|
253
|
-
flags: [],
|
|
254
|
-
values: ["script_path", "workspace_path", "project_group_no", "request_id", "delivery"],
|
|
255
|
-
arrays: ["speaker"],
|
|
256
|
-
required: [],
|
|
257
|
-
defaults: { workspace_path: "workspace", delivery: "simultaneous" },
|
|
258
|
-
acceptsPositionals: true,
|
|
259
|
-
};
|
|
63
|
+
function longestKnownPrefix(path) {
|
|
64
|
+
for (let len = path.length; len > 0; len--) {
|
|
65
|
+
if (KNOWN_COMMANDS.has(path.slice(0, len).join(".")))
|
|
66
|
+
return len;
|
|
260
67
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
68
|
+
return 0;
|
|
69
|
+
}
|
|
70
|
+
function commandPath(cmd) {
|
|
71
|
+
const parts = [];
|
|
72
|
+
let c = cmd;
|
|
73
|
+
while (c) {
|
|
74
|
+
const name = c.name();
|
|
75
|
+
if (!name || name === "scriptctl")
|
|
76
|
+
break;
|
|
77
|
+
parts.unshift(name);
|
|
78
|
+
c = c.parent;
|
|
270
79
|
}
|
|
271
|
-
return
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
80
|
+
return parts;
|
|
81
|
+
}
|
|
82
|
+
function camelToSnake(s) {
|
|
83
|
+
return s.replace(/([A-Z])/g, "_$1").toLowerCase();
|
|
84
|
+
}
|
|
85
|
+
function normalizeOpts(opts) {
|
|
86
|
+
const out = {};
|
|
87
|
+
for (const [k, v] of Object.entries(opts))
|
|
88
|
+
out[camelToSnake(k)] = v;
|
|
89
|
+
return out;
|
|
90
|
+
}
|
|
91
|
+
function dispatch(handler, state) {
|
|
92
|
+
return async (...args) => {
|
|
93
|
+
const cmd = args[args.length - 1];
|
|
94
|
+
const positionals = args.slice(0, -2).filter((p) => p !== undefined);
|
|
95
|
+
const normalized = normalizeOpts(cmd.opts());
|
|
96
|
+
if (positionals.length > 0)
|
|
97
|
+
normalized._args = positionals;
|
|
98
|
+
const [report, exitCode] = await handler(normalized);
|
|
99
|
+
emit(report, exitCode, state.jsonMode);
|
|
100
|
+
state.exitCode = exitCode;
|
|
278
101
|
};
|
|
279
102
|
}
|
|
280
|
-
function
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
if (argv[0] !== "direct" && argv[0] !== "script")
|
|
286
|
-
return null;
|
|
287
|
-
const group = argv[0];
|
|
288
|
-
if (argv.length < 2)
|
|
289
|
-
return { command: [group], rest: [] };
|
|
290
|
-
if (argv[1] === "--help" || argv[1] === "-h")
|
|
291
|
-
return { command: [group], rest: [] };
|
|
292
|
-
if (group === "script" && SCRIPT_NESTED_GROUPS.has(argv[1])) {
|
|
293
|
-
if (argv.length < 3 || argv[2] === "--help" || argv[2] === "-h") {
|
|
294
|
-
return { command: ["script", argv[1]], rest: [] };
|
|
295
|
-
}
|
|
296
|
-
return { command: ["script", argv[1], argv[2]], rest: argv.slice(3) };
|
|
297
|
-
}
|
|
298
|
-
return { command: [group, argv[1]], rest: argv.slice(2) };
|
|
103
|
+
function showGroupHelp(commandPathParts, state) {
|
|
104
|
+
return () => {
|
|
105
|
+
process.stdout.write(getHelp(commandPathParts) ?? getHelp([]) ?? "");
|
|
106
|
+
state.exitCode = EXIT_OK;
|
|
107
|
+
};
|
|
299
108
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
return
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
109
|
+
const appendStr = (value, prev) => [...prev, value];
|
|
110
|
+
function withScriptOpts(cmd) {
|
|
111
|
+
return cmd
|
|
112
|
+
.option("--script-path <path>")
|
|
113
|
+
.option("--workspace-path <path>", "", "workspace")
|
|
114
|
+
.option("--project-group-no <no>")
|
|
115
|
+
.option("--request-id <id>");
|
|
116
|
+
}
|
|
117
|
+
function buildProgram(state) {
|
|
118
|
+
const program = new Command("scriptctl")
|
|
119
|
+
.exitOverride()
|
|
120
|
+
.allowExcessArguments(false)
|
|
121
|
+
.allowUnknownOption(false)
|
|
122
|
+
.configureOutput({
|
|
123
|
+
writeOut: (str) => process.stdout.write(str),
|
|
124
|
+
writeErr: () => {
|
|
125
|
+
/* swallowed; we emit our own envelope */
|
|
126
|
+
},
|
|
127
|
+
})
|
|
128
|
+
.configureHelp({
|
|
129
|
+
formatHelp: (cmd) => getHelp(commandPath(cmd)) ?? getHelp([]) ?? "",
|
|
130
|
+
});
|
|
131
|
+
program.command("doctor").action(dispatch((o) => commandDoctor(o), state));
|
|
132
|
+
// ============================== direct ==============================
|
|
133
|
+
const direct = program.command("direct").action(showGroupHelp(["direct"], state));
|
|
134
|
+
direct.command("init")
|
|
135
|
+
.requiredOption("--source-path <path>")
|
|
136
|
+
.option("--workspace-path <path>", "", "workspace")
|
|
137
|
+
.option("--provider <name>", "", "anthropic")
|
|
138
|
+
.option("--model <model>")
|
|
139
|
+
.option("--concurrency <n>", "", "30")
|
|
140
|
+
.option("--batch-mode <mode>", "", "episode")
|
|
141
|
+
.option("--batch-target-lines <n>", "", "36")
|
|
142
|
+
.option("--batch-max-chars <n>", "", "1800")
|
|
143
|
+
.option("--batch-min-lines <n>", "", "12")
|
|
144
|
+
.action(dispatch(commandInit, state));
|
|
145
|
+
direct.command("validate")
|
|
146
|
+
.option("--workspace-path <path>", "", "workspace")
|
|
147
|
+
.option("--script-path <path>")
|
|
148
|
+
.action(dispatch((o) => commandValidate(o), state));
|
|
149
|
+
direct.command("inspect")
|
|
150
|
+
.requiredOption("--target <target>")
|
|
151
|
+
.option("--workspace-path <path>", "", "workspace")
|
|
152
|
+
.option("--id <id>")
|
|
153
|
+
.option("--episode <e>")
|
|
154
|
+
.action(dispatch((o) => commandInspect(o), state));
|
|
155
|
+
direct.command("export")
|
|
156
|
+
.option("--workspace-path <path>", "", "workspace")
|
|
157
|
+
.option("--output-path <path>", "", "output")
|
|
158
|
+
.option("--project-group-no <no>")
|
|
159
|
+
.option("--request-id <id>")
|
|
160
|
+
.option("--force")
|
|
161
|
+
.action(dispatch(commandExport, state));
|
|
162
|
+
// ============================== script ==============================
|
|
163
|
+
const script = program.command("script").action(showGroupHelp(["script"], state));
|
|
164
|
+
withScriptOpts(script.command("inspect"))
|
|
165
|
+
.option("--target <target>", "", "summary")
|
|
166
|
+
.option("--id <id>")
|
|
167
|
+
.action(dispatch(commandScriptInspect, state));
|
|
168
|
+
withScriptOpts(script.command("validate")).action(dispatch(commandScriptValidate, state));
|
|
169
|
+
withScriptOpts(script.command("patch"))
|
|
170
|
+
.requiredOption("--patch <file>")
|
|
171
|
+
.action(dispatch(commandScriptPatch, state));
|
|
172
|
+
// ------- script state -------
|
|
173
|
+
const scriptState = script.command("state").action(showGroupHelp(["script", "state"], state));
|
|
174
|
+
withScriptOpts(scriptState.command("add <target>"))
|
|
175
|
+
.requiredOption("--name <name>")
|
|
176
|
+
.option("--description <text>", "", "")
|
|
177
|
+
.option("--state-id <id>")
|
|
178
|
+
.action(dispatch((o) => commandScriptState(o, "add"), state));
|
|
179
|
+
withScriptOpts(scriptState.command("rename <target>"))
|
|
180
|
+
.requiredOption("--name <name>")
|
|
181
|
+
.action(dispatch((o) => commandScriptState(o, "rename"), state));
|
|
182
|
+
withScriptOpts(scriptState.command("describe <target>"))
|
|
183
|
+
.requiredOption("--description <text>")
|
|
184
|
+
.action(dispatch((o) => commandScriptState(o, "describe"), state));
|
|
185
|
+
withScriptOpts(scriptState.command("refs <target>"))
|
|
186
|
+
.action(dispatch((o) => commandScriptState(o, "refs"), state));
|
|
187
|
+
withScriptOpts(scriptState.command("delete-plan <target>"))
|
|
188
|
+
.action(dispatch((o) => commandScriptState(o, "delete-plan"), state));
|
|
189
|
+
withScriptOpts(scriptState.command("delete-apply <target>"))
|
|
190
|
+
.requiredOption("--strategy <strategy>")
|
|
191
|
+
.option("--replacement <id>")
|
|
192
|
+
.action(dispatch((o) => commandScriptState(o, "delete-apply"), state));
|
|
193
|
+
// ------- script context -------
|
|
194
|
+
const scriptContext = script.command("context").action(showGroupHelp(["script", "context"], state));
|
|
195
|
+
withScriptOpts(scriptContext.command("set <at> <target>"))
|
|
196
|
+
.requiredOption("--state <id>")
|
|
197
|
+
.action(dispatch((o) => commandScriptContext(o, "set"), state));
|
|
198
|
+
withScriptOpts(scriptContext.command("clear <at> <target>"))
|
|
199
|
+
.action(dispatch((o) => commandScriptContext(o, "clear"), state));
|
|
200
|
+
// ------- script action -------
|
|
201
|
+
const scriptAction = script.command("action").action(showGroupHelp(["script", "action"], state));
|
|
202
|
+
withScriptOpts(scriptAction.command("state-change <at> <target>"))
|
|
203
|
+
.requiredOption("--to <id>")
|
|
204
|
+
.option("--from <id>")
|
|
205
|
+
.option("--effective <when>", "", "after")
|
|
206
|
+
.action(dispatch((o) => commandScriptAction(o, "state-change"), state));
|
|
207
|
+
withScriptOpts(scriptAction.command("state-remove <at> <target>"))
|
|
208
|
+
.action(dispatch((o) => commandScriptAction(o, "state-remove"), state));
|
|
209
|
+
withScriptOpts(scriptAction.command("transition-set <at> <target>"))
|
|
210
|
+
.requiredOption("--process <text>")
|
|
211
|
+
.requiredOption("--contrast <text>")
|
|
212
|
+
.action(dispatch((o) => commandScriptAction(o, "transition-set"), state));
|
|
213
|
+
withScriptOpts(scriptAction.command("transition-clear <at> <target>"))
|
|
214
|
+
.action(dispatch((o) => commandScriptAction(o, "transition-clear"), state));
|
|
215
|
+
// ------- script speaker -------
|
|
216
|
+
const scriptSpeaker = script.command("speaker").action(showGroupHelp(["script", "speaker"], state));
|
|
217
|
+
withScriptOpts(scriptSpeaker.command("add"))
|
|
218
|
+
.requiredOption("--kind <kind>")
|
|
219
|
+
.requiredOption("--name <name>")
|
|
220
|
+
.option("--source-id <id>")
|
|
221
|
+
.option("--voice-desc <text>", "", "")
|
|
222
|
+
.option("--speaker-id <id>")
|
|
223
|
+
.action(dispatch((o) => commandScriptSpeaker(o, "add"), state));
|
|
224
|
+
// ------- script dialogue -------
|
|
225
|
+
const scriptDialogue = script.command("dialogue").action(showGroupHelp(["script", "dialogue"], state));
|
|
226
|
+
withScriptOpts(scriptDialogue.command("speakers <at>"))
|
|
227
|
+
.option("--speaker <id>", "", appendStr, [])
|
|
228
|
+
.option("--delivery <mode>", "", "simultaneous")
|
|
229
|
+
.action(dispatch((o) => commandScriptDialogue(o, "speakers"), state));
|
|
230
|
+
withScriptOpts(scriptDialogue.command("overlap <at>"))
|
|
231
|
+
.option("--line <spec>", "", appendStr, [])
|
|
232
|
+
.action(dispatch((o) => commandScriptDialogue(o, "overlap"), state));
|
|
233
|
+
// ============================== episode ==============================
|
|
234
|
+
const episode = program.command("episode").action(showGroupHelp(["episode"], state));
|
|
235
|
+
episode.command("init")
|
|
236
|
+
.option("--workspace-path <path>", "", "workspace")
|
|
237
|
+
.option("--force")
|
|
238
|
+
.action(dispatch((o) => commandEpisodeInit(o), state));
|
|
239
|
+
episode.command("draft <n>")
|
|
240
|
+
.option("--workspace-path <path>", "", "workspace")
|
|
241
|
+
.option("--prompt-template <path>")
|
|
242
|
+
.option("--outline <path>")
|
|
243
|
+
.option("--ref <spec>", "", appendStr, [])
|
|
244
|
+
.option("--from-md <path>")
|
|
245
|
+
.option("--provider <name>")
|
|
246
|
+
.option("--model <model>")
|
|
247
|
+
.option("--max-tokens <n>")
|
|
248
|
+
.option("--regen")
|
|
249
|
+
.option("--resume")
|
|
250
|
+
.action(dispatch((o) => commandEpisodeDraft(o), state));
|
|
251
|
+
episode.command("batch")
|
|
252
|
+
.requiredOption("--range <a-b>")
|
|
253
|
+
.option("--workspace-path <path>", "", "workspace")
|
|
254
|
+
.option("--prompt-template <path>")
|
|
255
|
+
.option("--outline <path>")
|
|
256
|
+
.option("--ref <spec>", "", appendStr, [])
|
|
257
|
+
.option("--provider <name>")
|
|
258
|
+
.option("--model <model>")
|
|
259
|
+
.option("--max-tokens <n>")
|
|
260
|
+
.action(dispatch((o) => commandEpisodeBatch(o), state));
|
|
261
|
+
episode.command("status")
|
|
262
|
+
.option("--workspace-path <path>", "", "workspace")
|
|
263
|
+
.action(dispatch((o) => commandEpisodeStatus(o), state));
|
|
264
|
+
episode.command("merge")
|
|
265
|
+
.option("--workspace-path <path>", "", "workspace")
|
|
266
|
+
.option("--meta-path <path>")
|
|
267
|
+
.option("--from <n>")
|
|
268
|
+
.option("--to <n>")
|
|
269
|
+
.option("--force")
|
|
270
|
+
.action(dispatch((o) => commandEpisodeMerge(o), state));
|
|
271
|
+
episode.command("push")
|
|
272
|
+
.option("--workspace-path <path>", "", "workspace")
|
|
273
|
+
.option("--project-group-no <no>")
|
|
274
|
+
.option("--request-id <id>")
|
|
275
|
+
.action(dispatch((o) => commandEpisodePush(o), state));
|
|
276
|
+
return program;
|
|
308
277
|
}
|
|
309
|
-
const TOP_LEVEL_GROUPS_WITHOUT_SUB = new Set([
|
|
310
|
-
"direct",
|
|
311
|
-
"script",
|
|
312
|
-
"script.state",
|
|
313
|
-
"script.context",
|
|
314
|
-
"script.action",
|
|
315
|
-
"script.speaker",
|
|
316
|
-
"script.dialogue",
|
|
317
|
-
]);
|
|
318
278
|
export async function main(argv = null) {
|
|
319
279
|
loadLocalEnv();
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
if (resolved === null)
|
|
329
|
-
return unknownCommandError(args, jsonMode);
|
|
330
|
-
const { command, rest } = resolved;
|
|
331
|
-
const cmdKey = key(command);
|
|
332
|
-
if (TOP_LEVEL_GROUPS_WITHOUT_SUB.has(cmdKey)) {
|
|
333
|
-
if (rest.length === 0 || rest[0] === "--help" || rest[0] === "-h") {
|
|
334
|
-
process.stdout.write(getHelp(command) ?? "");
|
|
280
|
+
let args = argv ?? process.argv.slice(2);
|
|
281
|
+
const state = { jsonMode: args.includes("--json"), exitCode: EXIT_OK };
|
|
282
|
+
args = args.filter((a) => a !== "--json");
|
|
283
|
+
const wantsHelp = args.includes("--help") || args.includes("-h");
|
|
284
|
+
const cmdPath = extractLeadingPath(args);
|
|
285
|
+
if (cmdPath.length === 0) {
|
|
286
|
+
if (args.length === 0 || wantsHelp) {
|
|
287
|
+
process.stdout.write(getHelp([]) ?? "");
|
|
335
288
|
return EXIT_OK;
|
|
336
289
|
}
|
|
290
|
+
return emitError(new CliError("USAGE ERROR: Unknown command", "Unknown command.", {
|
|
291
|
+
exitCode: EXIT_USAGE,
|
|
292
|
+
required: ["valid scriptctl command"],
|
|
293
|
+
received: [args.join(" ") || "<empty>"],
|
|
294
|
+
nextSteps: ["Run: scriptctl --help"],
|
|
295
|
+
}), state.jsonMode);
|
|
337
296
|
}
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
return EXIT_OK;
|
|
342
|
-
}
|
|
343
|
-
const [report, exitCode] = commandDoctor({});
|
|
344
|
-
emit(report, exitCode, jsonMode);
|
|
345
|
-
return exitCode;
|
|
346
|
-
}
|
|
347
|
-
// Validate command is recognized
|
|
348
|
-
const helpExists = getHelp(command) !== undefined;
|
|
349
|
-
if (!helpExists && !NESTED_COMMANDS.has(cmdKey)) {
|
|
350
|
-
const required = command[0] === "direct"
|
|
351
|
-
? ["init, validate, inspect, export"]
|
|
352
|
-
: ["inspect, validate, patch, state, context, action, speaker, dialogue"];
|
|
353
|
-
return emitError(new CliError(`USAGE ERROR: Unknown ${command[0]} command`, "Unknown command.", {
|
|
297
|
+
const knownLen = longestKnownPrefix(cmdPath);
|
|
298
|
+
if (knownLen < cmdPath.length) {
|
|
299
|
+
return emitError(new CliError("USAGE ERROR: Unknown command", "Unknown command.", {
|
|
354
300
|
exitCode: EXIT_USAGE,
|
|
355
|
-
required,
|
|
356
|
-
received: [
|
|
357
|
-
nextSteps: [
|
|
358
|
-
}), jsonMode);
|
|
301
|
+
required: ["valid scriptctl command"],
|
|
302
|
+
received: [cmdPath.join(" ")],
|
|
303
|
+
nextSteps: ["Run: scriptctl --help"],
|
|
304
|
+
}), state.jsonMode);
|
|
359
305
|
}
|
|
360
|
-
if (
|
|
361
|
-
|
|
362
|
-
if (helpText === undefined && command.length >= 2) {
|
|
363
|
-
helpText = getHelp(command.slice(0, 2));
|
|
364
|
-
}
|
|
365
|
-
if (helpText === undefined)
|
|
366
|
-
helpText = getHelp([]) ?? "";
|
|
367
|
-
process.stdout.write(helpText);
|
|
306
|
+
if (wantsHelp) {
|
|
307
|
+
process.stdout.write(getHelp(cmdPath) ?? getHelp([]) ?? "");
|
|
368
308
|
return EXIT_OK;
|
|
369
309
|
}
|
|
310
|
+
const program = buildProgram(state);
|
|
370
311
|
try {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
if (
|
|
376
|
-
|
|
312
|
+
await program.parseAsync(args, { from: "user" });
|
|
313
|
+
return state.exitCode;
|
|
314
|
+
}
|
|
315
|
+
catch (err) {
|
|
316
|
+
if (err instanceof CommanderError) {
|
|
317
|
+
const code = err.code;
|
|
318
|
+
if (code === "commander.help" ||
|
|
319
|
+
code === "commander.helpDisplayed" ||
|
|
320
|
+
code === "commander.version") {
|
|
321
|
+
return EXIT_OK;
|
|
322
|
+
}
|
|
323
|
+
const message = err.message || "Invalid arguments.";
|
|
324
|
+
return emitError(new CliError("USAGE ERROR: Invalid arguments", "Invalid arguments.", {
|
|
377
325
|
exitCode: EXIT_USAGE,
|
|
378
|
-
required: ["
|
|
379
|
-
received: [
|
|
380
|
-
nextSteps: ["Run scriptctl --help"],
|
|
381
|
-
});
|
|
326
|
+
required: ["Run: scriptctl --help"],
|
|
327
|
+
received: [message],
|
|
328
|
+
nextSteps: ["Run: scriptctl --help"],
|
|
329
|
+
}), state.jsonMode);
|
|
382
330
|
}
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
return exitCode;
|
|
387
|
-
}
|
|
388
|
-
catch (exc) {
|
|
389
|
-
if (exc instanceof CliError)
|
|
390
|
-
return emitError(exc, jsonMode);
|
|
391
|
-
const err = exc;
|
|
331
|
+
if (err instanceof CliError)
|
|
332
|
+
return emitError(err, state.jsonMode);
|
|
333
|
+
const e = err;
|
|
392
334
|
return emitError(new CliError("RUNTIME FAILED: Unexpected error", "Unexpected error.", {
|
|
393
335
|
exitCode: 70,
|
|
394
336
|
required: ["successful command execution"],
|
|
395
|
-
received: [
|
|
337
|
+
received: [e?.name ?? "Error"],
|
|
396
338
|
nextSteps: ["Rerun with valid inputs or inspect workspace artifacts."],
|
|
397
|
-
}), jsonMode);
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
function pickHandler(command) {
|
|
401
|
-
const k = key(command);
|
|
402
|
-
if (k === "direct.init")
|
|
403
|
-
return commandInit;
|
|
404
|
-
if (k === "direct.validate")
|
|
405
|
-
return (opts) => commandValidate(opts);
|
|
406
|
-
if (k === "direct.inspect")
|
|
407
|
-
return (opts) => commandInspect(opts);
|
|
408
|
-
if (k === "direct.export")
|
|
409
|
-
return commandExport;
|
|
410
|
-
if (k === "script.inspect")
|
|
411
|
-
return commandScriptInspect;
|
|
412
|
-
if (k === "script.validate")
|
|
413
|
-
return commandScriptValidate;
|
|
414
|
-
if (k === "script.patch")
|
|
415
|
-
return commandScriptPatch;
|
|
416
|
-
if (command.length === 3 && command[0] === "script" && command[1] === "state") {
|
|
417
|
-
return (opts) => commandScriptState(opts, command[2]);
|
|
418
|
-
}
|
|
419
|
-
if (command.length === 3 && command[0] === "script" && command[1] === "context") {
|
|
420
|
-
return (opts) => commandScriptContext(opts, command[2]);
|
|
421
|
-
}
|
|
422
|
-
if (command.length === 3 && command[0] === "script" && command[1] === "action") {
|
|
423
|
-
return (opts) => commandScriptAction(opts, command[2]);
|
|
424
|
-
}
|
|
425
|
-
if (command.length === 3 && command[0] === "script" && command[1] === "speaker") {
|
|
426
|
-
return (opts) => commandScriptSpeaker(opts, command[2]);
|
|
427
|
-
}
|
|
428
|
-
if (command.length === 3 && command[0] === "script" && command[1] === "dialogue") {
|
|
429
|
-
return (opts) => commandScriptDialogue(opts, command[2]);
|
|
339
|
+
}), state.jsonMode);
|
|
430
340
|
}
|
|
431
|
-
return null;
|
|
432
341
|
}
|
|
433
342
|
//# sourceMappingURL=cli.js.map
|