@lingjingai/scriptctl 0.49.11 → 0.49.14

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.
Files changed (88) hide show
  1. package/README.md +8 -5
  2. package/changes/0.49.12.md +13 -0
  3. package/changes/0.49.14.md +23 -0
  4. package/dist/cli.js +34 -1
  5. package/dist/cli.js.map +1 -1
  6. package/dist/common.d.ts +1 -4
  7. package/dist/common.js +1 -12
  8. package/dist/common.js.map +1 -1
  9. package/dist/domain/authoring/apply.d.ts +33 -0
  10. package/dist/domain/authoring/apply.js +708 -0
  11. package/dist/domain/authoring/apply.js.map +1 -0
  12. package/dist/domain/authoring/export.d.ts +7 -0
  13. package/dist/domain/authoring/export.js +85 -0
  14. package/dist/domain/authoring/export.js.map +1 -0
  15. package/dist/domain/authoring/parser.d.ts +3 -0
  16. package/dist/domain/authoring/parser.js +915 -0
  17. package/dist/domain/authoring/parser.js.map +1 -0
  18. package/dist/domain/authoring/serializer.d.ts +2 -0
  19. package/dist/domain/authoring/serializer.js +244 -0
  20. package/dist/domain/authoring/serializer.js.map +1 -0
  21. package/dist/domain/authoring/types.d.ts +87 -0
  22. package/dist/domain/authoring/types.js +2 -0
  23. package/dist/domain/authoring/types.js.map +1 -0
  24. package/dist/domain/ingest/apply-plan.d.ts +1 -1
  25. package/dist/domain/ingest/records.d.ts +3 -2
  26. package/dist/domain/ingest/records.js +2 -1
  27. package/dist/domain/ingest/records.js.map +1 -1
  28. package/dist/domain/ingest/serial-context.d.ts +1 -1
  29. package/dist/domain/ingest/validation.js +12 -2
  30. package/dist/domain/ingest/validation.js.map +1 -1
  31. package/dist/domain/ingest/video-apply.js +7 -9
  32. package/dist/domain/ingest/video-apply.js.map +1 -1
  33. package/dist/domain/script/address.js.map +1 -1
  34. package/dist/domain/script/lookups.d.ts +0 -1
  35. package/dist/domain/script/lookups.js +0 -9
  36. package/dist/domain/script/lookups.js.map +1 -1
  37. package/dist/domain/script/parse.d.ts +3 -0
  38. package/dist/domain/script/parse.js +165 -0
  39. package/dist/domain/script/parse.js.map +1 -0
  40. package/dist/domain/script/patch/apply.d.ts +1 -3
  41. package/dist/domain/script/patch/apply.js +5 -12
  42. package/dist/domain/script/patch/apply.js.map +1 -1
  43. package/dist/domain/script/patch/inline-speaker.js +2 -2
  44. package/dist/domain/script/patch/inline-speaker.js.map +1 -1
  45. package/dist/domain/script/patch/ops-action.js +3 -3
  46. package/dist/domain/script/patch/ops-action.js.map +1 -1
  47. package/dist/domain/script/patch/ops-asset.js +4 -5
  48. package/dist/domain/script/patch/ops-asset.js.map +1 -1
  49. package/dist/domain/script/patch/ops-meta.js.map +1 -1
  50. package/dist/domain/script/selector.js +1 -3
  51. package/dist/domain/script/selector.js.map +1 -1
  52. package/dist/domain/script/types.d.ts +123 -0
  53. package/dist/domain/script/types.js +9 -0
  54. package/dist/domain/script/types.js.map +1 -0
  55. package/dist/help-text.js +105 -0
  56. package/dist/help-text.js.map +1 -1
  57. package/dist/infra/converters.d.ts +0 -1
  58. package/dist/infra/converters.js +0 -29
  59. package/dist/infra/converters.js.map +1 -1
  60. package/dist/infra/script-working-copy.d.ts +1 -0
  61. package/dist/infra/script-working-copy.js +4 -1
  62. package/dist/infra/script-working-copy.js.map +1 -1
  63. package/dist/llm/tasks/ingest/asset-curate.d.ts +1 -1
  64. package/dist/llm/tasks/ingest/video-serial.js +2 -2
  65. package/dist/llm/tasks/ingest/video-serial.js.map +1 -1
  66. package/dist/llm/tasks/schemas.js +2 -2
  67. package/dist/llm/tasks/schemas.js.map +1 -1
  68. package/dist/usecases/doctor.js +0 -1
  69. package/dist/usecases/doctor.js.map +1 -1
  70. package/dist/usecases/script/do.js +2 -2
  71. package/dist/usecases/script/do.js.map +1 -1
  72. package/dist/usecases/script/export-authoring.d.ts +4 -0
  73. package/dist/usecases/script/export-authoring.js +305 -0
  74. package/dist/usecases/script/export-authoring.js.map +1 -0
  75. package/dist/usecases/script/ids.d.ts +3 -0
  76. package/dist/usecases/script/ids.js +101 -0
  77. package/dist/usecases/script/ids.js.map +1 -0
  78. package/dist/usecases/script/lib.js +1 -6
  79. package/dist/usecases/script/lib.js.map +1 -1
  80. package/dist/usecases/script/write-authoring.d.ts +3 -0
  81. package/dist/usecases/script/write-authoring.js +186 -0
  82. package/dist/usecases/script/write-authoring.js.map +1 -0
  83. package/package.json +2 -3
  84. package/skills/scriptctl/SKILL.md +40 -6
  85. package/skills/scriptctl/references/bulk-authoring.md +165 -0
  86. package/dist/domain/ingest/script-v3.d.ts +0 -94
  87. package/dist/domain/ingest/script-v3.js +0 -7
  88. package/dist/domain/ingest/script-v3.js.map +0 -1
