@lingjingai/scriptctl 0.49.10 → 0.49.13
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 +8 -5
- package/changes/0.49.11.md +13 -0
- package/changes/0.49.12.md +13 -0
- package/changes/unreleased.md +12 -3
- package/dist/cli.js +34 -1
- package/dist/cli.js.map +1 -1
- package/dist/common.d.ts +1 -4
- package/dist/common.js +1 -12
- package/dist/common.js.map +1 -1
- package/dist/domain/authoring/apply.d.ts +33 -0
- package/dist/domain/authoring/apply.js +717 -0
- package/dist/domain/authoring/apply.js.map +1 -0
- package/dist/domain/authoring/export.d.ts +7 -0
- package/dist/domain/authoring/export.js +85 -0
- package/dist/domain/authoring/export.js.map +1 -0
- package/dist/domain/authoring/parser.d.ts +3 -0
- package/dist/domain/authoring/parser.js +915 -0
- package/dist/domain/authoring/parser.js.map +1 -0
- package/dist/domain/authoring/serializer.d.ts +2 -0
- package/dist/domain/authoring/serializer.js +244 -0
- package/dist/domain/authoring/serializer.js.map +1 -0
- package/dist/domain/authoring/types.d.ts +87 -0
- package/dist/domain/authoring/types.js +2 -0
- package/dist/domain/authoring/types.js.map +1 -0
- package/dist/domain/ingest/apply-plan.d.ts +1 -1
- package/dist/domain/ingest/records.d.ts +3 -2
- package/dist/domain/ingest/records.js +2 -1
- package/dist/domain/ingest/records.js.map +1 -1
- package/dist/domain/ingest/serial-context.d.ts +1 -1
- package/dist/domain/ingest/validation.js +20 -2
- package/dist/domain/ingest/validation.js.map +1 -1
- package/dist/domain/ingest/video-apply.js +7 -9
- package/dist/domain/ingest/video-apply.js.map +1 -1
- package/dist/domain/script/address.js.map +1 -1
- package/dist/domain/script/lookups.d.ts +0 -1
- package/dist/domain/script/lookups.js +0 -9
- package/dist/domain/script/lookups.js.map +1 -1
- package/dist/domain/script/parse.d.ts +3 -0
- package/dist/domain/script/parse.js +165 -0
- package/dist/domain/script/parse.js.map +1 -0
- package/dist/domain/script/patch/apply.d.ts +1 -3
- package/dist/domain/script/patch/apply.js +5 -12
- package/dist/domain/script/patch/apply.js.map +1 -1
- package/dist/domain/script/patch/inline-speaker.js +2 -2
- package/dist/domain/script/patch/inline-speaker.js.map +1 -1
- package/dist/domain/script/patch/ops-action.js +3 -3
- package/dist/domain/script/patch/ops-action.js.map +1 -1
- package/dist/domain/script/patch/ops-asset.js +4 -5
- package/dist/domain/script/patch/ops-asset.js.map +1 -1
- package/dist/domain/script/patch/ops-meta.js.map +1 -1
- package/dist/domain/script/selector.js +1 -3
- package/dist/domain/script/selector.js.map +1 -1
- package/dist/domain/script/types.d.ts +123 -0
- package/dist/domain/script/types.js +9 -0
- package/dist/domain/script/types.js.map +1 -0
- package/dist/help-text.js +105 -0
- package/dist/help-text.js.map +1 -1
- package/dist/infra/converters.d.ts +0 -1
- package/dist/infra/converters.js +0 -29
- package/dist/infra/converters.js.map +1 -1
- package/dist/infra/script-working-copy.d.ts +1 -0
- package/dist/infra/script-working-copy.js +4 -1
- package/dist/infra/script-working-copy.js.map +1 -1
- package/dist/llm/tasks/ingest/asset-curate.d.ts +1 -1
- package/dist/llm/tasks/ingest/text-normalize.js +0 -21
- package/dist/llm/tasks/ingest/text-normalize.js.map +1 -1
- package/dist/llm/tasks/ingest/video-serial.js +2 -2
- package/dist/llm/tasks/ingest/video-serial.js.map +1 -1
- package/dist/llm/tasks/schemas.js +2 -2
- package/dist/llm/tasks/schemas.js.map +1 -1
- package/dist/usecases/doctor.js +0 -1
- package/dist/usecases/doctor.js.map +1 -1
- package/dist/usecases/ingest/pipeline.js +1 -1
- package/dist/usecases/script/do.js +2 -2
- package/dist/usecases/script/do.js.map +1 -1
- package/dist/usecases/script/export-authoring.d.ts +4 -0
- package/dist/usecases/script/export-authoring.js +305 -0
- package/dist/usecases/script/export-authoring.js.map +1 -0
- package/dist/usecases/script/ids.d.ts +3 -0
- package/dist/usecases/script/ids.js +101 -0
- package/dist/usecases/script/ids.js.map +1 -0
- package/dist/usecases/script/lib.js +1 -6
- package/dist/usecases/script/lib.js.map +1 -1
- package/dist/usecases/script/write-authoring.d.ts +3 -0
- package/dist/usecases/script/write-authoring.js +186 -0
- package/dist/usecases/script/write-authoring.js.map +1 -0
- package/package.json +2 -3
- package/skills/scriptctl/SKILL.md +41 -7
- package/skills/scriptctl/references/bulk-authoring.md +165 -0
- package/skills/scriptctl/references/state-reference-repair.md +2 -2
- package/dist/domain/ingest/script-v3.d.ts +0 -94
- package/dist/domain/ingest/script-v3.js +0 -7
- package/dist/domain/ingest/script-v3.js.map +0 -1
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# 文件化批量写作
|
|
2
|
+
|
|
3
|
+
这套接口给 LLM 直接生成和修改,不要求人编辑 JSON。authoring 文件使用 XML 风格块表达结构边界,块内使用 `[type|slot...] content` 行表达高密度字段。
|
|
4
|
+
|
|
5
|
+
## 固定工作流
|
|
6
|
+
|
|
7
|
+
1. 既有远端剧本先 `checkout` 到 `--script-path`。
|
|
8
|
+
2. 新 ID 用 `ids --kind ... --count ...` 查询候选值。它不预留 ID。
|
|
9
|
+
3. 修改既有内容先用 typed `export` 导出完整目标;从零写时直接生成完整 `.scriptctl` 文件。
|
|
10
|
+
4. `write FILE --create|--replace` 只做计划。
|
|
11
|
+
5. 从计划读取完整 `plan_digest`。
|
|
12
|
+
6. `write FILE --create|--replace --apply --plan DIGEST` 原子落盘。
|
|
13
|
+
7. `validate` 后按需 `publish`。
|
|
14
|
+
|
|
15
|
+
`write` 只接受命名文件,不读 stdin。digest 绑定源文件的精确字节、mode、解析后的正式目标和当前本地 Script v3 语义哈希。每次 plan/apply 均持有按 script 文件划分的独占锁;apply 在锁内重新校验基线。
|
|
16
|
+
|
|
17
|
+
## 根结构
|
|
18
|
+
|
|
19
|
+
```text
|
|
20
|
+
<authoring version=1>
|
|
21
|
+
|
|
22
|
+
<create>
|
|
23
|
+
...create-only asset/state declarations...
|
|
24
|
+
</create>
|
|
25
|
+
|
|
26
|
+
...one or more homogeneous targets...
|
|
27
|
+
|
|
28
|
+
</authoring>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`<create>` 可省略,但存在时只能有一个且必须在 targets 前。一个文件只能包含一种 target:
|
|
32
|
+
|
|
33
|
+
```text
|
|
34
|
+
<script>...</script>
|
|
35
|
+
<episode id=ep_007>...</episode>
|
|
36
|
+
<episode-span from=ep_002 through=ep_004>...</episode-span>
|
|
37
|
+
<scene id=scn_021 parent=ep_007>...</scene>
|
|
38
|
+
<scene-span parent=ep_007 from=scn_010 through=scn_012>...</scene-span>
|
|
39
|
+
<action-span parent=ep_007/scn_021 from=12 through=18>...</action-span>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
属性不加引号。script 只能有一个且 create-only。episode/scene 支持 create 或 replace。三种 span 都是 replace-only,端点包含两端,replacement 必须非空。
|
|
43
|
+
|
|
44
|
+
## create-only 声明
|
|
45
|
+
|
|
46
|
+
声明按 actor、location、prop 分组;每个新资产后立刻写它的 states,第一条且唯一常态 state 必须是 `default`。引用既有资产的 standalone state 放在所有资产声明之后。非 default `state_id` 全剧唯一。
|
|
47
|
+
|
|
48
|
+
```text
|
|
49
|
+
<create>
|
|
50
|
+
[aliases]
|
|
51
|
+
[alias] 门卫
|
|
52
|
+
[actor|act_010|王建国|featured|配角] 五十岁男性。
|
|
53
|
+
[state|actor:act_010|default|常态] 深蓝色保安制服。
|
|
54
|
+
[state|actor:act_010|st_010|雨衣] 黄色雨衣。
|
|
55
|
+
[location|loc_003|旧教室|featured] 墙皮脱落。
|
|
56
|
+
[state|location:loc_003|default|常态] 夜间无人使用。
|
|
57
|
+
[prop|prp_004|工作证|featured] 蓝色塑封证件。
|
|
58
|
+
[state|prop:prp_004|default|常态] 挂在胸前。
|
|
59
|
+
</create>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
重复提交完全相同的既有声明是 no-op;同 ID 不同定义是冲突。importance 只有 `featured|background`,actor role 只有 `主角|配角`。
|
|
63
|
+
`[aliases]` 表示正式 aliases 数组存在;后续零到多条 `[alias]` 保留顺序,因此空数组也能无损导出。
|
|
64
|
+
|
|
65
|
+
## script 与 episode
|
|
66
|
+
|
|
67
|
+
script metadata 固定顺序:
|
|
68
|
+
|
|
69
|
+
```text
|
|
70
|
+
<script>
|
|
71
|
+
[title] 剧名
|
|
72
|
+
[worldview] 现代
|
|
73
|
+
[worldview-raw] 可选原始世界观
|
|
74
|
+
[style] 悬疑
|
|
75
|
+
[synopsis] 可选全剧梗概
|
|
76
|
+
[logline] 可选一句话梗概
|
|
77
|
+
[theme] 可选主题
|
|
78
|
+
[main-characters]
|
|
79
|
+
[main-character|林夏|主角]
|
|
80
|
+
|
|
81
|
+
<episode id=ep_001>
|
|
82
|
+
[title] 第一集
|
|
83
|
+
[synopsis] 可选分集梗概
|
|
84
|
+
...scenes...
|
|
85
|
+
</episode>
|
|
86
|
+
</script>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
可选字段省略表示字段不存在;写成空 content 表示字段存在且值为空。
|
|
90
|
+
`[main-characters]` 表示正式数组存在,后续零到多条 main-character,因此空数组也能无损往返。
|
|
91
|
+
|
|
92
|
+
## scene
|
|
93
|
+
|
|
94
|
+
scene 成员固定为 environment、location、零到多条 cast、零到多条 prop、body。生产 scene 至少一条 action。每个非空 scene 引用都绑定具体 state。actor 引用允许重复并保留顺序;同一个 prop 不重复。
|
|
95
|
+
|
|
96
|
+
```text
|
|
97
|
+
<scene id=scn_021 parent=ep_007>
|
|
98
|
+
[environment|interior|night]
|
|
99
|
+
[location|loc_003|default]
|
|
100
|
+
[cast|act_001|st_before]
|
|
101
|
+
[cast|act_001|st_after]
|
|
102
|
+
[cast|act_010|default]
|
|
103
|
+
[prop|prp_004|default]
|
|
104
|
+
|
|
105
|
+
<body>
|
|
106
|
+
[act|紧张] 林夏拉开衣柜。
|
|
107
|
+
[dlg|act_001/st_after|压低声音] 谁在那里?
|
|
108
|
+
[think|act_001/st_after|不安] 不能让他发现。
|
|
109
|
+
[dlg|broadcast:] 不要回头。
|
|
110
|
+
[trans] 画面切黑。
|
|
111
|
+
</body>
|
|
112
|
+
</scene>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
嵌在 episode/scene-span 内的 scene 不写 parent;根 scene 必须写 parent。`location` 无槽位表示 `null`。非人物 speaker 是 `system|broadcast|offscreen|group`,可写 `kind:label`。普通写作不需要 `transition_prompt` 或 timestamp。
|
|
116
|
+
|
|
117
|
+
## prefix modifiers 与 extensions
|
|
118
|
+
|
|
119
|
+
modifier 必须紧贴其节点,顺序是零到多条 extend、零到多条 alias、最多一条 prompt:
|
|
120
|
+
|
|
121
|
+
```text
|
|
122
|
+
[extensions]
|
|
123
|
+
[extend|camera] {"lens":35,"locked":true}
|
|
124
|
+
[prompt|actor:act_001|换装|由校服变为礼服]
|
|
125
|
+
[act] 林夏拉开衣柜。
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
`[extensions]` 表示正式 extend 对象存在,后续零到多条 extend,因此缺失与空对象可无损区分。`extend` 的 content 是单个 JSON value,key 唯一;仅 extensions 使用 JSON。canonical serializer 按 key 排序。`prompt` 的 target/process/contrast 都必填,仅在确实存在显式过渡提示时使用。
|
|
129
|
+
|
|
130
|
+
## span
|
|
131
|
+
|
|
132
|
+
```text
|
|
133
|
+
<episode-span from=ep_002 through=ep_004>
|
|
134
|
+
...one or more complete episodes...
|
|
135
|
+
</episode-span>
|
|
136
|
+
|
|
137
|
+
<scene-span parent=ep_003 from=scn_010 through=scn_012>
|
|
138
|
+
...one or more complete scenes...
|
|
139
|
+
</scene-span>
|
|
140
|
+
|
|
141
|
+
<action-span parent=ep_003/scn_010 from=12 through=18>
|
|
142
|
+
<body>
|
|
143
|
+
...one or more actions...
|
|
144
|
+
</body>
|
|
145
|
+
</action-span>
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
episode/scene 端点按写入前本地脚本的真实数组位置解析,不比较 ID 数字。action index 零基且包含两端。一个文件中的多个 span 不得重叠,全部相对同一个写入前基线解析;replacement 数量可以与旧区间不同。action-span 只改 body,不改 scene refs。
|
|
149
|
+
|
|
150
|
+
## export
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
scriptctl export script --output story.scriptctl
|
|
154
|
+
scriptctl export episodes --in "ep_002..ep_004,ep_010" --output episodes.scriptctl
|
|
155
|
+
scriptctl export episode-spans --in "ep_002..ep_004" --output episode-span.scriptctl
|
|
156
|
+
scriptctl export scenes --in "ep_003/scn_010..ep_003/scn_012" --output scenes.scriptctl
|
|
157
|
+
scriptctl export scene-spans --in "ep_003/scn_010..ep_003/scn_012" --output scene-span.scriptctl
|
|
158
|
+
scriptctl export action-spans --in "ep_003/scn_010#12..ep_003/scn_010#18" --output actions.scriptctl
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
逗号分隔多个 point/range region。episodes/scenes 把区间展开成独立 targets;三种 span 命令的每个 region 产生一个 span target。跨 parent 的 scene/action span 直接拒绝。
|
|
162
|
+
|
|
163
|
+
## 转义
|
|
164
|
+
|
|
165
|
+
tag 属性只接受 canonical ID/address 字符,不需要转义。record header 中可用 `\|`、`\]`、`\\`、`\n`;content 中只用 `\\`、`\n`。不支持注释或自由散文行。
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
## 操作语义
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
合并 state 使用 `state-delete --strategy replace`,删除源 state 并替换引用:
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
12
|
# 合并:把 st_old 的引用全指向 st_keep,再删 st_old(replacement 必须是同一资产已存在的 state_id)
|
|
@@ -34,7 +34,7 @@ scriptctl refs actor:act_001/st_old
|
|
|
34
34
|
scriptctl state-delete actor:act_001/st_old --strategy replace --replacement st_keep
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
期望:`refs actor:act_001/st_old` 为空;`refs actor:act_001/st_keep`
|
|
37
|
+
期望:`refs actor:act_001/st_old` 为空;`refs actor:act_001/st_keep` 包含应迁移的场景引用;`scriptctl validate` 通过。
|
|
38
38
|
|
|
39
39
|
3. **真删除用 `remove`**:
|
|
40
40
|
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
export type SpeakerV3 = {
|
|
2
|
-
actor_id: string;
|
|
3
|
-
state_id?: string;
|
|
4
|
-
} | {
|
|
5
|
-
kind: "system" | "broadcast" | "offscreen" | "group";
|
|
6
|
-
label?: string;
|
|
7
|
-
};
|
|
8
|
-
export type Importance = "featured" | "background";
|
|
9
|
-
export declare const IMPORTANCE_TIERS: readonly ["featured", "background"];
|
|
10
|
-
export type TransitionPromptV3 = {
|
|
11
|
-
target: string;
|
|
12
|
-
process: string;
|
|
13
|
-
contrast: string;
|
|
14
|
-
};
|
|
15
|
-
export interface ActionV3 {
|
|
16
|
-
type: "action" | "dialogue" | "inner_thought" | "transition";
|
|
17
|
-
content: string;
|
|
18
|
-
speaker?: SpeakerV3;
|
|
19
|
-
emotion?: string;
|
|
20
|
-
transition_prompt?: TransitionPromptV3;
|
|
21
|
-
}
|
|
22
|
-
export type EntityRefV3 = {
|
|
23
|
-
actor_id: string;
|
|
24
|
-
state_id?: string;
|
|
25
|
-
} | {
|
|
26
|
-
prop_id: string;
|
|
27
|
-
state_id?: string;
|
|
28
|
-
};
|
|
29
|
-
export interface SceneV3 {
|
|
30
|
-
scene_id: string;
|
|
31
|
-
environment?: {
|
|
32
|
-
space?: string;
|
|
33
|
-
time?: string;
|
|
34
|
-
};
|
|
35
|
-
location: {
|
|
36
|
-
location_id: string;
|
|
37
|
-
state_id?: string;
|
|
38
|
-
} | null;
|
|
39
|
-
actors: {
|
|
40
|
-
actor_id: string;
|
|
41
|
-
state_id?: string;
|
|
42
|
-
}[];
|
|
43
|
-
props: {
|
|
44
|
-
prop_id: string;
|
|
45
|
-
state_id?: string;
|
|
46
|
-
}[];
|
|
47
|
-
actions: ActionV3[];
|
|
48
|
-
}
|
|
49
|
-
export interface EpisodeV3 {
|
|
50
|
-
episode_id: string;
|
|
51
|
-
title?: string;
|
|
52
|
-
scenes: SceneV3[];
|
|
53
|
-
}
|
|
54
|
-
export interface StateV3 {
|
|
55
|
-
state_id: string;
|
|
56
|
-
state_name: string;
|
|
57
|
-
description: string;
|
|
58
|
-
}
|
|
59
|
-
export interface ActorV3 {
|
|
60
|
-
actor_id: string;
|
|
61
|
-
actor_name: string;
|
|
62
|
-
importance: Importance;
|
|
63
|
-
role_type?: string;
|
|
64
|
-
aliases?: string[];
|
|
65
|
-
description: string;
|
|
66
|
-
states: StateV3[];
|
|
67
|
-
}
|
|
68
|
-
export interface LocationV3 {
|
|
69
|
-
location_id: string;
|
|
70
|
-
location_name: string;
|
|
71
|
-
importance: Importance;
|
|
72
|
-
aliases?: string[];
|
|
73
|
-
description: string;
|
|
74
|
-
states: StateV3[];
|
|
75
|
-
}
|
|
76
|
-
export interface PropV3 {
|
|
77
|
-
prop_id: string;
|
|
78
|
-
prop_name: string;
|
|
79
|
-
importance: Importance;
|
|
80
|
-
aliases?: string[];
|
|
81
|
-
description: string;
|
|
82
|
-
states: StateV3[];
|
|
83
|
-
}
|
|
84
|
-
export interface ScriptV3 {
|
|
85
|
-
version: 3;
|
|
86
|
-
title: string;
|
|
87
|
-
worldview: string;
|
|
88
|
-
style: string;
|
|
89
|
-
actors: ActorV3[];
|
|
90
|
-
locations: LocationV3[];
|
|
91
|
-
props: PropV3[];
|
|
92
|
-
episodes: EpisodeV3[];
|
|
93
|
-
}
|
|
94
|
-
export declare const NON_ACTOR_SPEAKER_KINDS: readonly ["system", "broadcast", "offscreen", "group", "minor"];
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
// Script schema v3 (§15.1, revised): content is plain text; scene-level cast and
|
|
2
|
-
// props carry materialized state. Kept ingest-local. Scripts remain plain JSON
|
|
3
|
-
// objects; these types document the shape the emitter writes and the validator
|
|
4
|
-
// enforces.
|
|
5
|
-
export const IMPORTANCE_TIERS = ["featured", "background"];
|
|
6
|
-
export const NON_ACTOR_SPEAKER_KINDS = ["system", "broadcast", "offscreen", "group", "minor"];
|
|
7
|
-
//# sourceMappingURL=script-v3.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"script-v3.js","sourceRoot":"","sources":["../../../src/domain/ingest/script-v3.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,+EAA+E;AAC/E,+EAA+E;AAC/E,YAAY;AASZ,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,UAAU,EAAE,YAAY,CAAU,CAAC;AAyCpE,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,CAAU,CAAC"}
|