@lingjingai/scriptctl 0.60.13 → 0.61.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/changes/0.61.0.md +19 -0
- package/dist/cli/register-script.d.ts +3 -0
- package/dist/cli/register-script.js +256 -0
- package/dist/cli/register-script.js.map +1 -0
- package/dist/cli/register-workflows.js +37 -42
- package/dist/cli/register-workflows.js.map +1 -1
- package/dist/cli.js +2 -6
- package/dist/cli.js.map +1 -1
- package/dist/domain/ingest/environment.d.ts +2 -3
- package/dist/domain/ingest/environment.js +1 -4
- package/dist/domain/ingest/environment.js.map +1 -1
- package/dist/domain/script/names.d.ts +1 -1
- package/dist/domain/script/names.js +1 -3
- package/dist/domain/script/names.js.map +1 -1
- package/dist/domain/script/shared/types.d.ts +1 -18
- package/dist/domain/script/shared/types.js +4 -8
- package/dist/domain/script/shared/types.js.map +1 -1
- package/dist/domain/script/shared/validation.d.ts +1 -12
- package/dist/domain/script/shared/validation.js +2 -22
- package/dist/domain/script/shared/validation.js.map +1 -1
- package/dist/domain/script/timestamp.d.ts +1 -23
- package/dist/domain/script/timestamp.js +2 -126
- package/dist/domain/script/timestamp.js.map +1 -1
- package/dist/domain/script/v3/validation.d.ts +2 -3
- package/dist/domain/script/v3/validation.js +1 -232
- package/dist/domain/script/v3/validation.js.map +1 -1
- package/dist/domain/script/v4/ids.d.ts +2 -24
- package/dist/domain/script/v4/ids.js +19 -40
- package/dist/domain/script/v4/ids.js.map +1 -1
- package/dist/domain/script/v4/validation.d.ts +2 -2
- package/dist/domain/script/v4/validation.js +1 -410
- package/dist/domain/script/v4/validation.js.map +1 -1
- package/dist/usecases/script/action-span.d.ts +3 -19
- package/dist/usecases/script/action-span.js +19 -146
- package/dist/usecases/script/action-span.js.map +1 -1
- package/package.json +4 -3
- package/skills/scriptctl/SKILL.md +148 -214
- package/skills/scriptctl/references/ingest-workflow.md +1 -1
- package/skills/scriptctl/references/state-reference-repair.md +23 -19
- package/skills/scriptctl/references/video-transcript-repair.md +27 -29
- package/dist/cli/register-batch.d.ts +0 -3
- package/dist/cli/register-batch.js +0 -28
- package/dist/cli/register-batch.js.map +0 -1
- package/dist/cli/register-edits.d.ts +0 -4
- package/dist/cli/register-edits.js +0 -234
- package/dist/cli/register-edits.js.map +0 -1
- package/dist/cli/register-query.d.ts +0 -4
- package/dist/cli/register-query.js +0 -95
- package/dist/cli/register-query.js.map +0 -1
- package/skills/scriptctl/references/atomic-edit-workflow.md +0 -47
- package/skills/scriptctl/references/bulk-authoring.md +0 -50
|
@@ -1,162 +1,35 @@
|
|
|
1
|
+
// The span logic lives in `@lingjingai/screenplay` so the SDK's `span` tool and
|
|
2
|
+
// this command compute it from one definition. Only the error mapping onto
|
|
3
|
+
// scriptctl's CliError stays here.
|
|
1
4
|
import { CliError, EXIT_INPUT, EXIT_RUNTIME, } from "../../common.js";
|
|
2
|
-
import {
|
|
3
|
-
function actionTimestamp(extend) {
|
|
4
|
-
const timestamp = extend?.timestamp;
|
|
5
|
-
if (typeof timestamp !== "string")
|
|
6
|
-
return undefined;
|
|
7
|
-
const trimmed = timestamp.trim();
|
|
8
|
-
return trimmed || undefined;
|
|
9
|
-
}
|
|
5
|
+
import { SPAN_COLUMNS, parse, resolveSpan, spanPoints, } from "@lingjingai/screenplay";
|
|
10
6
|
export function actionSpanPointsV3(script) {
|
|
11
|
-
return
|
|
12
|
-
address: `${episode.episode_id}/${scene.scene_id}#${actionIndex}`,
|
|
13
|
-
episodeId: episode.episode_id,
|
|
14
|
-
episodeNo: episodeIndex + 1,
|
|
15
|
-
timestamp: actionTimestamp(action.extend),
|
|
16
|
-
}))));
|
|
7
|
+
return spanPoints(parse(script));
|
|
17
8
|
}
|
|
18
9
|
export function actionSpanPointsV4(script) {
|
|
19
|
-
return
|
|
20
|
-
address: action.action_id,
|
|
21
|
-
episodeId: episode.episode_id,
|
|
22
|
-
episodeNo: episodeIndex + 1,
|
|
23
|
-
timestamp: actionTimestamp(action.extend),
|
|
24
|
-
}))));
|
|
10
|
+
return spanPoints(parse(script));
|
|
25
11
|
}
|
|
26
|
-
|
|
12
|
+
// Only an inconsistent selection is our own bug; every other span failure is
|
|
13
|
+
// something the caller can fix in the script or the selector.
|
|
14
|
+
const RUNTIME_CODES = new Set(["ACTION_SPAN_SELECTION_INCONSISTENT"]);
|
|
15
|
+
export function resolveActionSpan(timeline, selectedAddresses) {
|
|
27
16
|
try {
|
|
28
|
-
return
|
|
17
|
+
return resolveSpan(timeline, selectedAddresses);
|
|
29
18
|
}
|
|
30
19
|
catch (error) {
|
|
31
|
-
|
|
20
|
+
const detail = error;
|
|
21
|
+
if (!detail?.code?.startsWith("ACTION_SPAN_"))
|
|
32
22
|
throw error;
|
|
33
|
-
throw new CliError(
|
|
34
|
-
exitCode: EXIT_INPUT,
|
|
35
|
-
errorCode:
|
|
36
|
-
hint
|
|
37
|
-
data: {
|
|
38
|
-
expected: ["valid action.extend.timestamp"],
|
|
39
|
-
actual: [`${point.address}: ${JSON.stringify(point.timestamp ?? "")}`],
|
|
40
|
-
},
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
function nonMonotonic(previous, current) {
|
|
45
|
-
throw new CliError("Action timestamps run backward within the selected episode.", {
|
|
46
|
-
exitCode: EXIT_INPUT,
|
|
47
|
-
errorCode: "ACTION_SPAN_TIMESTAMP_NON_MONOTONIC",
|
|
48
|
-
hint: "Fix the stored timestamps so they do not move backward in document order, then rerun `actions --span`.",
|
|
49
|
-
data: {
|
|
50
|
-
actual: [
|
|
51
|
-
`${previous.address}: ${previous.timestamp}`,
|
|
52
|
-
`${current.address}: ${current.timestamp}`,
|
|
53
|
-
],
|
|
54
|
-
},
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
export function resolveActionSpan(timeline, selectedAddresses) {
|
|
58
|
-
if (selectedAddresses.length === 0) {
|
|
59
|
-
throw new CliError("The action selection matched nothing.", {
|
|
60
|
-
exitCode: EXIT_INPUT,
|
|
61
|
-
errorCode: "ACTION_SPAN_NO_MATCH",
|
|
62
|
-
hint: "Check the selector with `scriptctl actions` and rerun with `--span`.",
|
|
63
|
-
data: { actual: ["0 matched actions"] },
|
|
23
|
+
throw new CliError(detail.message ?? "Action span failed.", {
|
|
24
|
+
exitCode: RUNTIME_CODES.has(detail.code) ? EXIT_RUNTIME : EXIT_INPUT,
|
|
25
|
+
errorCode: detail.code,
|
|
26
|
+
...(detail.hint ? { hint: detail.hint } : {}),
|
|
27
|
+
...(detail.data ? { data: detail.data } : {}),
|
|
64
28
|
});
|
|
65
29
|
}
|
|
66
|
-
const selectedSet = new Set(selectedAddresses);
|
|
67
|
-
const selected = timeline.filter((point) => selectedSet.has(point.address));
|
|
68
|
-
if (selected.length !== selectedSet.size) {
|
|
69
|
-
throw new CliError("The resolved action selection is inconsistent with the script timeline.", {
|
|
70
|
-
exitCode: EXIT_RUNTIME,
|
|
71
|
-
errorCode: "ACTION_SPAN_SELECTION_INCONSISTENT",
|
|
72
|
-
data: {
|
|
73
|
-
expected: [`${selectedSet.size} timeline actions`],
|
|
74
|
-
actual: [`${selected.length} timeline actions`],
|
|
75
|
-
},
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
const episodeIds = new Set(selected.map((point) => point.episodeId));
|
|
79
|
-
if (episodeIds.size !== 1) {
|
|
80
|
-
throw new CliError("An action timestamp span must stay within one episode.", {
|
|
81
|
-
exitCode: EXIT_INPUT,
|
|
82
|
-
errorCode: "ACTION_SPAN_CROSSES_EPISODES",
|
|
83
|
-
hint: "Split the selector into one `actions --span` call per episode.",
|
|
84
|
-
data: { actual: [...episodeIds] },
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
const first = selected[0];
|
|
88
|
-
const last = selected[selected.length - 1];
|
|
89
|
-
if (!first.timestamp) {
|
|
90
|
-
throw new CliError(`The first selected Action ${first.address} has no timestamp.`, {
|
|
91
|
-
exitCode: EXIT_INPUT,
|
|
92
|
-
errorCode: "ACTION_SPAN_START_TIMESTAMP_MISSING",
|
|
93
|
-
hint: `Set it with \`scriptctl timestamp ${first.address} --set <time>\`, then rerun.`,
|
|
94
|
-
data: { actual: [first.address] },
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
const start = parsePointTimestamp(first);
|
|
98
|
-
let previousStampedPoint = first;
|
|
99
|
-
let previousTimestamp = start;
|
|
100
|
-
let lastSelectedTimestamp = "";
|
|
101
|
-
for (const point of selected) {
|
|
102
|
-
if (!point.timestamp)
|
|
103
|
-
continue;
|
|
104
|
-
const timestamp = parsePointTimestamp(point);
|
|
105
|
-
if (timestamp.milliseconds < previousTimestamp.milliseconds) {
|
|
106
|
-
nonMonotonic(previousStampedPoint, point);
|
|
107
|
-
}
|
|
108
|
-
previousStampedPoint = point;
|
|
109
|
-
previousTimestamp = timestamp;
|
|
110
|
-
if (point.address === last.address)
|
|
111
|
-
lastSelectedTimestamp = timestamp.canonical;
|
|
112
|
-
}
|
|
113
|
-
const lastTimelineIndex = timeline.findIndex((point) => point.address === last.address);
|
|
114
|
-
let boundary;
|
|
115
|
-
let boundaryTimestamp;
|
|
116
|
-
for (let index = lastTimelineIndex + 1; index < timeline.length; index += 1) {
|
|
117
|
-
const candidate = timeline[index];
|
|
118
|
-
if (candidate.episodeId !== first.episodeId)
|
|
119
|
-
break;
|
|
120
|
-
if (!candidate.timestamp)
|
|
121
|
-
continue;
|
|
122
|
-
const timestamp = parsePointTimestamp(candidate);
|
|
123
|
-
if (timestamp.milliseconds < previousTimestamp.milliseconds) {
|
|
124
|
-
nonMonotonic(previousStampedPoint, candidate);
|
|
125
|
-
}
|
|
126
|
-
if (timestamp.milliseconds === previousTimestamp.milliseconds)
|
|
127
|
-
continue;
|
|
128
|
-
boundary = candidate;
|
|
129
|
-
boundaryTimestamp = timestamp;
|
|
130
|
-
break;
|
|
131
|
-
}
|
|
132
|
-
return {
|
|
133
|
-
episode_id: first.episodeId,
|
|
134
|
-
ep_no: first.episodeNo,
|
|
135
|
-
start_timestamp: start.canonical,
|
|
136
|
-
last_selected_timestamp: lastSelectedTimestamp,
|
|
137
|
-
end_timestamp: boundaryTimestamp?.canonical ?? "",
|
|
138
|
-
end_open: boundaryTimestamp === undefined,
|
|
139
|
-
end_exclusive: true,
|
|
140
|
-
start_action: first.address,
|
|
141
|
-
last_action: last.address,
|
|
142
|
-
end_boundary_action: boundary?.address ?? "",
|
|
143
|
-
matched_actions: selected.length,
|
|
144
|
-
};
|
|
145
30
|
}
|
|
146
31
|
export function actionSpanOutput(row) {
|
|
147
|
-
const rowColumns = [
|
|
148
|
-
"episode_id",
|
|
149
|
-
"ep_no",
|
|
150
|
-
"start_timestamp",
|
|
151
|
-
"last_selected_timestamp",
|
|
152
|
-
"end_timestamp",
|
|
153
|
-
"end_open",
|
|
154
|
-
"end_exclusive",
|
|
155
|
-
"start_action",
|
|
156
|
-
"last_action",
|
|
157
|
-
"end_boundary_action",
|
|
158
|
-
"matched_actions",
|
|
159
|
-
];
|
|
32
|
+
const rowColumns = [...SPAN_COLUMNS];
|
|
160
33
|
return {
|
|
161
34
|
text: rowColumns.map((column) => String(row[column])).join("\t"),
|
|
162
35
|
data: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action-span.js","sourceRoot":"","sources":["../../../src/usecases/script/action-span.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,UAAU,EACV,YAAY,GAEb,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,
|
|
1
|
+
{"version":3,"file":"action-span.js","sourceRoot":"","sources":["../../../src/usecases/script/action-span.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,2EAA2E;AAC3E,mCAAmC;AACnC,OAAO,EACL,QAAQ,EACR,UAAU,EACV,YAAY,GAEb,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,YAAY,EACZ,KAAK,EACL,WAAW,EACX,UAAU,GAGX,MAAM,wBAAwB,CAAC;AAOhC,MAAM,UAAU,kBAAkB,CAAC,MAAgB;IACjD,OAAO,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAAgB;IACjD,OAAO,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;AACnC,CAAC;AAED,6EAA6E;AAC7E,8DAA8D;AAC9D,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,oCAAoC,CAAC,CAAC,CAAC;AAEtE,MAAM,UAAU,iBAAiB,CAC/B,QAAoC,EACpC,iBAAoC;IAEpC,IAAI,CAAC;QACH,OAAO,WAAW,CAAC,QAAQ,EAAE,iBAAiB,CAAC,CAAC;IAClD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,MAAM,GAAG,KAA2E,CAAC;QAC3F,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,UAAU,CAAC,cAAc,CAAC;YAAE,MAAM,KAAK,CAAC;QAC3D,MAAM,IAAI,QAAQ,CAAC,MAAM,CAAC,OAAO,IAAI,qBAAqB,EAAE;YAC1D,QAAQ,EAAE,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU;YACpE,SAAS,EAAE,MAAM,CAAC,IAAI;YACtB,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7C,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAgC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1E,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,GAAkB;IACjD,MAAM,UAAU,GAAG,CAAC,GAAG,YAAY,CAAC,CAAC;IACrC,OAAO;QACL,IAAI,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QAChE,IAAI,EAAE;YACJ,EAAE,EAAE,mBAAmB;YACvB,WAAW,EAAE,UAAU;YACvB,IAAI,EAAE,CAAC,GAAG,CAAC;SACZ;KACF,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lingjingai/scriptctl",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.61.0",
|
|
4
4
|
"description": "剧本阶段统一 CLI:素材转 Script v4,并兼容 Script v3 的本地写作、精修、校验和发布。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
"node": ">=20"
|
|
20
20
|
},
|
|
21
21
|
"scripts": {
|
|
22
|
-
"build": "tsc",
|
|
23
|
-
"clean": "rm -rf dist",
|
|
22
|
+
"build": "pnpm --filter @lingjingai/screenplay build && tsc",
|
|
23
|
+
"clean": "rm -rf dist packages/screenplay/dist",
|
|
24
24
|
"postinstall": "node scripts/install-skill.mjs",
|
|
25
25
|
"install-skill": "node scripts/install-skill.mjs",
|
|
26
26
|
"prepublishOnly": "pnpm run clean && pnpm run build",
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@anthropic-ai/sdk": "^0.111.0",
|
|
37
37
|
"@google/genai": "^2.11.0",
|
|
38
|
+
"@lingjingai/screenplay": "workspace:*",
|
|
38
39
|
"commander": "^12.1.0",
|
|
39
40
|
"fast-json-patch": "^3.1.1",
|
|
40
41
|
"fast-xml-parser": "^5.9.0",
|