@@ -1,9 +1,9 @@
1
1
  ---
2
2
  name: scriptctl
3
- description: "剧本 script.json 的本地读写 + 入库 CLI。远端剧本先 checkout 成工作副本,所有原子读写只改本地 script.json,完成后 publish 严格按 revision 入库;新增 op 无需新增业务 API。转剧本:ingest(txt/md/docx 或视频,产出 workspace/script.json)→ 标准化复核 view 自查 → publish。覆盖集/场/action/资产/state/scene-ref/结构调整/批量 do/patch/校验。剧本阶段做任何剧本相关读写、以及操作两个 script.json 之前都应加载。"
3
+ description: "剧本 script.json 的本地读写 + 入库 CLI。远端剧本先 checkout 成工作副本;完整剧集/场/正文区间用 export + 文件化 authoring + write plan/apply 批量创作或替换,细小精修用原子 verb/do;完成后 publish 严格按 revision 入库。也覆盖 ingest、查询、资产/state、校验。剧本阶段做任何剧本相关读写、以及操作两个 script.json 之前都应加载。"
4
4
  metadata:
5
- version: "0.24.1"
6
- scriptctl_version: "0.49.11"
5
+ version: "0.25.0"
6
+ scriptctl_version: "0.49.14"
7
7
  author: "official"
8
8
  ---
9
9
 
@@ -11,9 +11,10 @@ metadata:
11
11
 
12
12
  `scriptctl` 读写结构化剧本 `script.json`,并把外部素材转成剧本、入库。查询和原子编辑始终作用于本地文件;远端只在 `checkout` / `publish` 边界访问。
13
13
 
14
- 两条主线:
14
+ 三条主线:
15
15
  - **转剧本入库**:`ingest`(抽取,产出 `workspace/script.json`)→ 标准化复核 → `view`(自查)→ `publish`(入库)。见 [references/ingest-workflow.md](references/ingest-workflow.md)。
16
- - **读写既有剧本**:查询 + 原子写 + 选择器批量 + `do`。
16
+ - **完整块创作/替换**:`ids` `.scriptctl` authoring 文件,或先 `export` 既有完整块 → `write` plan → `write --apply --plan <digest>`。
17
+ - **精修既有剧本**:查询 + 原子写 + 选择器批量 + `do`。
17
18
 
18
19
  ## 标准剧本通用流程:先把可引用世界建完整
19
20
 
@@ -47,7 +48,7 @@ location 表示可独立布置、可独立生成参考图、可重复引用的
47
48
 
48
49
  ## 先定本地文件
49
50
 
