@lingjingai/scriptctl 0.50.0 → 0.51.1
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/changes/0.51.0.md +24 -0
- package/changes/0.51.1.md +15 -0
- package/changes/unreleased.md +1 -2
- package/dist/cli/register-batch.d.ts +3 -0
- package/dist/cli/register-batch.js +28 -0
- package/dist/cli/register-batch.js.map +1 -0
- package/dist/cli/register-edits.d.ts +4 -0
- package/dist/cli/register-edits.js +226 -0
- package/dist/cli/register-edits.js.map +1 -0
- package/dist/cli/register-query.d.ts +4 -0
- package/dist/cli/register-query.js +93 -0
- package/dist/cli/register-query.js.map +1 -0
- package/dist/cli/register-tools.d.ts +3 -0
- package/dist/cli/register-tools.js +23 -0
- package/dist/cli/register-tools.js.map +1 -0
- package/dist/cli/register-workflows.d.ts +4 -0
- package/dist/cli/register-workflows.js +71 -0
- package/dist/cli/register-workflows.js.map +1 -0
- package/dist/cli/registry.d.ts +14 -0
- package/dist/cli/registry.js +65 -0
- package/dist/cli/registry.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +146 -596
- package/dist/cli.js.map +1 -1
- package/dist/common.d.ts +12 -38
- package/dist/common.js +5 -11
- package/dist/common.js.map +1 -1
- package/dist/domain/authoring/shared/bracket.js +3 -3
- package/dist/domain/authoring/shared/bracket.js.map +1 -1
- package/dist/domain/authoring/v3/apply.js +3 -3
- package/dist/domain/authoring/v3/apply.js.map +1 -1
- package/dist/domain/authoring/v4/apply.js +6 -6
- package/dist/domain/authoring/v4/apply.js.map +1 -1
- package/dist/domain/authoring/v4/parser.js +2 -2
- package/dist/domain/authoring/v4/parser.js.map +1 -1
- package/dist/domain/authoring/v4/serializer.js +2 -2
- package/dist/domain/authoring/v4/serializer.js.map +1 -1
- package/dist/domain/ingest/assembler.d.ts +1 -0
- package/dist/domain/ingest/assembler.js +8 -2
- package/dist/domain/ingest/assembler.js.map +1 -1
- package/dist/domain/ingest/video-apply.js +6 -3
- package/dist/domain/ingest/video-apply.js.map +1 -1
- package/dist/domain/ingest/video-context.js +2 -2
- package/dist/domain/ingest/video-context.js.map +1 -1
- package/dist/domain/ingest/video-records.d.ts +6 -5
- package/dist/domain/ingest/video-serial-md.d.ts +6 -5
- package/dist/domain/ingest/video-serial-md.js +11 -4
- package/dist/domain/ingest/video-serial-md.js.map +1 -1
- package/dist/domain/script/dispatch.js +5 -7
- package/dist/domain/script/dispatch.js.map +1 -1
- package/dist/domain/script/shared.js +4 -6
- package/dist/domain/script/shared.js.map +1 -1
- package/dist/domain/script/v3/address.js +29 -38
- package/dist/domain/script/v3/address.js.map +1 -1
- package/dist/domain/script/v3/lookups.js +31 -32
- package/dist/domain/script/v3/lookups.js.map +1 -1
- package/dist/domain/script/v3/ordinal.js +4 -5
- package/dist/domain/script/v3/ordinal.js.map +1 -1
- package/dist/domain/script/v3/parse.js +3 -4
- package/dist/domain/script/v3/parse.js.map +1 -1
- package/dist/domain/script/v3/patch/helpers.js +6 -8
- package/dist/domain/script/v3/patch/helpers.js.map +1 -1
- package/dist/domain/script/v3/selector.js +6 -8
- package/dist/domain/script/v3/selector.js.map +1 -1
- package/dist/domain/script/v4/address.js +2 -3
- package/dist/domain/script/v4/address.js.map +1 -1
- package/dist/domain/script/v4/ids.js +6 -7
- package/dist/domain/script/v4/ids.js.map +1 -1
- package/dist/domain/script/v4/ordinal.js +4 -5
- package/dist/domain/script/v4/ordinal.js.map +1 -1
- package/dist/domain/script/v4/parse.js +3 -4
- package/dist/domain/script/v4/parse.js.map +1 -1
- package/dist/domain/script/v4/patch/apply.js +3 -3
- package/dist/domain/script/v4/patch/apply.js.map +1 -1
- package/dist/domain/script/v4/patch/helpers.js +3 -4
- package/dist/domain/script/v4/patch/helpers.js.map +1 -1
- package/dist/domain/script/v4/patch/ops-action.js +46 -49
- package/dist/domain/script/v4/patch/ops-action.js.map +1 -1
- package/dist/domain/script/v4/selector.js +2 -3
- package/dist/domain/script/v4/selector.js.map +1 -1
- package/dist/infra/ingest/video-discovery.js +7 -4
- package/dist/infra/ingest/video-discovery.js.map +1 -1
- package/dist/infra/script-output-store.js +6 -11
- package/dist/infra/script-output-store.js.map +1 -1
- package/dist/infra/script-working-copy.js +15 -16
- package/dist/infra/script-working-copy.js.map +1 -1
- package/dist/llm/config.js +3 -4
- package/dist/llm/config.js.map +1 -1
- package/dist/llm/router.js +6 -8
- package/dist/llm/router.js.map +1 -1
- package/dist/llm/tasks/ingest/text-normalize.js +3 -3
- package/dist/llm/tasks/ingest/text-normalize.js.map +1 -1
- package/dist/llm/tasks/ingest/video-serial.js +29 -22
- package/dist/llm/tasks/ingest/video-serial.js.map +1 -1
- package/dist/llm/tasks/schemas.js +5 -5
- package/dist/llm/tasks/schemas.js.map +1 -1
- package/dist/output.d.ts +2 -3
- package/dist/output.js +72 -109
- package/dist/output.js.map +1 -1
- package/dist/usecases/changelog.d.ts +2 -2
- package/dist/usecases/changelog.js +28 -36
- package/dist/usecases/changelog.js.map +1 -1
- package/dist/usecases/doctor.d.ts +2 -2
- package/dist/usecases/doctor.js +3 -5
- package/dist/usecases/doctor.js.map +1 -1
- package/dist/usecases/ingest/command.d.ts +2 -2
- package/dist/usecases/ingest/command.js +22 -5
- package/dist/usecases/ingest/command.js.map +1 -1
- package/dist/usecases/ingest/pass5-extract.js +5 -4
- package/dist/usecases/ingest/pass5-extract.js.map +1 -1
- package/dist/usecases/ingest/pass5-govern.js +13 -11
- package/dist/usecases/ingest/pass5-govern.js.map +1 -1
- package/dist/usecases/ingest/pipeline.js +19 -16
- package/dist/usecases/ingest/pipeline.js.map +1 -1
- package/dist/usecases/ingest/serial-govern.js +5 -4
- package/dist/usecases/ingest/serial-govern.js.map +1 -1
- package/dist/usecases/ingest/status.d.ts +2 -2
- package/dist/usecases/ingest/status.js +1 -1
- package/dist/usecases/ingest/status.js.map +1 -1
- package/dist/usecases/ingest/video-pipeline.js +23 -17
- package/dist/usecases/ingest/video-pipeline.js.map +1 -1
- package/dist/usecases/ingest/view-command.d.ts +2 -2
- package/dist/usecases/ingest/view-command.js +7 -6
- package/dist/usecases/ingest/view-command.js.map +1 -1
- package/dist/usecases/ingest/view-server.d.ts +2 -2
- package/dist/usecases/ingest/view-server.js +7 -5
- package/dist/usecases/ingest/view-server.js.map +1 -1
- package/dist/usecases/script/actions.d.ts +2 -2
- package/dist/usecases/script/actions.js +12 -13
- package/dist/usecases/script/actions.js.map +1 -1
- package/dist/usecases/script/actor.d.ts +2 -2
- package/dist/usecases/script/actor.js +3 -4
- package/dist/usecases/script/actor.js.map +1 -1
- package/dist/usecases/script/actors.d.ts +2 -2
- package/dist/usecases/script/actors.js +5 -5
- package/dist/usecases/script/actors.js.map +1 -1
- package/dist/usecases/script/add-actor.d.ts +2 -2
- package/dist/usecases/script/add-episode.d.ts +2 -2
- package/dist/usecases/script/add-location.d.ts +2 -2
- package/dist/usecases/script/add-prop.d.ts +2 -2
- package/dist/usecases/script/alias.d.ts +2 -2
- package/dist/usecases/script/alias.js +6 -8
- package/dist/usecases/script/alias.js.map +1 -1
- package/dist/usecases/script/assets.d.ts +2 -2
- package/dist/usecases/script/assets.js +15 -7
- package/dist/usecases/script/assets.js.map +1 -1
- package/dist/usecases/script/audit-assets.d.ts +2 -2
- package/dist/usecases/script/audit-assets.js +12 -15
- package/dist/usecases/script/audit-assets.js.map +1 -1
- package/dist/usecases/script/command-constraints.js +17 -18
- package/dist/usecases/script/command-constraints.js.map +1 -1
- package/dist/usecases/script/context.d.ts +2 -2
- package/dist/usecases/script/context.js +3 -4
- package/dist/usecases/script/context.js.map +1 -1
- package/dist/usecases/script/create.d.ts +2 -2
- package/dist/usecases/script/create.js +3 -4
- package/dist/usecases/script/create.js.map +1 -1
- package/dist/usecases/script/delete.d.ts +2 -2
- package/dist/usecases/script/delete.js +9 -12
- package/dist/usecases/script/delete.js.map +1 -1
- package/dist/usecases/script/describe.d.ts +2 -2
- package/dist/usecases/script/describe.js +6 -8
- package/dist/usecases/script/describe.js.map +1 -1
- package/dist/usecases/script/dialogue.d.ts +2 -2
- package/dist/usecases/script/dialogue.js +5 -6
- package/dist/usecases/script/dialogue.js.map +1 -1
- package/dist/usecases/script/do.d.ts +2 -2
- package/dist/usecases/script/do.js +63 -66
- package/dist/usecases/script/do.js.map +1 -1
- package/dist/usecases/script/emotion.d.ts +2 -2
- package/dist/usecases/script/emotion.js +3 -3
- package/dist/usecases/script/emotion.js.map +1 -1
- package/dist/usecases/script/episodes.d.ts +2 -2
- package/dist/usecases/script/episodes.js +5 -5
- package/dist/usecases/script/episodes.js.map +1 -1
- package/dist/usecases/script/export-authoring.d.ts +2 -2
- package/dist/usecases/script/export-authoring.js +26 -29
- package/dist/usecases/script/export-authoring.js.map +1 -1
- package/dist/usecases/script/extend.d.ts +2 -2
- package/dist/usecases/script/extend.js +22 -18
- package/dist/usecases/script/extend.js.map +1 -1
- package/dist/usecases/script/ids.d.ts +2 -2
- package/dist/usecases/script/ids.js +21 -17
- package/dist/usecases/script/ids.js.map +1 -1
- package/dist/usecases/script/importance.d.ts +2 -2
- package/dist/usecases/script/importance.js +3 -4
- package/dist/usecases/script/importance.js.map +1 -1
- package/dist/usecases/script/insert.d.ts +2 -2
- package/dist/usecases/script/insert.js +8 -10
- package/dist/usecases/script/insert.js.map +1 -1
- package/dist/usecases/script/issues.d.ts +2 -2
- package/dist/usecases/script/issues.js +10 -2
- package/dist/usecases/script/issues.js.map +1 -1
- package/dist/usecases/script/lib.d.ts +15 -9
- package/dist/usecases/script/lib.js +226 -166
- package/dist/usecases/script/lib.js.map +1 -1
- package/dist/usecases/script/locations.d.ts +2 -2
- package/dist/usecases/script/locations.js +5 -5
- package/dist/usecases/script/locations.js.map +1 -1
- package/dist/usecases/script/merge.d.ts +2 -2
- package/dist/usecases/script/merge.js +9 -12
- package/dist/usecases/script/merge.js.map +1 -1
- package/dist/usecases/script/move.d.ts +2 -2
- package/dist/usecases/script/move.js +6 -8
- package/dist/usecases/script/move.js.map +1 -1
- package/dist/usecases/script/parenthetical.d.ts +2 -2
- package/dist/usecases/script/parenthetical.js +9 -12
- package/dist/usecases/script/parenthetical.js.map +1 -1
- package/dist/usecases/script/props.d.ts +2 -2
- package/dist/usecases/script/props.js +5 -5
- package/dist/usecases/script/props.js.map +1 -1
- package/dist/usecases/script/refs.d.ts +2 -2
- package/dist/usecases/script/refs.js +23 -17
- package/dist/usecases/script/refs.js.map +1 -1
- package/dist/usecases/script/rename.d.ts +2 -2
- package/dist/usecases/script/rename.js +6 -8
- package/dist/usecases/script/rename.js.map +1 -1
- package/dist/usecases/script/replace.d.ts +2 -2
- package/dist/usecases/script/replace.js +6 -8
- package/dist/usecases/script/replace.js.map +1 -1
- package/dist/usecases/script/role.d.ts +2 -2
- package/dist/usecases/script/role.js +3 -4
- package/dist/usecases/script/role.js.map +1 -1
- package/dist/usecases/script/scenes.d.ts +2 -2
- package/dist/usecases/script/scenes.js +7 -5
- package/dist/usecases/script/scenes.js.map +1 -1
- package/dist/usecases/script/script-patch.d.ts +2 -2
- package/dist/usecases/script/script-patch.js +95 -112
- package/dist/usecases/script/script-patch.js.map +1 -1
- package/dist/usecases/script/script-validate.d.ts +2 -2
- package/dist/usecases/script/script-validate.js +11 -7
- package/dist/usecases/script/script-validate.js.map +1 -1
- package/dist/usecases/script/session.js +52 -63
- package/dist/usecases/script/session.js.map +1 -1
- package/dist/usecases/script/split.d.ts +2 -2
- package/dist/usecases/script/split.js +6 -8
- package/dist/usecases/script/split.js.map +1 -1
- package/dist/usecases/script/state-add.d.ts +2 -2
- package/dist/usecases/script/state-add.js +3 -4
- package/dist/usecases/script/state-add.js.map +1 -1
- package/dist/usecases/script/state-delete.d.ts +2 -2
- package/dist/usecases/script/state-delete.js +3 -4
- package/dist/usecases/script/state-delete.js.map +1 -1
- package/dist/usecases/script/state-rename.d.ts +2 -2
- package/dist/usecases/script/state-rename.js +3 -4
- package/dist/usecases/script/state-rename.js.map +1 -1
- package/dist/usecases/script/states.d.ts +2 -2
- package/dist/usecases/script/states.js +54 -27
- package/dist/usecases/script/states.js.map +1 -1
- package/dist/usecases/script/summary.d.ts +2 -2
- package/dist/usecases/script/summary.js +21 -2
- package/dist/usecases/script/summary.js.map +1 -1
- package/dist/usecases/script/synopsis-generate.d.ts +2 -2
- package/dist/usecases/script/synopsis-generate.js +38 -39
- package/dist/usecases/script/synopsis-generate.js.map +1 -1
- package/dist/usecases/script/synopsis.d.ts +2 -2
- package/dist/usecases/script/synopsis.js +9 -12
- package/dist/usecases/script/synopsis.js.map +1 -1
- package/dist/usecases/script/transition.d.ts +2 -2
- package/dist/usecases/script/transition.js +3 -4
- package/dist/usecases/script/transition.js.map +1 -1
- package/dist/usecases/script/type.d.ts +2 -2
- package/dist/usecases/script/type.js +3 -4
- package/dist/usecases/script/type.js.map +1 -1
- package/dist/usecases/script/v4/queries.d.ts +3 -2
- package/dist/usecases/script/v4/queries.js +43 -6
- package/dist/usecases/script/v4/queries.js.map +1 -1
- package/dist/usecases/script/working-copy.d.ts +4 -4
- package/dist/usecases/script/working-copy.js +96 -92
- package/dist/usecases/script/working-copy.js.map +1 -1
- package/dist/usecases/script/worldview.d.ts +2 -2
- package/dist/usecases/script/worldview.js +3 -4
- package/dist/usecases/script/worldview.js.map +1 -1
- package/dist/usecases/script/write-authoring.d.ts +2 -2
- package/dist/usecases/script/write-authoring.js +62 -81
- package/dist/usecases/script/write-authoring.js.map +1 -1
- package/dist/usecases/update.d.ts +2 -2
- package/dist/usecases/update.js +32 -47
- package/dist/usecases/update.js.map +1 -1
- package/package.json +1 -1
- package/skills/scriptctl/SKILL.md +46 -37
- package/skills/scriptctl/references/atomic-edit-workflow.md +6 -6
- package/skills/scriptctl/references/ingest-workflow.md +20 -20
- package/skills/scriptctl/references/state-reference-repair.md +6 -6
- package/dist/help-text.d.ts +0 -2
- package/dist/help-text.js +0 -1144
- package/dist/help-text.js.map +0 -1
|
@@ -155,12 +155,11 @@ export function parseDoLine(tokens) {
|
|
|
155
155
|
return { verb, args, flags };
|
|
156
156
|
}
|
|
157
157
|
export function doErr(detail) {
|
|
158
|
-
return new CliError(
|
|
158
|
+
return new CliError(detail, {
|
|
159
159
|
exitCode: EXIT_USAGE,
|
|
160
|
-
required: ["a valid <verb> ...args... line"],
|
|
161
|
-
received: [detail],
|
|
162
|
-
nextSteps: ["Each line is a scriptctl verb minus the leading `scriptctl`; see `scriptctl do --help`."],
|
|
163
160
|
errorCode: "DO_LINE_INVALID",
|
|
161
|
+
hint: "Each line is a scriptctl verb minus the leading `scriptctl`; see `scriptctl do --help`.",
|
|
162
|
+
data: { expected: ["a valid <verb> ...args... line"], actual: [detail] },
|
|
164
163
|
});
|
|
165
164
|
}
|
|
166
165
|
// ---- shared op-template builders ------------------------------------------
|
|
@@ -172,36 +171,46 @@ export function stateChangeTemplate(target, f) {
|
|
|
172
171
|
const toSet = f.to !== undefined;
|
|
173
172
|
const clearSet = Boolean(f.clear);
|
|
174
173
|
if (toSet && clearSet) {
|
|
175
|
-
throw new CliError("
|
|
176
|
-
exitCode: EXIT_USAGE,
|
|
177
|
-
|
|
174
|
+
throw new CliError("state-change: --to and --clear are mutually exclusive.", {
|
|
175
|
+
exitCode: EXIT_USAGE,
|
|
176
|
+
errorCode: "STATE_CHANGE_FLAG_CONFLICT",
|
|
177
|
+
hint: "Pick one and retry.",
|
|
178
|
+
data: { expected: ["exactly one of --to <state> / --clear"], actual: ["--to", "--clear"] },
|
|
178
179
|
});
|
|
179
180
|
}
|
|
180
181
|
if (!toSet && !clearSet) {
|
|
181
|
-
throw new CliError("
|
|
182
|
-
exitCode: EXIT_USAGE,
|
|
183
|
-
|
|
182
|
+
throw new CliError("state-change: must specify --to <state> or --clear.", {
|
|
183
|
+
exitCode: EXIT_USAGE,
|
|
184
|
+
errorCode: "STATE_CHANGE_FLAG_MISSING",
|
|
185
|
+
hint: "Pick exactly one flag.",
|
|
186
|
+
data: { expected: ["one of --to <state> / --clear"], actual: ["<missing>"] },
|
|
184
187
|
});
|
|
185
188
|
}
|
|
186
189
|
// v3 has no per-action state_changes; state lives on scene.ref.* only.
|
|
187
|
-
throw new CliError("
|
|
188
|
-
exitCode: EXIT_USAGE,
|
|
189
|
-
|
|
190
|
+
throw new CliError("state-change was removed in v3; set a scene ref's state instead.", {
|
|
191
|
+
exitCode: EXIT_USAGE,
|
|
192
|
+
errorCode: "STATE_CHANGE_REMOVED",
|
|
193
|
+
hint: "Use `scene-ref <ep/scn> <kind:id> --state <state_id>` (op scene.ref.set).",
|
|
194
|
+
data: { expected: ["scene-ref state edit"], actual: ["state-change"] },
|
|
190
195
|
});
|
|
191
196
|
}
|
|
192
197
|
export function transitionTemplate(target, f) {
|
|
193
198
|
const setBoth = f.process !== undefined || f.contrast !== undefined;
|
|
194
199
|
const clearSet = Boolean(f.clear);
|
|
195
200
|
if (setBoth && clearSet) {
|
|
196
|
-
throw new CliError("
|
|
197
|
-
exitCode: EXIT_USAGE,
|
|
198
|
-
|
|
201
|
+
throw new CliError("transition: --clear is mutually exclusive with --process/--contrast.", {
|
|
202
|
+
exitCode: EXIT_USAGE,
|
|
203
|
+
errorCode: "TRANSITION_FLAG_CONFLICT",
|
|
204
|
+
hint: "Pick one mode and retry.",
|
|
205
|
+
data: { expected: ["either --clear, or --process + --contrast"], actual: ["--clear", "--process/--contrast"] },
|
|
199
206
|
});
|
|
200
207
|
}
|
|
201
208
|
if (!setBoth && !clearSet) {
|
|
202
|
-
throw new CliError("
|
|
203
|
-
exitCode: EXIT_USAGE,
|
|
204
|
-
|
|
209
|
+
throw new CliError("transition: must specify --process/--contrast or --clear.", {
|
|
210
|
+
exitCode: EXIT_USAGE,
|
|
211
|
+
errorCode: "TRANSITION_FLAG_MISSING",
|
|
212
|
+
hint: "Pick exactly one mode.",
|
|
213
|
+
data: { expected: ["--process + --contrast, or --clear"], actual: ["<missing>"] },
|
|
205
214
|
});
|
|
206
215
|
}
|
|
207
216
|
return clearSet
|
|
@@ -212,15 +221,19 @@ export function emotionTemplate(f) {
|
|
|
212
221
|
const emotionSet = f.emotion !== undefined;
|
|
213
222
|
const clearSet = Boolean(f.clear);
|
|
214
223
|
if (emotionSet && clearSet) {
|
|
215
|
-
throw new CliError("
|
|
216
|
-
exitCode: EXIT_USAGE,
|
|
217
|
-
|
|
224
|
+
throw new CliError("emotion: value and --clear are mutually exclusive.", {
|
|
225
|
+
exitCode: EXIT_USAGE,
|
|
226
|
+
errorCode: "EMOTION_FLAG_CONFLICT",
|
|
227
|
+
hint: "Pick one mode and retry.",
|
|
228
|
+
data: { expected: ["either <emotion>, or --clear"], actual: ["<emotion>", "--clear"] },
|
|
218
229
|
});
|
|
219
230
|
}
|
|
220
231
|
if (!emotionSet && !clearSet) {
|
|
221
|
-
throw new CliError("
|
|
222
|
-
exitCode: EXIT_USAGE,
|
|
223
|
-
|
|
232
|
+
throw new CliError("emotion: must specify <emotion> or --clear.", {
|
|
233
|
+
exitCode: EXIT_USAGE,
|
|
234
|
+
errorCode: "EMOTION_VALUE_MISSING",
|
|
235
|
+
hint: "Pass an emotion label, or use --clear.",
|
|
236
|
+
data: { expected: ["<emotion>, or --clear"], actual: ["<missing>"] },
|
|
224
237
|
});
|
|
225
238
|
}
|
|
226
239
|
return clearSet
|
|
@@ -233,9 +246,11 @@ export function contextTemplate(target, f) {
|
|
|
233
246
|
const removeSet = Boolean(f.remove);
|
|
234
247
|
const n = (stateSet ? 1 : 0) + (clearSet ? 1 : 0) + (removeSet ? 1 : 0);
|
|
235
248
|
if (n === 0) {
|
|
236
|
-
throw new CliError("
|
|
237
|
-
exitCode: EXIT_USAGE,
|
|
238
|
-
|
|
249
|
+
throw new CliError("context: must specify --state X, --clear, or --remove.", {
|
|
250
|
+
exitCode: EXIT_USAGE,
|
|
251
|
+
errorCode: "CONTEXT_FLAG_MISSING",
|
|
252
|
+
hint: "Pick exactly one flag.",
|
|
253
|
+
data: { expected: ["one of --state <state_id> / --clear / --remove"], actual: ["<missing>"] },
|
|
239
254
|
});
|
|
240
255
|
}
|
|
241
256
|
if (n > 1) {
|
|
@@ -246,30 +261,30 @@ export function contextTemplate(target, f) {
|
|
|
246
261
|
passed.push("--clear");
|
|
247
262
|
if (removeSet)
|
|
248
263
|
passed.push("--remove");
|
|
249
|
-
throw new CliError("
|
|
250
|
-
exitCode: EXIT_USAGE,
|
|
251
|
-
|
|
264
|
+
throw new CliError("context: --state / --clear / --remove are mutually exclusive.", {
|
|
265
|
+
exitCode: EXIT_USAGE,
|
|
266
|
+
errorCode: "CONTEXT_FLAG_CONFLICT",
|
|
267
|
+
hint: "Pick one and retry.",
|
|
268
|
+
data: { expected: ["exactly one of --state / --clear / --remove"], actual: passed },
|
|
252
269
|
});
|
|
253
270
|
}
|
|
254
271
|
const append = Boolean(f.append);
|
|
255
272
|
const occurrenceRaw = strOf(f.occurrence).trim();
|
|
256
273
|
const occurrence = occurrenceRaw ? Number(occurrenceRaw) : undefined;
|
|
257
274
|
if (occurrence !== undefined && (!Number.isInteger(occurrence) || occurrence < 1)) {
|
|
258
|
-
throw new CliError("
|
|
275
|
+
throw new CliError("scene-ref: --occurrence must be a positive integer.", {
|
|
259
276
|
exitCode: EXIT_USAGE,
|
|
260
|
-
required: ["--occurrence <positive integer> (1-based)"],
|
|
261
|
-
received: [occurrenceRaw],
|
|
262
|
-
nextSteps: ["Use 1 for the first matching scene ref, 2 for the second, and so on."],
|
|
263
277
|
errorCode: "SCENE_REF_OCCURRENCE_INVALID",
|
|
278
|
+
hint: "Use 1 for the first matching scene ref, 2 for the second, and so on.",
|
|
279
|
+
data: { expected: ["--occurrence <positive integer> (1-based)"], actual: [occurrenceRaw] },
|
|
264
280
|
});
|
|
265
281
|
}
|
|
266
282
|
if (append && (!stateSet || occurrence !== undefined)) {
|
|
267
|
-
throw new CliError("
|
|
283
|
+
throw new CliError("scene-ref: --append requires --state and cannot be combined with --occurrence.", {
|
|
268
284
|
exitCode: EXIT_USAGE,
|
|
269
|
-
required: ["--state <state_id> --append"],
|
|
270
|
-
received: [append ? "--append" : "", occurrence !== undefined ? "--occurrence" : "", clearSet ? "--clear" : "", removeSet ? "--remove" : ""].filter(Boolean),
|
|
271
|
-
nextSteps: ["Append a new actor ref with --state <state_id> --append, or target an existing ref with --occurrence <n>."],
|
|
272
285
|
errorCode: "SCENE_REF_APPEND_FLAG_CONFLICT",
|
|
286
|
+
hint: "Append a new actor ref with --state <state_id> --append, or target an existing ref with --occurrence <n>.",
|
|
287
|
+
data: { expected: ["--state <state_id> --append"], actual: [append ? "--append" : "", occurrence !== undefined ? "--occurrence" : "", clearSet ? "--clear" : "", removeSet ? "--remove" : ""].filter(Boolean) },
|
|
273
288
|
});
|
|
274
289
|
}
|
|
275
290
|
if (removeSet)
|
|
@@ -285,30 +300,30 @@ export function dialogueTemplate(f) {
|
|
|
285
300
|
const speakerKind = strOf(f.kind).trim();
|
|
286
301
|
const label = strOf(f.label).trim();
|
|
287
302
|
if (actorId && speakerKind) {
|
|
288
|
-
throw new CliError("
|
|
303
|
+
throw new CliError("dialogue: --actor and --kind are mutually exclusive.", {
|
|
289
304
|
exitCode: EXIT_USAGE,
|
|
290
|
-
required: ["exactly one of --actor <actor_id> or --kind <non-actor kind>"],
|
|
291
|
-
received: ["--actor", "--kind"],
|
|
292
|
-
nextSteps: ["Keep --actor for a character, or --kind for a non-actor source."],
|
|
293
305
|
errorCode: "SPEAKER_AMBIGUOUS",
|
|
306
|
+
hint: "Keep --actor for a character, or --kind for a non-actor source.",
|
|
307
|
+
data: { expected: ["exactly one of --actor <actor_id> or --kind <non-actor kind>"], actual: ["--actor", "--kind"] },
|
|
294
308
|
});
|
|
295
309
|
}
|
|
296
310
|
if (actorId && label) {
|
|
297
|
-
throw new CliError("
|
|
311
|
+
throw new CliError("dialogue: --label is only valid with --kind.", {
|
|
298
312
|
exitCode: EXIT_USAGE,
|
|
299
|
-
required: ["omit --label with --actor, or pair --label with --kind"],
|
|
300
|
-
received: ["--actor", "--label"],
|
|
301
|
-
nextSteps: ["Remove --label for an actor line, or use --kind for a labeled non-actor source."],
|
|
302
313
|
errorCode: "SPEAKER_LABEL_WITHOUT_KIND",
|
|
314
|
+
hint: "Remove --label for an actor line, or use --kind for a labeled non-actor source.",
|
|
315
|
+
data: { expected: ["omit --label with --actor, or pair --label with --kind"], actual: ["--actor", "--label"] },
|
|
303
316
|
});
|
|
304
317
|
}
|
|
305
318
|
if (actorId)
|
|
306
319
|
return { op: "dialogue.speaker.set", actor_id: actorId };
|
|
307
320
|
if (speakerKind)
|
|
308
321
|
return { op: "dialogue.speaker.set", kind: speakerKind, label: label || undefined };
|
|
309
|
-
throw new CliError("
|
|
310
|
-
exitCode: EXIT_USAGE,
|
|
311
|
-
|
|
322
|
+
throw new CliError("dialogue: pass --actor <id> or --kind <system|broadcast|offscreen|group>.", {
|
|
323
|
+
exitCode: EXIT_USAGE,
|
|
324
|
+
errorCode: "DIALOGUE_SPEAKER_MISSING",
|
|
325
|
+
hint: "Set --actor for an actor line, or --kind for a non-actor line.",
|
|
326
|
+
data: { expected: ["--actor <actor_id> or --kind <non-actor kind>"], actual: ["<missing>"] },
|
|
312
327
|
});
|
|
313
328
|
}
|
|
314
329
|
// Translate one parsed verb line into a patch op dict (the SAME ops `patch`
|
|
@@ -863,10 +878,10 @@ function v4OperationTargets(operation) {
|
|
|
863
878
|
}
|
|
864
879
|
export function buildV4MutationPlan(session, operations, options = {}) {
|
|
865
880
|
if (session.version !== 4) {
|
|
866
|
-
throw new CliError("
|
|
881
|
+
throw new CliError("A v4 mutation plan requires Script v4.", {
|
|
867
882
|
exitCode: EXIT_USAGE,
|
|
868
883
|
errorCode: "V4_PLAN_VERSION_INVALID",
|
|
869
|
-
|
|
884
|
+
data: { actual: [`Script v${session.version}`] },
|
|
870
885
|
});
|
|
871
886
|
}
|
|
872
887
|
const original = requireScriptV4(session.script);
|
|
@@ -954,12 +969,11 @@ export function assertV4PlanHasExplicitNewIds(operations) {
|
|
|
954
969
|
if (!field || strOf(operation[field]).trim())
|
|
955
970
|
continue;
|
|
956
971
|
const idKind = field === "new_scene_id" ? "scene" : field.replace(/_id$/, "");
|
|
957
|
-
throw new CliError("
|
|
972
|
+
throw new CliError("Planned creation operations require an explicit candidate ID.", {
|
|
958
973
|
exitCode: EXIT_USAGE,
|
|
959
974
|
errorCode: "V4_PLAN_ID_REQUIRED",
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
nextSteps: [`Generate a candidate with \`scriptctl ids --kind ${idKind} --count 1\`, then include it in the operation.`],
|
|
975
|
+
hint: `Generate a candidate with \`scriptctl ids --kind ${idKind} --count 1\`, then include it in the operation.`,
|
|
976
|
+
data: { expected: [`${kind}.${field}`], actual: [`${kind}.${field}=<missing>`] },
|
|
963
977
|
});
|
|
964
978
|
}
|
|
965
979
|
}
|
|
@@ -969,11 +983,11 @@ export function assertV4PlanHasExplicitNewIds(operations) {
|
|
|
969
983
|
export async function applySingleScriptOpToSession(session, opts, op) {
|
|
970
984
|
const plan = strOf(opts["plan"]).trim();
|
|
971
985
|
if (plan) {
|
|
972
|
-
throw new CliError("
|
|
986
|
+
throw new CliError("Single-point writes do not use plan digests.", {
|
|
973
987
|
exitCode: EXIT_USAGE,
|
|
974
988
|
errorCode: "MULTI_PLAN_USAGE_INVALID",
|
|
975
|
-
|
|
976
|
-
|
|
989
|
+
hint: "Remove --plan from this single-point edit.",
|
|
990
|
+
data: { actual: [plan] },
|
|
977
991
|
});
|
|
978
992
|
}
|
|
979
993
|
return applyScriptOpsToSession(session, opts, [op]);
|
|
@@ -989,17 +1003,18 @@ export async function applyScriptOpsToSession(session, opts, operations) {
|
|
|
989
1003
|
// One outcome line: what changed + revision (remote) + validation verdict.
|
|
990
1004
|
const rev = session.remote ? `; rev ${newRevision}` : "";
|
|
991
1005
|
const resultLine = `${applied.join(", ")} applied${rev}; validation ${passed ? "passed" : "needs repair"}`;
|
|
1006
|
+
const issues = summarizeIssues(asList(validation["issues"]));
|
|
992
1007
|
const report = {
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1008
|
+
text: [resultLine, ...issues].join("\n"),
|
|
1009
|
+
data: {
|
|
1010
|
+
op: opName,
|
|
1011
|
+
changed: applied.length > 0,
|
|
1012
|
+
revision: session.remote ? newRevision : undefined,
|
|
1013
|
+
idempotent: session.remote ? idempotent : undefined,
|
|
1014
|
+
validation,
|
|
1015
|
+
issues,
|
|
1016
|
+
script_path: session.artifactLabel,
|
|
1017
|
+
},
|
|
1003
1018
|
};
|
|
1004
1019
|
return [report, passed ? EXIT_OK : EXIT_NEEDS_AGENT];
|
|
1005
1020
|
}
|
|
@@ -1010,32 +1025,32 @@ export async function applySingleScriptOp(opts, op) {
|
|
|
1010
1025
|
export function summarizeScriptOp(_script, op) {
|
|
1011
1026
|
const kind = strOf(op["op"]);
|
|
1012
1027
|
if (kind === "actor.add")
|
|
1013
|
-
return
|
|
1028
|
+
return `Added actor ${op["name"] || op["actor_name"]}${op["role_type"] ? ` (${op["role_type"]})` : ""}`;
|
|
1014
1029
|
if (kind === "location.add")
|
|
1015
|
-
return
|
|
1030
|
+
return `Added location ${op["name"] || op["location_name"]}`;
|
|
1016
1031
|
if (kind === "prop.add")
|
|
1017
|
-
return
|
|
1032
|
+
return `Added prop ${op["name"] || op["prop_name"]}`;
|
|
1018
1033
|
if (kind === "episode.add")
|
|
1019
|
-
return
|
|
1034
|
+
return `Added episode${op["episode_id"] ? ` ${op["episode_id"]}` : " (generated ID)"}${op["title"] ? `: ${op["title"]}` : ""}`;
|
|
1020
1035
|
if (kind === "meta.synopsis.set")
|
|
1021
|
-
return
|
|
1036
|
+
return "Updated script synopsis";
|
|
1022
1037
|
if (kind === "episode.synopsis.set")
|
|
1023
|
-
return
|
|
1038
|
+
return `Updated episode synopsis ${op["episode_id"] ?? op["target"] ?? op["at"]}`;
|
|
1024
1039
|
if (kind === "state.add")
|
|
1025
|
-
return
|
|
1040
|
+
return `Added state ${op["state_id"]}: ${op["name"] || op["state_name"]} to ${op["target"]}`;
|
|
1026
1041
|
if (kind === "importance.set")
|
|
1027
|
-
return
|
|
1042
|
+
return `Set ${op["target"]} importance to ${op["importance"]}`;
|
|
1028
1043
|
if (kind === "scene.ref.set")
|
|
1029
|
-
return
|
|
1044
|
+
return `Set reference ${op["target"]} on ${op["at"]}${op["state"] ? ` (state ${op["state"]})` : ""}`;
|
|
1030
1045
|
if (kind === "extend.set")
|
|
1031
|
-
return
|
|
1046
|
+
return `Set extend.${op["key"]} on ${op["at"]}`;
|
|
1032
1047
|
if (kind === "extend.clear")
|
|
1033
|
-
return op["key"] ?
|
|
1048
|
+
return op["key"] ? `Removed extend.${op["key"]} from ${op["at"]}` : `Cleared extend on ${op["at"]}`;
|
|
1034
1049
|
if (kind.startsWith("state."))
|
|
1035
|
-
return
|
|
1050
|
+
return `Applied ${kind}: ${op["target"]}`;
|
|
1036
1051
|
if (kind.startsWith("dialogue."))
|
|
1037
|
-
return
|
|
1038
|
-
return
|
|
1052
|
+
return `Applied ${kind}: ${op["at"]}`;
|
|
1053
|
+
return `Applied ${kind}`;
|
|
1039
1054
|
}
|
|
1040
1055
|
// Accept `/re/flags` as-is; wrap a bare pattern as `/pattern/` so
|
|
1041
1056
|
// `replace --regex --from '^\s*\[[^\]]*\]'` works without the user typing slashes.
|
|
@@ -1068,29 +1083,27 @@ export async function applySelectorEditsToSession(session, opts, template, verbL
|
|
|
1068
1083
|
const planDigest = planned?.digest ?? null;
|
|
1069
1084
|
const suppliedPlan = strOf(opts["plan"]).trim();
|
|
1070
1085
|
if (suppliedPlan && (!multiV4 || !apply)) {
|
|
1071
|
-
throw new CliError("
|
|
1086
|
+
throw new CliError("A plan digest is only accepted for a v4 multi-target apply.", {
|
|
1072
1087
|
exitCode: EXIT_USAGE,
|
|
1073
1088
|
errorCode: "MULTI_PLAN_USAGE_INVALID",
|
|
1074
|
-
|
|
1075
|
-
|
|
1089
|
+
hint: "Remove --plan, or apply the same v4 multi-target selection that produced the digest.",
|
|
1090
|
+
data: { actual: [suppliedPlan] },
|
|
1076
1091
|
});
|
|
1077
1092
|
}
|
|
1078
1093
|
if (multiV4 && apply && !suppliedPlan) {
|
|
1079
|
-
throw new CliError("
|
|
1094
|
+
throw new CliError("A v4 multi-target write requires its dry-run plan digest.", {
|
|
1080
1095
|
exitCode: EXIT_USAGE,
|
|
1081
1096
|
errorCode: "MULTI_PLAN_REQUIRED",
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
nextSteps: ["Run the same command without --apply, review the full plan, then retry with `--apply --plan <digest>`."],
|
|
1097
|
+
hint: "Run the same command without --apply, review the full plan, then retry with `--apply --plan <digest>`.",
|
|
1098
|
+
data: { expected: [planDigest ?? ""], actual: ["<missing>"] },
|
|
1085
1099
|
});
|
|
1086
1100
|
}
|
|
1087
1101
|
if (multiV4 && apply && suppliedPlan !== planDigest) {
|
|
1088
|
-
throw new CliError("
|
|
1102
|
+
throw new CliError("The supplied digest does not match the current targets and operations.", {
|
|
1089
1103
|
exitCode: EXIT_INPUT,
|
|
1090
1104
|
errorCode: "MULTI_PLAN_MISMATCH",
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
nextSteps: ["Review the newly computed dry-run plan, then apply its exact digest."],
|
|
1105
|
+
hint: "Review the newly computed dry-run plan, then apply its exact digest.",
|
|
1106
|
+
data: { expected: [planDigest ?? ""], actual: [suppliedPlan] },
|
|
1094
1107
|
});
|
|
1095
1108
|
}
|
|
1096
1109
|
const source = scriptSourceText(workspace);
|
|
@@ -1139,39 +1152,43 @@ export async function applySelectorEditsToSession(session, opts, template, verbL
|
|
|
1139
1152
|
const legacyIssueLines = legacyValidation === null
|
|
1140
1153
|
? []
|
|
1141
1154
|
: summarizeIssues(asList(legacyValidation["issues"]));
|
|
1155
|
+
const issues = plannedIssueLines ?? legacyIssueLines;
|
|
1156
|
+
const hint = refs.length === 0
|
|
1157
|
+
? "Widen the selection with --in, --grep, or predicates."
|
|
1158
|
+
: planDigest
|
|
1159
|
+
? `Run again with --apply --plan ${planDigest} to commit this exact plan.`
|
|
1160
|
+
: "Run again with --apply to commit.";
|
|
1161
|
+
const lines = [...blast, `validation: ${passed ? "would pass" : "would need repair"}; no write`, ...issues, hint];
|
|
1142
1162
|
const report = {
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
? "Widen the selection (--in / --grep / predicates)."
|
|
1161
|
-
: planDigest
|
|
1162
|
-
? `Re-run with --apply --plan ${planDigest} to commit this exact plan.`
|
|
1163
|
-
: "Re-run with --apply to commit."],
|
|
1163
|
+
text: lines.join("\n"),
|
|
1164
|
+
data: {
|
|
1165
|
+
op: `${opName}.dry-run`,
|
|
1166
|
+
changed: false,
|
|
1167
|
+
matched: refs.length,
|
|
1168
|
+
applied,
|
|
1169
|
+
skipped,
|
|
1170
|
+
issues,
|
|
1171
|
+
script_path: session.artifactLabel,
|
|
1172
|
+
...(planDigest ? {
|
|
1173
|
+
baseline: session.baselineHash,
|
|
1174
|
+
plan_digest: planDigest,
|
|
1175
|
+
operations,
|
|
1176
|
+
targets: refs,
|
|
1177
|
+
plan: planned?.plan,
|
|
1178
|
+
} : {}),
|
|
1179
|
+
},
|
|
1164
1180
|
};
|
|
1165
1181
|
return [report, passed ? EXIT_OK : EXIT_NEEDS_AGENT];
|
|
1166
1182
|
}
|
|
1167
1183
|
if (refs.length === 0) {
|
|
1168
1184
|
return [{
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1185
|
+
text: [...blast, "Widen the selection with --in, --grep, or predicates."].join("\n"),
|
|
1186
|
+
data: {
|
|
1187
|
+
op: opName,
|
|
1188
|
+
changed: false,
|
|
1189
|
+
matched: 0,
|
|
1190
|
+
script_path: session.artifactLabel,
|
|
1191
|
+
},
|
|
1175
1192
|
}, EXIT_OK];
|
|
1176
1193
|
}
|
|
1177
1194
|
const [newRevision, idempotent] = await saveScriptSession(session, opts, opName);
|
|
@@ -1179,23 +1196,28 @@ export async function applySelectorEditsToSession(session, opts, template, verbL
|
|
|
1179
1196
|
await syncValidationResult(session, validation, newRevision);
|
|
1180
1197
|
const passed = Boolean(validation["passed"]);
|
|
1181
1198
|
const rev = session.remote ? `; rev ${newRevision}` : "";
|
|
1199
|
+
const issues = summarizeIssues(asList(validation["issues"]));
|
|
1182
1200
|
const report = {
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1201
|
+
text: [...blast, `validation: ${passed ? "passed" : "needs repair"}${rev}`, ...issues].join("\n"),
|
|
1202
|
+
data: {
|
|
1203
|
+
op: opName,
|
|
1204
|
+
changed: applied > 0,
|
|
1205
|
+
matched: refs.length,
|
|
1206
|
+
applied,
|
|
1207
|
+
skipped,
|
|
1208
|
+
revision: session.remote ? newRevision : undefined,
|
|
1209
|
+
idempotent: session.remote ? idempotent : undefined,
|
|
1210
|
+
validation,
|
|
1211
|
+
issues,
|
|
1212
|
+
script_path: session.artifactLabel,
|
|
1213
|
+
...(planDigest ? {
|
|
1214
|
+
baseline: session.baselineHash,
|
|
1215
|
+
plan_digest: planDigest,
|
|
1216
|
+
operations,
|
|
1217
|
+
targets: refs,
|
|
1218
|
+
plan: planned?.plan,
|
|
1219
|
+
} : {}),
|
|
1220
|
+
},
|
|
1199
1221
|
};
|
|
1200
1222
|
return [report, passed ? EXIT_OK : EXIT_NEEDS_AGENT];
|
|
1201
1223
|
}
|
|
@@ -1209,7 +1231,7 @@ export { sortDeep };
|
|
|
1209
1231
|
// ===========================================================================
|
|
1210
1232
|
//
|
|
1211
1233
|
// Each command is a thin read-only wrapper around the underlying script
|
|
1212
|
-
// document. They all return a
|
|
1234
|
+
// document. They all return a CommandOutput shaped like inspect's existing output but
|
|
1213
1235
|
// without the `--target` flag — the verb itself encodes the target. Filters
|
|
1214
1236
|
// use `--in <addr>` (compose with the address parsers) plus per-target
|
|
1215
1237
|
// predicates (--name / --kind / --has / --grep / --context / --type / --actor
|
|
@@ -1260,12 +1282,11 @@ export function buildGrepMatcher(raw) {
|
|
|
1260
1282
|
if (m) {
|
|
1261
1283
|
const pattern = m[1];
|
|
1262
1284
|
if (isDangerousRegex(pattern)) {
|
|
1263
|
-
throw new CliError("
|
|
1285
|
+
throw new CliError("regex pattern has nested quantifiers (ReDoS risk) or exceeds the length limit.", {
|
|
1264
1286
|
exitCode: EXIT_USAGE,
|
|
1265
|
-
required: [`pattern length <= ${MAX_GREP_PATTERN_LEN}; no quantifier-on-group-with-internal-quantifier (e.g. (a+)+)`],
|
|
1266
|
-
received: [`length=${pattern.length}, sample=${pattern.slice(0, 80)}`],
|
|
1267
|
-
nextSteps: ["Rewrite the regex to avoid nested quantifiers, or use a literal substring (drop the /…/ wrapper)."],
|
|
1268
1287
|
errorCode: "REGEX_UNSAFE",
|
|
1288
|
+
hint: "Rewrite the regex to avoid nested quantifiers, or use a literal substring (drop the /…/ wrapper).",
|
|
1289
|
+
data: { expected: [`pattern length <= ${MAX_GREP_PATTERN_LEN}; no quantifier-on-group-with-internal-quantifier (e.g. (a+)+)`], actual: [`length=${pattern.length}, sample=${pattern.slice(0, 80)}`] },
|
|
1269
1290
|
});
|
|
1270
1291
|
}
|
|
1271
1292
|
try {
|
|
@@ -1281,15 +1302,22 @@ export function buildGrepMatcher(raw) {
|
|
|
1281
1302
|
}
|
|
1282
1303
|
return (hay) => hay.includes(raw);
|
|
1283
1304
|
}
|
|
1284
|
-
export function buildReport(op,
|
|
1305
|
+
export function buildReport(op, lines) {
|
|
1306
|
+
const outputLines = lines.length > 0 ? lines : ["No matches."];
|
|
1285
1307
|
return {
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1308
|
+
text: outputLines.join("\n"),
|
|
1309
|
+
data: {
|
|
1310
|
+
op,
|
|
1311
|
+
changed: false,
|
|
1312
|
+
},
|
|
1291
1313
|
};
|
|
1292
1314
|
}
|
|
1315
|
+
export function buildTableReport(op, lines, rowColumns, rows) {
|
|
1316
|
+
const report = buildReport(op, lines);
|
|
1317
|
+
report.data["row_columns"] = rowColumns;
|
|
1318
|
+
report.data["rows"] = rows;
|
|
1319
|
+
return report;
|
|
1320
|
+
}
|
|
1293
1321
|
// ----- summary --------------------------------------------------------------
|
|
1294
1322
|
export function synopsisPreview(text, limit) {
|
|
1295
1323
|
const oneLine = text.replace(/\s+/g, " ").trim();
|
|
@@ -1353,12 +1381,11 @@ export function resolveActionTargets(script, opts) {
|
|
|
1353
1381
|
// "state_changes" (underscore) passed the filter-missing guard but bypassed
|
|
1354
1382
|
// every concrete predicate, returning the whole script.
|
|
1355
1383
|
if (hasFilter && !HAS_FILTERS.has(hasFilter)) {
|
|
1356
|
-
throw new CliError("
|
|
1384
|
+
throw new CliError("--has value invalid.", {
|
|
1357
1385
|
exitCode: EXIT_USAGE,
|
|
1358
|
-
required: [`--has: one of ${[...HAS_FILTERS].join(", ")}`],
|
|
1359
|
-
received: [hasFilter],
|
|
1360
|
-
nextSteps: ["Use a supported --has value."],
|
|
1361
1386
|
errorCode: "HAS_FILTER_INVALID",
|
|
1387
|
+
hint: "Use a supported --has value.",
|
|
1388
|
+
data: { expected: [`--has: one of ${[...HAS_FILTERS].join(", ")}`], actual: [hasFilter] },
|
|
1362
1389
|
});
|
|
1363
1390
|
}
|
|
1364
1391
|
const grepMatcher = buildGrepMatcher(strOf(opts["grep"]));
|
|
@@ -1451,6 +1478,7 @@ export function assetAppearanceCounts(script, kind) {
|
|
|
1451
1478
|
}
|
|
1452
1479
|
export function listAssetsByKind(script, kind, opts) {
|
|
1453
1480
|
const lines = [];
|
|
1481
|
+
const rows = [];
|
|
1454
1482
|
const [key, idKey, nameKey] = (() => {
|
|
1455
1483
|
switch (kind) {
|
|
1456
1484
|
case "actor": return ["actors", "actor_id", "actor_name"];
|
|
@@ -1527,8 +1555,42 @@ export function listAssetsByKind(script, kind, opts) {
|
|
|
1527
1555
|
extra.push(`scenes=${scns}`, `episodes_count=${eps}${arc}`);
|
|
1528
1556
|
}
|
|
1529
1557
|
lines.push(`${kind} ${id}: ${name || "-"} ${extra.join(" ")}`);
|
|
1558
|
+
const seen = appearances?.get(id);
|
|
1559
|
+
rows.push({
|
|
1560
|
+
addr: `${kind}:${id}`,
|
|
1561
|
+
kind,
|
|
1562
|
+
id,
|
|
1563
|
+
name,
|
|
1564
|
+
aliases,
|
|
1565
|
+
importance,
|
|
1566
|
+
role,
|
|
1567
|
+
states,
|
|
1568
|
+
description_present: descPresent === "yes",
|
|
1569
|
+
...(appearances
|
|
1570
|
+
? {
|
|
1571
|
+
scenes: seen?.scenes ?? 0,
|
|
1572
|
+
episodes_count: seen?.episodes.size ?? 0,
|
|
1573
|
+
episodes: seen ? compactEpisodeRanges(seen.episodes) : "",
|
|
1574
|
+
}
|
|
1575
|
+
: {}),
|
|
1576
|
+
});
|
|
1530
1577
|
}
|
|
1531
|
-
return
|
|
1578
|
+
return {
|
|
1579
|
+
lines,
|
|
1580
|
+
rows,
|
|
1581
|
+
rowColumns: [
|
|
1582
|
+
"addr",
|
|
1583
|
+
"kind",
|
|
1584
|
+
"id",
|
|
1585
|
+
"name",
|
|
1586
|
+
"aliases",
|
|
1587
|
+
"importance",
|
|
1588
|
+
"role",
|
|
1589
|
+
"states",
|
|
1590
|
+
"description_present",
|
|
1591
|
+
...(appearances ? ["scenes", "episodes_count", "episodes"] : []),
|
|
1592
|
+
],
|
|
1593
|
+
};
|
|
1532
1594
|
}
|
|
1533
1595
|
export function splitSpeakerList(raw) {
|
|
1534
1596
|
if (Array.isArray(raw))
|
|
@@ -1544,15 +1606,14 @@ export function blankCreateReport(session, validation, idempotent) {
|
|
|
1544
1606
|
resultLines.push(`idempotent: ${String(idempotent).toLowerCase()}`);
|
|
1545
1607
|
}
|
|
1546
1608
|
return {
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
],
|
|
1609
|
+
text: resultLines.join("\n"),
|
|
1610
|
+
data: {
|
|
1611
|
+
op: "script.create",
|
|
1612
|
+
changed: true,
|
|
1613
|
+
validation,
|
|
1614
|
+
script_path: session.artifactLabel,
|
|
1615
|
+
...(session.remote ? { revision: session.revision, idempotent } : {}),
|
|
1616
|
+
},
|
|
1556
1617
|
};
|
|
1557
1618
|
}
|
|
1558
1619
|
// ----- add-* (register new entities) ----------------------------------------
|
|
@@ -1561,12 +1622,11 @@ export function blankCreateReport(session, validation, idempotent) {
|
|
|
1561
1622
|
export function requireNameArg(opts, verb, example) {
|
|
1562
1623
|
const args = asList(opts["_args"]);
|
|
1563
1624
|
if (args.length < 1) {
|
|
1564
|
-
throw new CliError(
|
|
1625
|
+
throw new CliError("Name missing.", {
|
|
1565
1626
|
exitCode: EXIT_USAGE,
|
|
1566
|
-
required: ["<name>"],
|
|
1567
|
-
received: ["<empty>"],
|
|
1568
|
-
nextSteps: [example],
|
|
1569
1627
|
errorCode: "ARGS_MISSING",
|
|
1628
|
+
hint: example,
|
|
1629
|
+
data: { expected: ["<name>"], actual: ["<empty>"] },
|
|
1570
1630
|
});
|
|
1571
1631
|
}
|
|
1572
1632
|
return args[0];
|