50
- - 查询、`create`、全部原子编辑、`do`、`patch` 只接受 `--script-path <file>`;省略时统一使用 `<cwd>/workspace/script.json`。
51
+ - 查询、`write`、`export`、`ids`、`create`、全部原子编辑、`do`、`patch` 只接受 `--script-path <file>`;省略时统一使用 `<cwd>/workspace/script.json`。
51
52
  - 编辑远端已有剧本:先 `scriptctl checkout [--script-path FILE]`,再对该文件运行任意原子命令,最后 `scriptctl publish [--script-path FILE]`。
52
53
  - `checkout` 会建立 `.scriptctl/<filename>.working-copy.json`,记录远端项目、API 地址、base revision 和语义内容 hash。已有未管理文件或有本地修改时拒绝覆盖;只有明确 `--discard-local` 才丢弃。
53
54
  - `status` 完全本地判断 managed / clean / dirty,不访问网络。
@@ -151,6 +152,39 @@ scriptctl emotion --in ep_003..ep_007 --actor act_001 "紧张" --apply
151
152
 
152
153
  > 先 discover 后 mutate 用**同一套 flag**:`scriptctl actions --in … --actor …` 查出来是哪些,换个动词就改哪些。`actions --json` 带结构化 `rows[]`,`actions … --format addr` 直接吐裸地址流喂 `xargs`。scene-ref/importance/dialogue 是**单点**动词,不进选择器批量。
153
154
 
155
+ ### 完整块批量创作与替换(`export` → authoring 文件 → `write`)
156
+
157
+ 写一整本、整集、整场,或替换中间连续几集/几场/几条 action 时,使用 `.scriptctl` authoring 文件,不把结构化 JSON 直接交给模型写。完整语法与约束见 [references/bulk-authoring.md](references/bulk-authoring.md)。
158
+
159
+ ```bash
160
+ # 先取候选 ID;只读、不预留
161
+ scriptctl ids --kind actor --count 2 --script-path workspace/script.json
162
+ scriptctl ids --kind scene --count 4 --script-path workspace/script.json
163
+
164
+ # 改既有第 2-4 集:先导出完整块,再让模型只改导出文件
165
+ scriptctl export episodes --in "ep_002..ep_004" \
166
+ --output rewrite.scriptctl --script-path workspace/script.json
167
+
168
+ # 默认只生成完整计划,不写
169
+ scriptctl write rewrite.scriptctl --replace --script-path workspace/script.json
170
+
171
+ # 读取计划里的 plan_digest,原样带回;任何源文件、mode、目标或本地剧本变化都会使它失效
172
+ scriptctl write rewrite.scriptctl --replace --apply --plan sha256:... \
173
+ --script-path workspace/script.json
174
+ ```
175
+
176
+ 目标选择:
177
+
178
+ | 需求 | 导出/authoring target | mode |
179
+ |---|---|---|
180
+ | 从零创建整本 | `export script` 作为模板,或直接写 `<script>` | `--create` |
181
+ | 追加完整集/场 | `<episode>` / `<scene parent=...>` | `--create` |
182
+ | 一对一替换多集/多场 | `export episodes` / `export scenes` | `--replace` |
183
+ | 用不同数量节点替换连续几集/几场 | `export episode-spans` / `export scene-spans` | `--replace` |
184
+ | 替换某场中间连续 action | `export action-spans` | `--replace` |
185
+
186
+ 一个 authoring 文件只有一种 target kind。scene span 的每个区间只能在同一 episode;action span 只能在同一 scene。区间端点按当前数组顺序判断,不按 ID 数字判断;新 ID 可以放在 replacement 内容中,但不能当旧区间端点。所有 span 都必须有非空 replacement。`write` 每次都持有本地独占锁,应用时还校验计划绑定的语义基线并用临时文件原子替换。
187
+
154
188
  ### 异构批量 `do`(一组各不相同的改动 = 一段动词脚本 = 一个事务)
155
189
 
156
190
  每行就是一条**去掉 `scriptctl` 的命令**,`#` 注释、空行随意;整段全成或全不成。比手写 patch JSON 省心(动词原样,不猜字段名)。
@@ -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`。不支持注释或自由散文行。
@@ -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"}