@lingjingai/scriptctl 0.63.14 → 0.63.16

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 (781) hide show
  1. package/README.md +12 -1
  2. package/changes/0.63.15.md +15 -0
  3. package/dist/bin.js +1 -20844
  4. package/dist/chunk-YOCQDDQC.js +823 -0
  5. package/dist/cli.d.ts +214 -5
  6. package/dist/cli.js +1 -187
  7. package/dist/review-agent.js +60 -3593
  8. package/package.json +17 -9
  9. package/skills/scriptctl/SKILL.md +2 -0
  10. package/skills/scriptctl/references/ingest-workflow.md +4 -0
  11. package/skills/scriptctl/references/production-writing-standard.md +10 -1
  12. package/skills/scriptctl/references/state-reference-repair.md +8 -0
  13. package/dist/bin.d.ts +0 -2
  14. package/dist/bin.js.map +0 -7
  15. package/dist/cli/register-authoring.d.ts +0 -4
  16. package/dist/cli/register-authoring.js +0 -35
  17. package/dist/cli/register-authoring.js.map +0 -1
  18. package/dist/cli/register-review.d.ts +0 -3
  19. package/dist/cli/register-review.js +0 -20
  20. package/dist/cli/register-review.js.map +0 -1
  21. package/dist/cli/register-script.d.ts +0 -3
  22. package/dist/cli/register-script.js +0 -297
  23. package/dist/cli/register-script.js.map +0 -1
  24. package/dist/cli/register-tools.d.ts +0 -3
  25. package/dist/cli/register-tools.js +0 -23
  26. package/dist/cli/register-tools.js.map +0 -1
  27. package/dist/cli/register-workflows.d.ts +0 -4
  28. package/dist/cli/register-workflows.js +0 -108
  29. package/dist/cli/register-workflows.js.map +0 -1
  30. package/dist/cli/registry.d.ts +0 -14
  31. package/dist/cli/registry.js +0 -65
  32. package/dist/cli/registry.js.map +0 -1
  33. package/dist/cli.js.map +0 -1
  34. package/dist/common.d.ts +0 -93
  35. package/dist/common.js +0 -240
  36. package/dist/common.js.map +0 -1
  37. package/dist/domain/authoring/apply.d.ts +0 -1
  38. package/dist/domain/authoring/apply.js +0 -2
  39. package/dist/domain/authoring/apply.js.map +0 -1
  40. package/dist/domain/authoring/export.d.ts +0 -1
  41. package/dist/domain/authoring/export.js +0 -2
  42. package/dist/domain/authoring/export.js.map +0 -1
  43. package/dist/domain/authoring/parser.d.ts +0 -2
  44. package/dist/domain/authoring/parser.js +0 -3
  45. package/dist/domain/authoring/parser.js.map +0 -1
  46. package/dist/domain/authoring/serializer.d.ts +0 -1
  47. package/dist/domain/authoring/serializer.js +0 -2
  48. package/dist/domain/authoring/serializer.js.map +0 -1
  49. package/dist/domain/authoring/shared/bracket.d.ts +0 -4
  50. package/dist/domain/authoring/shared/bracket.js +0 -95
  51. package/dist/domain/authoring/shared/bracket.js.map +0 -1
  52. package/dist/domain/authoring/shared/types.d.ts +0 -12
  53. package/dist/domain/authoring/shared/types.js +0 -2
  54. package/dist/domain/authoring/shared/types.js.map +0 -1
  55. package/dist/domain/authoring/types.d.ts +0 -2
  56. package/dist/domain/authoring/types.js +0 -3
  57. package/dist/domain/authoring/types.js.map +0 -1
  58. package/dist/domain/authoring/v3/apply.d.ts +0 -33
  59. package/dist/domain/authoring/v3/apply.js +0 -784
  60. package/dist/domain/authoring/v3/apply.js.map +0 -1
  61. package/dist/domain/authoring/v3/export.d.ts +0 -7
  62. package/dist/domain/authoring/v3/export.js +0 -85
  63. package/dist/domain/authoring/v3/export.js.map +0 -1
  64. package/dist/domain/authoring/v3/parser.d.ts +0 -3
  65. package/dist/domain/authoring/v3/parser.js +0 -823
  66. package/dist/domain/authoring/v3/parser.js.map +0 -1
  67. package/dist/domain/authoring/v3/serializer.d.ts +0 -2
  68. package/dist/domain/authoring/v3/serializer.js +0 -244
  69. package/dist/domain/authoring/v3/serializer.js.map +0 -1
  70. package/dist/domain/authoring/v3/types.d.ts +0 -76
  71. package/dist/domain/authoring/v3/types.js +0 -2
  72. package/dist/domain/authoring/v3/types.js.map +0 -1
  73. package/dist/domain/authoring/v4/apply.d.ts +0 -40
  74. package/dist/domain/authoring/v4/apply.js +0 -451
  75. package/dist/domain/authoring/v4/apply.js.map +0 -1
  76. package/dist/domain/authoring/v4/parser.d.ts +0 -2
  77. package/dist/domain/authoring/v4/parser.js +0 -729
  78. package/dist/domain/authoring/v4/parser.js.map +0 -1
  79. package/dist/domain/authoring/v4/serializer.d.ts +0 -6
  80. package/dist/domain/authoring/v4/serializer.js +0 -280
  81. package/dist/domain/authoring/v4/serializer.js.map +0 -1
  82. package/dist/domain/authoring/v4/types.d.ts +0 -50
  83. package/dist/domain/authoring/v4/types.js +0 -2
  84. package/dist/domain/authoring/v4/types.js.map +0 -1
  85. package/dist/domain/creative-draft/compose.d.ts +0 -18
  86. package/dist/domain/creative-draft/compose.js +0 -448
  87. package/dist/domain/creative-draft/compose.js.map +0 -1
  88. package/dist/domain/ingest/apply-plan.d.ts +0 -23
  89. package/dist/domain/ingest/apply-plan.js +0 -210
  90. package/dist/domain/ingest/apply-plan.js.map +0 -1
  91. package/dist/domain/ingest/assembler.d.ts +0 -65
  92. package/dist/domain/ingest/assembler.js +0 -263
  93. package/dist/domain/ingest/assembler.js.map +0 -1
  94. package/dist/domain/ingest/asset-audit.d.ts +0 -50
  95. package/dist/domain/ingest/asset-audit.js +0 -196
  96. package/dist/domain/ingest/asset-audit.js.map +0 -1
  97. package/dist/domain/ingest/chunker.d.ts +0 -9
  98. package/dist/domain/ingest/chunker.js +0 -49
  99. package/dist/domain/ingest/chunker.js.map +0 -1
  100. package/dist/domain/ingest/environment.d.ts +0 -3
  101. package/dist/domain/ingest/environment.js +0 -32
  102. package/dist/domain/ingest/environment.js.map +0 -1
  103. package/dist/domain/ingest/evidence.d.ts +0 -5
  104. package/dist/domain/ingest/evidence.js +0 -66
  105. package/dist/domain/ingest/evidence.js.map +0 -1
  106. package/dist/domain/ingest/govern.d.ts +0 -3
  107. package/dist/domain/ingest/govern.js +0 -157
  108. package/dist/domain/ingest/govern.js.map +0 -1
  109. package/dist/domain/ingest/jsonl-parser.d.ts +0 -6
  110. package/dist/domain/ingest/jsonl-parser.js +0 -204
  111. package/dist/domain/ingest/jsonl-parser.js.map +0 -1
  112. package/dist/domain/ingest/markdown-parser.d.ts +0 -6
  113. package/dist/domain/ingest/markdown-parser.js +0 -187
  114. package/dist/domain/ingest/markdown-parser.js.map +0 -1
  115. package/dist/domain/ingest/production-validation.d.ts +0 -8
  116. package/dist/domain/ingest/production-validation.js +0 -37
  117. package/dist/domain/ingest/production-validation.js.map +0 -1
  118. package/dist/domain/ingest/records.d.ts +0 -72
  119. package/dist/domain/ingest/records.js +0 -10
  120. package/dist/domain/ingest/records.js.map +0 -1
  121. package/dist/domain/ingest/renumber.d.ts +0 -14
  122. package/dist/domain/ingest/renumber.js +0 -130
  123. package/dist/domain/ingest/renumber.js.map +0 -1
  124. package/dist/domain/ingest/serial-context.d.ts +0 -93
  125. package/dist/domain/ingest/serial-context.js +0 -355
  126. package/dist/domain/ingest/serial-context.js.map +0 -1
  127. package/dist/domain/ingest/state-identity.d.ts +0 -2
  128. package/dist/domain/ingest/state-identity.js +0 -3
  129. package/dist/domain/ingest/state-identity.js.map +0 -1
  130. package/dist/domain/ingest/state-reconcile.d.ts +0 -12
  131. package/dist/domain/ingest/state-reconcile.js +0 -92
  132. package/dist/domain/ingest/state-reconcile.js.map +0 -1
  133. package/dist/domain/ingest/validation.d.ts +0 -1
  134. package/dist/domain/ingest/validation.js +0 -2
  135. package/dist/domain/ingest/validation.js.map +0 -1
  136. package/dist/domain/ingest/video-apply.d.ts +0 -4
  137. package/dist/domain/ingest/video-apply.js +0 -128
  138. package/dist/domain/ingest/video-apply.js.map +0 -1
  139. package/dist/domain/ingest/video-context.d.ts +0 -64
  140. package/dist/domain/ingest/video-context.js +0 -480
  141. package/dist/domain/ingest/video-context.js.map +0 -1
  142. package/dist/domain/ingest/video-records.d.ts +0 -57
  143. package/dist/domain/ingest/video-records.js +0 -9
  144. package/dist/domain/ingest/video-records.js.map +0 -1
  145. package/dist/domain/ingest/video-serial-md.d.ts +0 -81
  146. package/dist/domain/ingest/video-serial-md.js +0 -297
  147. package/dist/domain/ingest/video-serial-md.js.map +0 -1
  148. package/dist/domain/ingest/video-source-evolution.d.ts +0 -25
  149. package/dist/domain/ingest/video-source-evolution.js +0 -40
  150. package/dist/domain/ingest/video-source-evolution.js.map +0 -1
  151. package/dist/domain/ingest/video-state-evidence.d.ts +0 -66
  152. package/dist/domain/ingest/video-state-evidence.js +0 -385
  153. package/dist/domain/ingest/video-state-evidence.js.map +0 -1
  154. package/dist/domain/ingest/video-timestamp.d.ts +0 -8
  155. package/dist/domain/ingest/video-timestamp.js +0 -26
  156. package/dist/domain/ingest/video-timestamp.js.map +0 -1
  157. package/dist/domain/loom/checkpointer.d.ts +0 -3
  158. package/dist/domain/loom/checkpointer.js +0 -30
  159. package/dist/domain/loom/checkpointer.js.map +0 -1
  160. package/dist/domain/loom/index.d.ts +0 -45
  161. package/dist/domain/loom/index.js +0 -277
  162. package/dist/domain/loom/index.js.map +0 -1
  163. package/dist/domain/loom/types.d.ts +0 -101
  164. package/dist/domain/loom/types.js +0 -2
  165. package/dist/domain/loom/types.js.map +0 -1
  166. package/dist/domain/script/address.d.ts +0 -1
  167. package/dist/domain/script/address.js +0 -2
  168. package/dist/domain/script/address.js.map +0 -1
  169. package/dist/domain/script/dispatch.d.ts +0 -18
  170. package/dist/domain/script/dispatch.js +0 -55
  171. package/dist/domain/script/dispatch.js.map +0 -1
  172. package/dist/domain/script/lookups.d.ts +0 -1
  173. package/dist/domain/script/lookups.js +0 -2
  174. package/dist/domain/script/lookups.js.map +0 -1
  175. package/dist/domain/script/migrations/registry.d.ts +0 -4
  176. package/dist/domain/script/migrations/registry.js +0 -76
  177. package/dist/domain/script/migrations/registry.js.map +0 -1
  178. package/dist/domain/script/migrations/types.d.ts +0 -17
  179. package/dist/domain/script/migrations/types.js +0 -2
  180. package/dist/domain/script/migrations/types.js.map +0 -1
  181. package/dist/domain/script/migrations/v3-to-v4.d.ts +0 -3
  182. package/dist/domain/script/migrations/v3-to-v4.js +0 -57
  183. package/dist/domain/script/migrations/v3-to-v4.js.map +0 -1
  184. package/dist/domain/script/names.d.ts +0 -1
  185. package/dist/domain/script/names.js +0 -2
  186. package/dist/domain/script/names.js.map +0 -1
  187. package/dist/domain/script/parse.d.ts +0 -1
  188. package/dist/domain/script/parse.js +0 -2
  189. package/dist/domain/script/parse.js.map +0 -1
  190. package/dist/domain/script/patch/apply.d.ts +0 -1
  191. package/dist/domain/script/patch/apply.js +0 -2
  192. package/dist/domain/script/patch/apply.js.map +0 -1
  193. package/dist/domain/script/patch/helpers.d.ts +0 -1
  194. package/dist/domain/script/patch/helpers.js +0 -2
  195. package/dist/domain/script/patch/helpers.js.map +0 -1
  196. package/dist/domain/script/patch/inline-speaker.d.ts +0 -1
  197. package/dist/domain/script/patch/inline-speaker.js +0 -2
  198. package/dist/domain/script/patch/inline-speaker.js.map +0 -1
  199. package/dist/domain/script/patch/ops-action.d.ts +0 -1
  200. package/dist/domain/script/patch/ops-action.js +0 -2
  201. package/dist/domain/script/patch/ops-action.js.map +0 -1
  202. package/dist/domain/script/patch/ops-asset.d.ts +0 -1
  203. package/dist/domain/script/patch/ops-asset.js +0 -2
  204. package/dist/domain/script/patch/ops-asset.js.map +0 -1
  205. package/dist/domain/script/patch/ops-dialogue.d.ts +0 -1
  206. package/dist/domain/script/patch/ops-dialogue.js +0 -2
  207. package/dist/domain/script/patch/ops-dialogue.js.map +0 -1
  208. package/dist/domain/script/patch/ops-extend.d.ts +0 -1
  209. package/dist/domain/script/patch/ops-extend.js +0 -2
  210. package/dist/domain/script/patch/ops-extend.js.map +0 -1
  211. package/dist/domain/script/patch/ops-meta.d.ts +0 -1
  212. package/dist/domain/script/patch/ops-meta.js +0 -2
  213. package/dist/domain/script/patch/ops-meta.js.map +0 -1
  214. package/dist/domain/script/patch/ops-scene.d.ts +0 -1
  215. package/dist/domain/script/patch/ops-scene.js +0 -2
  216. package/dist/domain/script/patch/ops-scene.js.map +0 -1
  217. package/dist/domain/script/patch/ops-state.d.ts +0 -1
  218. package/dist/domain/script/patch/ops-state.js +0 -2
  219. package/dist/domain/script/patch/ops-state.js.map +0 -1
  220. package/dist/domain/script/patch/registry.d.ts +0 -1
  221. package/dist/domain/script/patch/registry.js +0 -2
  222. package/dist/domain/script/patch/registry.js.map +0 -1
  223. package/dist/domain/script/patch/types.d.ts +0 -1
  224. package/dist/domain/script/patch/types.js +0 -2
  225. package/dist/domain/script/patch/types.js.map +0 -1
  226. package/dist/domain/script/refs.d.ts +0 -1
  227. package/dist/domain/script/refs.js +0 -2
  228. package/dist/domain/script/refs.js.map +0 -1
  229. package/dist/domain/script/scene-refs.d.ts +0 -1
  230. package/dist/domain/script/scene-refs.js +0 -2
  231. package/dist/domain/script/scene-refs.js.map +0 -1
  232. package/dist/domain/script/schema.d.ts +0 -1
  233. package/dist/domain/script/schema.js +0 -2
  234. package/dist/domain/script/schema.js.map +0 -1
  235. package/dist/domain/script/selector.d.ts +0 -1
  236. package/dist/domain/script/selector.js +0 -2
  237. package/dist/domain/script/selector.js.map +0 -1
  238. package/dist/domain/script/shared/regex.d.ts +0 -2
  239. package/dist/domain/script/shared/regex.js +0 -7
  240. package/dist/domain/script/shared/regex.js.map +0 -1
  241. package/dist/domain/script/shared/types.d.ts +0 -1
  242. package/dist/domain/script/shared/types.js +0 -5
  243. package/dist/domain/script/shared/types.js.map +0 -1
  244. package/dist/domain/script/shared/validation.d.ts +0 -1
  245. package/dist/domain/script/shared/validation.js +0 -3
  246. package/dist/domain/script/shared/validation.js.map +0 -1
  247. package/dist/domain/script/shared.d.ts +0 -15
  248. package/dist/domain/script/shared.js +0 -35
  249. package/dist/domain/script/shared.js.map +0 -1
  250. package/dist/domain/script/text-util.d.ts +0 -7
  251. package/dist/domain/script/text-util.js +0 -95
  252. package/dist/domain/script/text-util.js.map +0 -1
  253. package/dist/domain/script/timestamp.d.ts +0 -1
  254. package/dist/domain/script/timestamp.js +0 -3
  255. package/dist/domain/script/timestamp.js.map +0 -1
  256. package/dist/domain/script/types.d.ts +0 -1
  257. package/dist/domain/script/types.js +0 -2
  258. package/dist/domain/script/types.js.map +0 -1
  259. package/dist/domain/script/v3/address.d.ts +0 -32
  260. package/dist/domain/script/v3/address.js +0 -136
  261. package/dist/domain/script/v3/address.js.map +0 -1
  262. package/dist/domain/script/v3/lookups.d.ts +0 -33
  263. package/dist/domain/script/v3/lookups.js +0 -316
  264. package/dist/domain/script/v3/lookups.js.map +0 -1
  265. package/dist/domain/script/v3/ordinal.d.ts +0 -8
  266. package/dist/domain/script/v3/ordinal.js +0 -91
  267. package/dist/domain/script/v3/ordinal.js.map +0 -1
  268. package/dist/domain/script/v3/parse.d.ts +0 -3
  269. package/dist/domain/script/v3/parse.js +0 -164
  270. package/dist/domain/script/v3/parse.js.map +0 -1
  271. package/dist/domain/script/v3/patch/apply.d.ts +0 -2
  272. package/dist/domain/script/v3/patch/apply.js +0 -31
  273. package/dist/domain/script/v3/patch/apply.js.map +0 -1
  274. package/dist/domain/script/v3/patch/helpers.d.ts +0 -15
  275. package/dist/domain/script/v3/patch/helpers.js +0 -155
  276. package/dist/domain/script/v3/patch/helpers.js.map +0 -1
  277. package/dist/domain/script/v3/patch/inline-speaker.d.ts +0 -2
  278. package/dist/domain/script/v3/patch/inline-speaker.js +0 -50
  279. package/dist/domain/script/v3/patch/inline-speaker.js.map +0 -1
  280. package/dist/domain/script/v3/patch/ops-action.d.ts +0 -12
  281. package/dist/domain/script/v3/patch/ops-action.js +0 -355
  282. package/dist/domain/script/v3/patch/ops-action.js.map +0 -1
  283. package/dist/domain/script/v3/patch/ops-asset.d.ts +0 -14
  284. package/dist/domain/script/v3/patch/ops-asset.js +0 -347
  285. package/dist/domain/script/v3/patch/ops-asset.js.map +0 -1
  286. package/dist/domain/script/v3/patch/ops-dialogue.d.ts +0 -2
  287. package/dist/domain/script/v3/patch/ops-dialogue.js +0 -21
  288. package/dist/domain/script/v3/patch/ops-dialogue.js.map +0 -1
  289. package/dist/domain/script/v3/patch/ops-extend.d.ts +0 -8
  290. package/dist/domain/script/v3/patch/ops-extend.js +0 -122
  291. package/dist/domain/script/v3/patch/ops-extend.js.map +0 -1
  292. package/dist/domain/script/v3/patch/ops-meta.d.ts +0 -5
  293. package/dist/domain/script/v3/patch/ops-meta.js +0 -82
  294. package/dist/domain/script/v3/patch/ops-meta.js.map +0 -1
  295. package/dist/domain/script/v3/patch/ops-scene.d.ts +0 -6
  296. package/dist/domain/script/v3/patch/ops-scene.js +0 -351
  297. package/dist/domain/script/v3/patch/ops-scene.js.map +0 -1
  298. package/dist/domain/script/v3/patch/ops-state.d.ts +0 -8
  299. package/dist/domain/script/v3/patch/ops-state.js +0 -155
  300. package/dist/domain/script/v3/patch/ops-state.js.map +0 -1
  301. package/dist/domain/script/v3/patch/ops-timestamp.d.ts +0 -6
  302. package/dist/domain/script/v3/patch/ops-timestamp.js +0 -47
  303. package/dist/domain/script/v3/patch/ops-timestamp.js.map +0 -1
  304. package/dist/domain/script/v3/patch/registry.d.ts +0 -2
  305. package/dist/domain/script/v3/patch/registry.js +0 -56
  306. package/dist/domain/script/v3/patch/registry.js.map +0 -1
  307. package/dist/domain/script/v3/patch/types.d.ts +0 -10
  308. package/dist/domain/script/v3/patch/types.js +0 -2
  309. package/dist/domain/script/v3/patch/types.js.map +0 -1
  310. package/dist/domain/script/v3/refs.d.ts +0 -4
  311. package/dist/domain/script/v3/refs.js +0 -64
  312. package/dist/domain/script/v3/refs.js.map +0 -1
  313. package/dist/domain/script/v3/scene-refs.d.ts +0 -3
  314. package/dist/domain/script/v3/scene-refs.js +0 -35
  315. package/dist/domain/script/v3/scene-refs.js.map +0 -1
  316. package/dist/domain/script/v3/schema.d.ts +0 -6
  317. package/dist/domain/script/v3/schema.js +0 -58
  318. package/dist/domain/script/v3/schema.js.map +0 -1
  319. package/dist/domain/script/v3/selector.d.ts +0 -44
  320. package/dist/domain/script/v3/selector.js +0 -178
  321. package/dist/domain/script/v3/selector.js.map +0 -1
  322. package/dist/domain/script/v3/types.d.ts +0 -106
  323. package/dist/domain/script/v3/types.js +0 -2
  324. package/dist/domain/script/v3/types.js.map +0 -1
  325. package/dist/domain/script/v3/validation.d.ts +0 -2
  326. package/dist/domain/script/v3/validation.js +0 -2
  327. package/dist/domain/script/v3/validation.js.map +0 -1
  328. package/dist/domain/script/v4/address.d.ts +0 -61
  329. package/dist/domain/script/v4/address.js +0 -99
  330. package/dist/domain/script/v4/address.js.map +0 -1
  331. package/dist/domain/script/v4/factory.d.ts +0 -2
  332. package/dist/domain/script/v4/factory.js +0 -13
  333. package/dist/domain/script/v4/factory.js.map +0 -1
  334. package/dist/domain/script/v4/from-v3.d.ts +0 -29
  335. package/dist/domain/script/v4/from-v3.js +0 -307
  336. package/dist/domain/script/v4/from-v3.js.map +0 -1
  337. package/dist/domain/script/v4/ids.d.ts +0 -5
  338. package/dist/domain/script/v4/ids.js +0 -41
  339. package/dist/domain/script/v4/ids.js.map +0 -1
  340. package/dist/domain/script/v4/ordinal.d.ts +0 -3
  341. package/dist/domain/script/v4/ordinal.js +0 -66
  342. package/dist/domain/script/v4/ordinal.js.map +0 -1
  343. package/dist/domain/script/v4/parse.d.ts +0 -5
  344. package/dist/domain/script/v4/parse.js +0 -196
  345. package/dist/domain/script/v4/parse.js.map +0 -1
  346. package/dist/domain/script/v4/patch/apply.d.ts +0 -3
  347. package/dist/domain/script/v4/patch/apply.js +0 -24
  348. package/dist/domain/script/v4/patch/apply.js.map +0 -1
  349. package/dist/domain/script/v4/patch/helpers.d.ts +0 -32
  350. package/dist/domain/script/v4/patch/helpers.js +0 -138
  351. package/dist/domain/script/v4/patch/helpers.js.map +0 -1
  352. package/dist/domain/script/v4/patch/ops-action.d.ts +0 -13
  353. package/dist/domain/script/v4/patch/ops-action.js +0 -351
  354. package/dist/domain/script/v4/patch/ops-action.js.map +0 -1
  355. package/dist/domain/script/v4/patch/ops-asset.d.ts +0 -17
  356. package/dist/domain/script/v4/patch/ops-asset.js +0 -556
  357. package/dist/domain/script/v4/patch/ops-asset.js.map +0 -1
  358. package/dist/domain/script/v4/patch/ops-extend.d.ts +0 -11
  359. package/dist/domain/script/v4/patch/ops-extend.js +0 -103
  360. package/dist/domain/script/v4/patch/ops-extend.js.map +0 -1
  361. package/dist/domain/script/v4/patch/ops-meta.d.ts +0 -5
  362. package/dist/domain/script/v4/patch/ops-meta.js +0 -49
  363. package/dist/domain/script/v4/patch/ops-meta.js.map +0 -1
  364. package/dist/domain/script/v4/patch/ops-scene-ref.d.ts +0 -3
  365. package/dist/domain/script/v4/patch/ops-scene-ref.js +0 -74
  366. package/dist/domain/script/v4/patch/ops-scene-ref.js.map +0 -1
  367. package/dist/domain/script/v4/patch/ops-structure.d.ts +0 -6
  368. package/dist/domain/script/v4/patch/ops-structure.js +0 -236
  369. package/dist/domain/script/v4/patch/ops-structure.js.map +0 -1
  370. package/dist/domain/script/v4/patch/ops-timestamp.d.ts +0 -6
  371. package/dist/domain/script/v4/patch/ops-timestamp.js +0 -40
  372. package/dist/domain/script/v4/patch/ops-timestamp.js.map +0 -1
  373. package/dist/domain/script/v4/patch/registry.d.ts +0 -2
  374. package/dist/domain/script/v4/patch/registry.js +0 -53
  375. package/dist/domain/script/v4/patch/registry.js.map +0 -1
  376. package/dist/domain/script/v4/patch/schema.d.ts +0 -7
  377. package/dist/domain/script/v4/patch/schema.js +0 -77
  378. package/dist/domain/script/v4/patch/schema.js.map +0 -1
  379. package/dist/domain/script/v4/patch/types.d.ts +0 -10
  380. package/dist/domain/script/v4/patch/types.js +0 -2
  381. package/dist/domain/script/v4/patch/types.js.map +0 -1
  382. package/dist/domain/script/v4/selector.d.ts +0 -11
  383. package/dist/domain/script/v4/selector.js +0 -124
  384. package/dist/domain/script/v4/selector.js.map +0 -1
  385. package/dist/domain/script/v4/types.d.ts +0 -120
  386. package/dist/domain/script/v4/types.js +0 -2
  387. package/dist/domain/script/v4/types.js.map +0 -1
  388. package/dist/domain/script/v4/validation.d.ts +0 -2
  389. package/dist/domain/script/v4/validation.js +0 -2
  390. package/dist/domain/script/v4/validation.js.map +0 -1
  391. package/dist/failures.d.ts +0 -58
  392. package/dist/failures.js +0 -96
  393. package/dist/failures.js.map +0 -1
  394. package/dist/infra/converters.d.ts +0 -9
  395. package/dist/infra/converters.js +0 -689
  396. package/dist/infra/converters.js.map +0 -1
  397. package/dist/infra/env.d.ts +0 -2
  398. package/dist/infra/env.js +0 -81
  399. package/dist/infra/env.js.map +0 -1
  400. package/dist/infra/episode-title.d.ts +0 -4
  401. package/dist/infra/episode-title.js +0 -129
  402. package/dist/infra/episode-title.js.map +0 -1
  403. package/dist/infra/ingest/review-renderer.d.ts +0 -1
  404. package/dist/infra/ingest/review-renderer.js +0 -440
  405. package/dist/infra/ingest/review-renderer.js.map +0 -1
  406. package/dist/infra/ingest/source-resolver.d.ts +0 -21
  407. package/dist/infra/ingest/source-resolver.js +0 -51
  408. package/dist/infra/ingest/source-resolver.js.map +0 -1
  409. package/dist/infra/ingest/text-reader.d.ts +0 -3
  410. package/dist/infra/ingest/text-reader.js +0 -27
  411. package/dist/infra/ingest/text-reader.js.map +0 -1
  412. package/dist/infra/ingest/video-discovery.d.ts +0 -8
  413. package/dist/infra/ingest/video-discovery.js +0 -69
  414. package/dist/infra/ingest/video-discovery.js.map +0 -1
  415. package/dist/infra/ingest/video-source-snapshot.d.ts +0 -4
  416. package/dist/infra/ingest/video-source-snapshot.js +0 -47
  417. package/dist/infra/ingest/video-source-snapshot.js.map +0 -1
  418. package/dist/infra/ingest/video-state-evidence.d.ts +0 -14
  419. package/dist/infra/ingest/video-state-evidence.js +0 -140
  420. package/dist/infra/ingest/video-state-evidence.js.map +0 -1
  421. package/dist/infra/ingest/video-transcode.d.ts +0 -7
  422. package/dist/infra/ingest/video-transcode.js +0 -98
  423. package/dist/infra/ingest/video-transcode.js.map +0 -1
  424. package/dist/infra/ingest/workspace-lock.d.ts +0 -1
  425. package/dist/infra/ingest/workspace-lock.js +0 -32
  426. package/dist/infra/ingest/workspace-lock.js.map +0 -1
  427. package/dist/infra/ingest/workspace-store.d.ts +0 -18
  428. package/dist/infra/ingest/workspace-store.js +0 -70
  429. package/dist/infra/ingest/workspace-store.js.map +0 -1
  430. package/dist/infra/llm/anthropic-model.d.ts +0 -11
  431. package/dist/infra/llm/anthropic-model.js +0 -130
  432. package/dist/infra/llm/anthropic-model.js.map +0 -1
  433. package/dist/infra/llm/doubao-model.d.ts +0 -60
  434. package/dist/infra/llm/doubao-model.js +0 -249
  435. package/dist/infra/llm/doubao-model.js.map +0 -1
  436. package/dist/infra/llm/failure-mapping.d.ts +0 -6
  437. package/dist/infra/llm/failure-mapping.js +0 -146
  438. package/dist/infra/llm/failure-mapping.js.map +0 -1
  439. package/dist/infra/llm/gemini-upload.d.ts +0 -13
  440. package/dist/infra/llm/gemini-upload.js +0 -138
  441. package/dist/infra/llm/gemini-upload.js.map +0 -1
  442. package/dist/infra/llm/gemini-video-model.d.ts +0 -50
  443. package/dist/infra/llm/gemini-video-model.js +0 -371
  444. package/dist/infra/llm/gemini-video-model.js.map +0 -1
  445. package/dist/infra/llm/openai-compatible-model.d.ts +0 -14
  446. package/dist/infra/llm/openai-compatible-model.js +0 -207
  447. package/dist/infra/llm/openai-compatible-model.js.map +0 -1
  448. package/dist/infra/llm/retry.d.ts +0 -8
  449. package/dist/infra/llm/retry.js +0 -41
  450. package/dist/infra/llm/retry.js.map +0 -1
  451. package/dist/infra/local-script-output-store.d.ts +0 -43
  452. package/dist/infra/local-script-output-store.js +0 -168
  453. package/dist/infra/local-script-output-store.js.map +0 -1
  454. package/dist/infra/script-output-api.d.ts +0 -50
  455. package/dist/infra/script-output-api.js +0 -251
  456. package/dist/infra/script-output-api.js.map +0 -1
  457. package/dist/infra/script-output-store.d.ts +0 -152
  458. package/dist/infra/script-output-store.js +0 -114
  459. package/dist/infra/script-output-store.js.map +0 -1
  460. package/dist/infra/script-working-copy.d.ts +0 -23
  461. package/dist/infra/script-working-copy.js +0 -157
  462. package/dist/infra/script-working-copy.js.map +0 -1
  463. package/dist/infra/storage.d.ts +0 -35
  464. package/dist/infra/storage.js +0 -91
  465. package/dist/infra/storage.js.map +0 -1
  466. package/dist/llm/composition.d.ts +0 -5
  467. package/dist/llm/composition.js +0 -5
  468. package/dist/llm/composition.js.map +0 -1
  469. package/dist/llm/config.d.ts +0 -28
  470. package/dist/llm/config.js +0 -231
  471. package/dist/llm/config.js.map +0 -1
  472. package/dist/llm/registry.d.ts +0 -43
  473. package/dist/llm/registry.js +0 -69
  474. package/dist/llm/registry.js.map +0 -1
  475. package/dist/llm/router.d.ts +0 -46
  476. package/dist/llm/router.js +0 -512
  477. package/dist/llm/router.js.map +0 -1
  478. package/dist/llm/tasks/ingest/arc-summary.d.ts +0 -8
  479. package/dist/llm/tasks/ingest/arc-summary.js +0 -26
  480. package/dist/llm/tasks/ingest/arc-summary.js.map +0 -1
  481. package/dist/llm/tasks/ingest/asset-audit.d.ts +0 -6
  482. package/dist/llm/tasks/ingest/asset-audit.js +0 -158
  483. package/dist/llm/tasks/ingest/asset-audit.js.map +0 -1
  484. package/dist/llm/tasks/ingest/asset-curate.d.ts +0 -13
  485. package/dist/llm/tasks/ingest/asset-curate.js +0 -45
  486. package/dist/llm/tasks/ingest/asset-curate.js.map +0 -1
  487. package/dist/llm/tasks/ingest/asset-extract.d.ts +0 -12
  488. package/dist/llm/tasks/ingest/asset-extract.js +0 -51
  489. package/dist/llm/tasks/ingest/asset-extract.js.map +0 -1
  490. package/dist/llm/tasks/ingest/asset-govern.d.ts +0 -22
  491. package/dist/llm/tasks/ingest/asset-govern.js +0 -143
  492. package/dist/llm/tasks/ingest/asset-govern.js.map +0 -1
  493. package/dist/llm/tasks/ingest/body-start.d.ts +0 -10
  494. package/dist/llm/tasks/ingest/body-start.js +0 -41
  495. package/dist/llm/tasks/ingest/body-start.js.map +0 -1
  496. package/dist/llm/tasks/ingest/episode-assets.d.ts +0 -29
  497. package/dist/llm/tasks/ingest/episode-assets.js +0 -282
  498. package/dist/llm/tasks/ingest/episode-assets.js.map +0 -1
  499. package/dist/llm/tasks/ingest/mention-resolve.d.ts +0 -9
  500. package/dist/llm/tasks/ingest/mention-resolve.js +0 -39
  501. package/dist/llm/tasks/ingest/mention-resolve.js.map +0 -1
  502. package/dist/llm/tasks/ingest/name-fix.d.ts +0 -9
  503. package/dist/llm/tasks/ingest/name-fix.js +0 -56
  504. package/dist/llm/tasks/ingest/name-fix.js.map +0 -1
  505. package/dist/llm/tasks/ingest/state-reconcile.d.ts +0 -8
  506. package/dist/llm/tasks/ingest/state-reconcile.js +0 -44
  507. package/dist/llm/tasks/ingest/state-reconcile.js.map +0 -1
  508. package/dist/llm/tasks/ingest/text-normalize.d.ts +0 -10
  509. package/dist/llm/tasks/ingest/text-normalize.js +0 -122
  510. package/dist/llm/tasks/ingest/text-normalize.js.map +0 -1
  511. package/dist/llm/tasks/ingest/video-serial.d.ts +0 -24
  512. package/dist/llm/tasks/ingest/video-serial.js +0 -416
  513. package/dist/llm/tasks/ingest/video-serial.js.map +0 -1
  514. package/dist/llm/tasks/schemas.d.ts +0 -9
  515. package/dist/llm/tasks/schemas.js +0 -466
  516. package/dist/llm/tasks/schemas.js.map +0 -1
  517. package/dist/llm/types.d.ts +0 -178
  518. package/dist/llm/types.js +0 -44
  519. package/dist/llm/types.js.map +0 -1
  520. package/dist/output.d.ts +0 -3
  521. package/dist/output.js +0 -94
  522. package/dist/output.js.map +0 -1
  523. package/dist/package-root.d.ts +0 -2
  524. package/dist/package-root.js +0 -38
  525. package/dist/package-root.js.map +0 -1
  526. package/dist/review-agent.js.map +0 -7
  527. package/dist/usecases/changelog.d.ts +0 -9
  528. package/dist/usecases/changelog.js +0 -134
  529. package/dist/usecases/changelog.js.map +0 -1
  530. package/dist/usecases/doctor.d.ts +0 -2
  531. package/dist/usecases/doctor.js +0 -231
  532. package/dist/usecases/doctor.js.map +0 -1
  533. package/dist/usecases/ingest/body-start.d.ts +0 -8
  534. package/dist/usecases/ingest/body-start.js +0 -36
  535. package/dist/usecases/ingest/body-start.js.map +0 -1
  536. package/dist/usecases/ingest/command.d.ts +0 -5
  537. package/dist/usecases/ingest/command.js +0 -183
  538. package/dist/usecases/ingest/command.js.map +0 -1
  539. package/dist/usecases/ingest/failure.d.ts +0 -26
  540. package/dist/usecases/ingest/failure.js +0 -153
  541. package/dist/usecases/ingest/failure.js.map +0 -1
  542. package/dist/usecases/ingest/fanout.d.ts +0 -10
  543. package/dist/usecases/ingest/fanout.js +0 -23
  544. package/dist/usecases/ingest/fanout.js.map +0 -1
  545. package/dist/usecases/ingest/final-asset-audit.d.ts +0 -39
  546. package/dist/usecases/ingest/final-asset-audit.js +0 -88
  547. package/dist/usecases/ingest/final-asset-audit.js.map +0 -1
  548. package/dist/usecases/ingest/generate-video-state-evidence.d.ts +0 -23
  549. package/dist/usecases/ingest/generate-video-state-evidence.js +0 -124
  550. package/dist/usecases/ingest/generate-video-state-evidence.js.map +0 -1
  551. package/dist/usecases/ingest/pass4-mention-resolve.d.ts +0 -11
  552. package/dist/usecases/ingest/pass4-mention-resolve.js +0 -52
  553. package/dist/usecases/ingest/pass4-mention-resolve.js.map +0 -1
  554. package/dist/usecases/ingest/pass5-extract.d.ts +0 -7
  555. package/dist/usecases/ingest/pass5-extract.js +0 -51
  556. package/dist/usecases/ingest/pass5-extract.js.map +0 -1
  557. package/dist/usecases/ingest/pass5-govern.d.ts +0 -13
  558. package/dist/usecases/ingest/pass5-govern.js +0 -157
  559. package/dist/usecases/ingest/pass5-govern.js.map +0 -1
  560. package/dist/usecases/ingest/pipeline.d.ts +0 -28
  561. package/dist/usecases/ingest/pipeline.js +0 -335
  562. package/dist/usecases/ingest/pipeline.js.map +0 -1
  563. package/dist/usecases/ingest/publish-command.d.ts +0 -1
  564. package/dist/usecases/ingest/publish-command.js +0 -4
  565. package/dist/usecases/ingest/publish-command.js.map +0 -1
  566. package/dist/usecases/ingest/serial-govern.d.ts +0 -40
  567. package/dist/usecases/ingest/serial-govern.js +0 -488
  568. package/dist/usecases/ingest/serial-govern.js.map +0 -1
  569. package/dist/usecases/ingest/skip-video-episode.d.ts +0 -4
  570. package/dist/usecases/ingest/skip-video-episode.js +0 -120
  571. package/dist/usecases/ingest/skip-video-episode.js.map +0 -1
  572. package/dist/usecases/ingest/status.d.ts +0 -61
  573. package/dist/usecases/ingest/status.js +0 -347
  574. package/dist/usecases/ingest/status.js.map +0 -1
  575. package/dist/usecases/ingest/timings.d.ts +0 -51
  576. package/dist/usecases/ingest/timings.js +0 -68
  577. package/dist/usecases/ingest/timings.js.map +0 -1
  578. package/dist/usecases/ingest/usage-report.d.ts +0 -125
  579. package/dist/usecases/ingest/usage-report.js +0 -248
  580. package/dist/usecases/ingest/usage-report.js.map +0 -1
  581. package/dist/usecases/ingest/video-pipeline.d.ts +0 -81
  582. package/dist/usecases/ingest/video-pipeline.js +0 -548
  583. package/dist/usecases/ingest/video-pipeline.js.map +0 -1
  584. package/dist/usecases/ingest/video-skip-state.d.ts +0 -29
  585. package/dist/usecases/ingest/video-skip-state.js +0 -148
  586. package/dist/usecases/ingest/video-skip-state.js.map +0 -1
  587. package/dist/usecases/ingest/view-command.d.ts +0 -4
  588. package/dist/usecases/ingest/view-command.js +0 -67
  589. package/dist/usecases/ingest/view-command.js.map +0 -1
  590. package/dist/usecases/ingest/view-server.d.ts +0 -29
  591. package/dist/usecases/ingest/view-server.js +0 -364
  592. package/dist/usecases/ingest/view-server.js.map +0 -1
  593. package/dist/usecases/script/action-span.d.ts +0 -10
  594. package/dist/usecases/script/action-span.js +0 -42
  595. package/dist/usecases/script/action-span.js.map +0 -1
  596. package/dist/usecases/script/actions.d.ts +0 -3
  597. package/dist/usecases/script/actions.js +0 -184
  598. package/dist/usecases/script/actions.js.map +0 -1
  599. package/dist/usecases/script/actor.d.ts +0 -3
  600. package/dist/usecases/script/actor.js +0 -26
  601. package/dist/usecases/script/actor.js.map +0 -1
  602. package/dist/usecases/script/actors.d.ts +0 -3
  603. package/dist/usecases/script/actors.js +0 -25
  604. package/dist/usecases/script/actors.js.map +0 -1
  605. package/dist/usecases/script/add-actor.d.ts +0 -3
  606. package/dist/usecases/script/add-actor.js +0 -13
  607. package/dist/usecases/script/add-actor.js.map +0 -1
  608. package/dist/usecases/script/add-episode.d.ts +0 -3
  609. package/dist/usecases/script/add-episode.js +0 -9
  610. package/dist/usecases/script/add-episode.js.map +0 -1
  611. package/dist/usecases/script/add-location.d.ts +0 -3
  612. package/dist/usecases/script/add-location.js +0 -11
  613. package/dist/usecases/script/add-location.js.map +0 -1
  614. package/dist/usecases/script/add-prop.d.ts +0 -3
  615. package/dist/usecases/script/add-prop.js +0 -11
  616. package/dist/usecases/script/add-prop.js.map +0 -1
  617. package/dist/usecases/script/alias.d.ts +0 -3
  618. package/dist/usecases/script/alias.js +0 -39
  619. package/dist/usecases/script/alias.js.map +0 -1
  620. package/dist/usecases/script/assets.d.ts +0 -3
  621. package/dist/usecases/script/assets.js +0 -46
  622. package/dist/usecases/script/assets.js.map +0 -1
  623. package/dist/usecases/script/audit-assets.d.ts +0 -4
  624. package/dist/usecases/script/audit-assets.js +0 -37
  625. package/dist/usecases/script/audit-assets.js.map +0 -1
  626. package/dist/usecases/script/command-constraints.d.ts +0 -38
  627. package/dist/usecases/script/command-constraints.js +0 -143
  628. package/dist/usecases/script/command-constraints.js.map +0 -1
  629. package/dist/usecases/script/compose-creative-draft.d.ts +0 -3
  630. package/dist/usecases/script/compose-creative-draft.js +0 -106
  631. package/dist/usecases/script/compose-creative-draft.js.map +0 -1
  632. package/dist/usecases/script/context.d.ts +0 -3
  633. package/dist/usecases/script/context.js +0 -52
  634. package/dist/usecases/script/context.js.map +0 -1
  635. package/dist/usecases/script/create.d.ts +0 -3
  636. package/dist/usecases/script/create.js +0 -27
  637. package/dist/usecases/script/create.js.map +0 -1
  638. package/dist/usecases/script/delete.d.ts +0 -3
  639. package/dist/usecases/script/delete.js +0 -88
  640. package/dist/usecases/script/delete.js.map +0 -1
  641. package/dist/usecases/script/describe.d.ts +0 -3
  642. package/dist/usecases/script/describe.js +0 -32
  643. package/dist/usecases/script/describe.js.map +0 -1
  644. package/dist/usecases/script/dialogue.d.ts +0 -3
  645. package/dist/usecases/script/dialogue.js +0 -30
  646. package/dist/usecases/script/dialogue.js.map +0 -1
  647. package/dist/usecases/script/dispatch.d.ts +0 -3
  648. package/dist/usecases/script/dispatch.js +0 -10
  649. package/dist/usecases/script/dispatch.js.map +0 -1
  650. package/dist/usecases/script/do.d.ts +0 -3
  651. package/dist/usecases/script/do.js +0 -186
  652. package/dist/usecases/script/do.js.map +0 -1
  653. package/dist/usecases/script/emotion.d.ts +0 -3
  654. package/dist/usecases/script/emotion.js +0 -24
  655. package/dist/usecases/script/emotion.js.map +0 -1
  656. package/dist/usecases/script/episodes.d.ts +0 -3
  657. package/dist/usecases/script/episodes.js +0 -62
  658. package/dist/usecases/script/episodes.js.map +0 -1
  659. package/dist/usecases/script/export-authoring.d.ts +0 -4
  660. package/dist/usecases/script/export-authoring.js +0 -326
  661. package/dist/usecases/script/export-authoring.js.map +0 -1
  662. package/dist/usecases/script/extend.d.ts +0 -3
  663. package/dist/usecases/script/extend.js +0 -94
  664. package/dist/usecases/script/extend.js.map +0 -1
  665. package/dist/usecases/script/ids.d.ts +0 -3
  666. package/dist/usecases/script/ids.js +0 -148
  667. package/dist/usecases/script/ids.js.map +0 -1
  668. package/dist/usecases/script/importance.d.ts +0 -3
  669. package/dist/usecases/script/importance.js +0 -16
  670. package/dist/usecases/script/importance.js.map +0 -1
  671. package/dist/usecases/script/insert.d.ts +0 -3
  672. package/dist/usecases/script/insert.js +0 -127
  673. package/dist/usecases/script/insert.js.map +0 -1
  674. package/dist/usecases/script/issues.d.ts +0 -3
  675. package/dist/usecases/script/issues.js +0 -35
  676. package/dist/usecases/script/issues.js.map +0 -1
  677. package/dist/usecases/script/lib.d.ts +0 -152
  678. package/dist/usecases/script/lib.js +0 -1654
  679. package/dist/usecases/script/lib.js.map +0 -1
  680. package/dist/usecases/script/locations.d.ts +0 -3
  681. package/dist/usecases/script/locations.js +0 -25
  682. package/dist/usecases/script/locations.js.map +0 -1
  683. package/dist/usecases/script/merge.d.ts +0 -3
  684. package/dist/usecases/script/merge.js +0 -43
  685. package/dist/usecases/script/merge.js.map +0 -1
  686. package/dist/usecases/script/migrate.d.ts +0 -3
  687. package/dist/usecases/script/migrate.js +0 -210
  688. package/dist/usecases/script/migrate.js.map +0 -1
  689. package/dist/usecases/script/move.d.ts +0 -3
  690. package/dist/usecases/script/move.js +0 -50
  691. package/dist/usecases/script/move.js.map +0 -1
  692. package/dist/usecases/script/parenthetical.d.ts +0 -3
  693. package/dist/usecases/script/parenthetical.js +0 -52
  694. package/dist/usecases/script/parenthetical.js.map +0 -1
  695. package/dist/usecases/script/props.d.ts +0 -3
  696. package/dist/usecases/script/props.js +0 -25
  697. package/dist/usecases/script/props.js.map +0 -1
  698. package/dist/usecases/script/refs.d.ts +0 -3
  699. package/dist/usecases/script/refs.js +0 -111
  700. package/dist/usecases/script/refs.js.map +0 -1
  701. package/dist/usecases/script/rename.d.ts +0 -3
  702. package/dist/usecases/script/rename.js +0 -35
  703. package/dist/usecases/script/rename.js.map +0 -1
  704. package/dist/usecases/script/replace.d.ts +0 -3
  705. package/dist/usecases/script/replace.js +0 -33
  706. package/dist/usecases/script/replace.js.map +0 -1
  707. package/dist/usecases/script/review.d.ts +0 -3
  708. package/dist/usecases/script/review.js +0 -187
  709. package/dist/usecases/script/review.js.map +0 -1
  710. package/dist/usecases/script/role.d.ts +0 -3
  711. package/dist/usecases/script/role.js +0 -16
  712. package/dist/usecases/script/role.js.map +0 -1
  713. package/dist/usecases/script/scenes.d.ts +0 -3
  714. package/dist/usecases/script/scenes.js +0 -66
  715. package/dist/usecases/script/scenes.js.map +0 -1
  716. package/dist/usecases/script/script-patch.d.ts +0 -3
  717. package/dist/usecases/script/script-patch.js +0 -321
  718. package/dist/usecases/script/script-patch.js.map +0 -1
  719. package/dist/usecases/script/script-validate.d.ts +0 -3
  720. package/dist/usecases/script/script-validate.js +0 -27
  721. package/dist/usecases/script/script-validate.js.map +0 -1
  722. package/dist/usecases/script/session.d.ts +0 -62
  723. package/dist/usecases/script/session.js +0 -567
  724. package/dist/usecases/script/session.js.map +0 -1
  725. package/dist/usecases/script/split.d.ts +0 -3
  726. package/dist/usecases/script/split.js +0 -41
  727. package/dist/usecases/script/split.js.map +0 -1
  728. package/dist/usecases/script/state-add.d.ts +0 -3
  729. package/dist/usecases/script/state-add.js +0 -22
  730. package/dist/usecases/script/state-add.js.map +0 -1
  731. package/dist/usecases/script/state-delete.d.ts +0 -3
  732. package/dist/usecases/script/state-delete.js +0 -22
  733. package/dist/usecases/script/state-delete.js.map +0 -1
  734. package/dist/usecases/script/state-rename.d.ts +0 -3
  735. package/dist/usecases/script/state-rename.js +0 -16
  736. package/dist/usecases/script/state-rename.js.map +0 -1
  737. package/dist/usecases/script/states.d.ts +0 -3
  738. package/dist/usecases/script/states.js +0 -197
  739. package/dist/usecases/script/states.js.map +0 -1
  740. package/dist/usecases/script/summary.d.ts +0 -3
  741. package/dist/usecases/script/summary.js +0 -72
  742. package/dist/usecases/script/summary.js.map +0 -1
  743. package/dist/usecases/script/synopsis-generate.d.ts +0 -115
  744. package/dist/usecases/script/synopsis-generate.js +0 -776
  745. package/dist/usecases/script/synopsis-generate.js.map +0 -1
  746. package/dist/usecases/script/synopsis.d.ts +0 -3
  747. package/dist/usecases/script/synopsis.js +0 -45
  748. package/dist/usecases/script/synopsis.js.map +0 -1
  749. package/dist/usecases/script/timestamp-filter.d.ts +0 -4
  750. package/dist/usecases/script/timestamp-filter.js +0 -55
  751. package/dist/usecases/script/timestamp-filter.js.map +0 -1
  752. package/dist/usecases/script/timestamp.d.ts +0 -3
  753. package/dist/usecases/script/timestamp.js +0 -11
  754. package/dist/usecases/script/timestamp.js.map +0 -1
  755. package/dist/usecases/script/transition.d.ts +0 -3
  756. package/dist/usecases/script/transition.js +0 -23
  757. package/dist/usecases/script/transition.js.map +0 -1
  758. package/dist/usecases/script/type.d.ts +0 -3
  759. package/dist/usecases/script/type.js +0 -23
  760. package/dist/usecases/script/type.js.map +0 -1
  761. package/dist/usecases/script/v3/mutations.d.ts +0 -2
  762. package/dist/usecases/script/v3/mutations.js +0 -5
  763. package/dist/usecases/script/v3/mutations.js.map +0 -1
  764. package/dist/usecases/script/v4/mutations.d.ts +0 -2
  765. package/dist/usecases/script/v4/mutations.js +0 -6
  766. package/dist/usecases/script/v4/mutations.js.map +0 -1
  767. package/dist/usecases/script/v4/queries.d.ts +0 -15
  768. package/dist/usecases/script/v4/queries.js +0 -196
  769. package/dist/usecases/script/v4/queries.js.map +0 -1
  770. package/dist/usecases/script/working-copy.d.ts +0 -5
  771. package/dist/usecases/script/working-copy.js +0 -399
  772. package/dist/usecases/script/working-copy.js.map +0 -1
  773. package/dist/usecases/script/worldview.d.ts +0 -3
  774. package/dist/usecases/script/worldview.js +0 -17
  775. package/dist/usecases/script/worldview.js.map +0 -1
  776. package/dist/usecases/script/write-authoring.d.ts +0 -3
  777. package/dist/usecases/script/write-authoring.js +0 -263
  778. package/dist/usecases/script/write-authoring.js.map +0 -1
  779. package/dist/usecases/update.d.ts +0 -13
  780. package/dist/usecases/update.js +0 -128
  781. package/dist/usecases/update.js.map +0 -1
@@ -1,1654 +0,0 @@
1
- import { CliError, EXIT_INPUT, EXIT_OK, EXIT_USAGE, sha256Text, } from "../../common.js";
2
- import { applyPatchOperationsV4 } from "../../domain/script/v4/patch/apply.js";
3
- import { isV4Id } from "../../domain/script/v4/ids.js";
4
- import { requireStructurallyReadableScriptV4 } from "../../domain/script/v4/parse.js";
5
- import { validateScriptV4 } from "../../domain/script/v4/validation.js";
6
- import { sceneRefs } from "../../domain/script/scene-refs.js";
7
- import { isDangerousRegex, MAX_GREP_PATTERN_LEN, parseInSelector, selectorSingleActionPoint, WHOLE_SCRIPT, } from "../../domain/script/selector.js";
8
- import { parseAnyAddress, } from "../../domain/script/address.js";
9
- import { parseV4Address } from "../../domain/script/v4/address.js";
10
- import { summarizeIssues } from "../../domain/script/text-util.js";
11
- import { sortDeep } from "../../domain/script/text-util.js";
12
- import { asList, idNum, isDict, strOf, } from "../../domain/script/shared.js";
13
- import { loadScriptForEdit, validateSession, saveScriptSession, syncValidationResult, scriptSourceText, mutationValidationWarnings, } from "./session.js";
14
- import { resolveActionTargetsV4 } from "./v4/queries.js";
15
- import { actionTimestampFilter, actionTimestampMatches } from "./timestamp-filter.js";
16
- import { applyVersionedMutations } from "./dispatch.js";
17
- import { assertInsertCommandFlags, assertMoveCommandFlags, assertSceneRefCommandFlags, buildTimestampOperation, } from "./command-constraints.js";
18
- export function tokenizeLine(line) {
19
- const out = [];
20
- let cur = "";
21
- let started = false;
22
- let quoted = false;
23
- let inSingle = false;
24
- let inDouble = false;
25
- const flush = () => { if (started) {
26
- out.push({ text: cur, quoted });
27
- cur = "";
28
- started = false;
29
- quoted = false;
30
- } };
31
- for (let i = 0; i < line.length; i++) {
32
- const ch = line[i];
33
- if (inSingle) {
34
- if (ch === "'")
35
- inSingle = false;
36
- else {
37
- cur += ch;
38
- quoted = true;
39
- }
40
- }
41
- else if (inDouble) {
42
- if (ch === '"')
43
- inDouble = false;
44
- else if (ch === "\\" && i + 1 < line.length) {
45
- cur += line[++i];
46
- quoted = true;
47
- }
48
- else {
49
- cur += ch;
50
- quoted = true;
51
- }
52
- }
53
- else if (ch === "'") {
54
- inSingle = true;
55
- started = true;
56
- }
57
- else if (ch === '"') {
58
- inDouble = true;
59
- started = true;
60
- }
61
- else if (ch === "\\" && i + 1 < line.length) {
62
- cur += line[++i];
63
- started = true;
64
- quoted = true;
65
- }
66
- else if (ch === " " || ch === "\t" || ch === "\r") {
67
- flush();
68
- }
69
- else {
70
- cur += ch;
71
- started = true;
72
- }
73
- }
74
- flush();
75
- return out;
76
- }
77
- // A token is a flag only if it was unquoted AND starts with `--`.
78
- function isDoFlag(t) {
79
- return !t.quoted && t.text.startsWith("--");
80
- }
81
- // Per-verb flag arity. Everything else takes the next token as its value.
82
- export const DO_BOOL_FLAGS = {
83
- replace: new Set(["all", "regex"]),
84
- transition: new Set(["clear"]),
85
- emotion: new Set(["clear"]),
86
- parenthetical: new Set(["remove"]),
87
- timestamp: new Set(["remove"]),
88
- "scene-ref": new Set(["clear", "remove", "append"]),
89
- delete: new Set(["force"]),
90
- extend: new Set(["clear", "json-value"]),
91
- };
92
- export const DO_REPEAT_FLAGS = {
93
- alias: new Set(["add", "remove"]),
94
- "add-actor": new Set(["alias"]),
95
- "scene-ref": new Set(["state"]),
96
- insert: new Set(["state"]),
97
- };
98
- function pushFlag(flags, repeats, name, val) {
99
- if (repeats.has(name)) {
100
- const arr = flags[name] ?? [];
101
- arr.push(val);
102
- flags[name] = arr;
103
- }
104
- else {
105
- flags[name] = val;
106
- }
107
- }
108
- export function parseDoLine(tokens) {
109
- if (tokens.length === 0 || isDoFlag(tokens[0])) {
110
- throw doErr("a line must start with a verb (not a flag)");
111
- }
112
- const verb = tokens[0].text;
113
- const bools = DO_BOOL_FLAGS[verb] ?? new Set();
114
- const repeats = DO_REPEAT_FLAGS[verb] ?? new Set();
115
- const args = [];
116
- const flags = {};
117
- for (let i = 1; i < tokens.length; i++) {
118
- const t = tokens[i];
119
- if (isDoFlag(t)) {
120
- let name = t.text.slice(2);
121
- // Support `--flag=value` (a common CLI habit) alongside `--flag value`.
122
- const eq = name.indexOf("=");
123
- if (eq >= 0) {
124
- const inlineVal = name.slice(eq + 1);
125
- name = name.slice(0, eq);
126
- if (!name)
127
- throw doErr(`empty flag name in "${t.text}"`);
128
- // A boolean flag written as `--all=false` must become false, not the
129
- // truthy string "false" — `--force=false` especially must NOT force.
130
- if (bools.has(name)) {
131
- flags[name] = !["false", "0", "no", "off"].includes(inlineVal.toLowerCase());
132
- }
133
- else {
134
- pushFlag(flags, repeats, name, inlineVal);
135
- }
136
- continue;
137
- }
138
- if (!name)
139
- throw doErr(`empty flag name "${t.text}"`);
140
- if (bools.has(name)) {
141
- flags[name] = true;
142
- continue;
143
- }
144
- // A value-taking flag must be followed by an actual value, not another
145
- // unquoted `--flag` (or end-of-line) — otherwise `--to --from x` silently
146
- // binds '--from' as --to's value. A quoted `"--x"` IS a valid value.
147
- const next = tokens[i + 1];
148
- if (next === undefined || isDoFlag(next)) {
149
- throw doErr(`--${name} needs a value`);
150
- }
151
- pushFlag(flags, repeats, name, tokens[++i].text);
152
- }
153
- else {
154
- args.push(t.text);
155
- }
156
- }
157
- return { verb, args, flags };
158
- }
159
- export function doErr(detail) {
160
- return new CliError(detail, {
161
- exitCode: EXIT_USAGE,
162
- errorCode: "DO_LINE_INVALID",
163
- hint: "Each line is a scriptctl verb minus the leading `scriptctl`; see `scriptctl do --help`.",
164
- data: { expected: ["a valid <verb> ...args... line"], actual: [detail] },
165
- });
166
- }
167
- // ---- shared op-template builders ------------------------------------------
168
- // One source of truth for the verbs whose op has validation/defaults, so the
169
- // typed CLI handler and `do`'s lineToOp can never drift. Each returns the op
170
- // WITHOUT `at` (the caller adds the single address or sweeps it over a selector)
171
- // and throws the SAME CliError the handler used to throw inline.
172
- export function stateChangeTemplate(target, f) {
173
- const toSet = f.to !== undefined;
174
- const clearSet = Boolean(f.clear);
175
- if (toSet && clearSet) {
176
- throw new CliError("state-change: --to and --clear are mutually exclusive.", {
177
- exitCode: EXIT_USAGE,
178
- errorCode: "STATE_CHANGE_FLAG_CONFLICT",
179
- hint: "Pick one and retry.",
180
- data: { expected: ["exactly one of --to <state> / --clear"], actual: ["--to", "--clear"] },
181
- });
182
- }
183
- if (!toSet && !clearSet) {
184
- throw new CliError("state-change: must specify --to <state> or --clear.", {
185
- exitCode: EXIT_USAGE,
186
- errorCode: "STATE_CHANGE_FLAG_MISSING",
187
- hint: "Pick exactly one flag.",
188
- data: { expected: ["one of --to <state> / --clear"], actual: ["<missing>"] },
189
- });
190
- }
191
- // v3 has no per-action state_changes; state lives on scene.ref.* only.
192
- throw new CliError("state-change was removed in v3; set a scene ref's state instead.", {
193
- exitCode: EXIT_USAGE,
194
- errorCode: "STATE_CHANGE_REMOVED",
195
- hint: "Use `scene-ref <ep/scn> <kind:id> --state <state_id>` (op scene.ref.set).",
196
- data: { expected: ["scene-ref state edit"], actual: ["state-change"] },
197
- });
198
- }
199
- export function transitionTemplate(target, f) {
200
- const setBoth = f.process !== undefined || f.contrast !== undefined;
201
- const clearSet = Boolean(f.clear);
202
- if (setBoth && clearSet) {
203
- throw new CliError("transition: --clear is mutually exclusive with --process/--contrast.", {
204
- exitCode: EXIT_USAGE,
205
- errorCode: "TRANSITION_FLAG_CONFLICT",
206
- hint: "Pick one mode and retry.",
207
- data: { expected: ["either --clear, or --process + --contrast"], actual: ["--clear", "--process/--contrast"] },
208
- });
209
- }
210
- if (!setBoth && !clearSet) {
211
- throw new CliError("transition: must specify --process/--contrast or --clear.", {
212
- exitCode: EXIT_USAGE,
213
- errorCode: "TRANSITION_FLAG_MISSING",
214
- hint: "Pick exactly one mode.",
215
- data: { expected: ["--process + --contrast, or --clear"], actual: ["<missing>"] },
216
- });
217
- }
218
- return clearSet
219
- ? { op: "action.transition.clear", target }
220
- : { op: "action.transition.set", target, process: f.process, contrast: f.contrast };
221
- }
222
- export function emotionTemplate(f) {
223
- const emotionSet = f.emotion !== undefined;
224
- const clearSet = Boolean(f.clear);
225
- if (emotionSet && clearSet) {
226
- throw new CliError("emotion: value and --clear are mutually exclusive.", {
227
- exitCode: EXIT_USAGE,
228
- errorCode: "EMOTION_FLAG_CONFLICT",
229
- hint: "Pick one mode and retry.",
230
- data: { expected: ["either <emotion>, or --clear"], actual: ["<emotion>", "--clear"] },
231
- });
232
- }
233
- if (!emotionSet && !clearSet) {
234
- throw new CliError("emotion: must specify <emotion> or --clear.", {
235
- exitCode: EXIT_USAGE,
236
- errorCode: "EMOTION_VALUE_MISSING",
237
- hint: "Pass an emotion label, or use --clear.",
238
- data: { expected: ["<emotion>, or --clear"], actual: ["<missing>"] },
239
- });
240
- }
241
- return clearSet
242
- ? { op: "action.emotion.clear" }
243
- : { op: "action.emotion.set", emotion: f.emotion };
244
- }
245
- export function contextTemplate(target, f) {
246
- const stateSet = f.state !== undefined;
247
- const clearSet = Boolean(f.clear);
248
- const removeSet = Boolean(f.remove);
249
- const n = (stateSet ? 1 : 0) + (clearSet ? 1 : 0) + (removeSet ? 1 : 0);
250
- if (n === 0) {
251
- throw new CliError("context: must specify --state X, --clear, or --remove.", {
252
- exitCode: EXIT_USAGE,
253
- errorCode: "CONTEXT_FLAG_MISSING",
254
- hint: "Pick exactly one flag.",
255
- data: { expected: ["one of --state <state_id> / --clear / --remove"], actual: ["<missing>"] },
256
- });
257
- }
258
- if (n > 1) {
259
- const passed = [];
260
- if (stateSet)
261
- passed.push("--state");
262
- if (clearSet)
263
- passed.push("--clear");
264
- if (removeSet)
265
- passed.push("--remove");
266
- throw new CliError("context: --state / --clear / --remove are mutually exclusive.", {
267
- exitCode: EXIT_USAGE,
268
- errorCode: "CONTEXT_FLAG_CONFLICT",
269
- hint: "Pick one and retry.",
270
- data: { expected: ["exactly one of --state / --clear / --remove"], actual: passed },
271
- });
272
- }
273
- const append = Boolean(f.append);
274
- const occurrenceRaw = strOf(f.occurrence).trim();
275
- const occurrence = occurrenceRaw ? Number(occurrenceRaw) : undefined;
276
- if (occurrence !== undefined && (!Number.isInteger(occurrence) || occurrence < 1)) {
277
- throw new CliError("scene-ref: --occurrence must be a positive integer.", {
278
- exitCode: EXIT_USAGE,
279
- errorCode: "SCENE_REF_OCCURRENCE_INVALID",
280
- hint: "Use 1 for the first matching scene ref, 2 for the second, and so on.",
281
- data: { expected: ["--occurrence <positive integer> (1-based)"], actual: [occurrenceRaw] },
282
- });
283
- }
284
- if (append && (!stateSet || occurrence !== undefined)) {
285
- throw new CliError("scene-ref: --append requires --state and cannot be combined with --occurrence.", {
286
- exitCode: EXIT_USAGE,
287
- errorCode: "SCENE_REF_APPEND_FLAG_CONFLICT",
288
- hint: "Append a new actor ref with --state <state_id> --append, or target an existing ref with --occurrence <n>.",
289
- data: { expected: ["--state <state_id> --append"], actual: [append ? "--append" : "", occurrence !== undefined ? "--occurrence" : "", clearSet ? "--clear" : "", removeSet ? "--remove" : ""].filter(Boolean) },
290
- });
291
- }
292
- if (removeSet)
293
- return { op: "scene.ref.remove", target, occurrence };
294
- if (clearSet)
295
- return { op: "scene.ref.clear", target, occurrence };
296
- return { op: "scene.ref.set", target, state: f.state === "none" ? "" : f.state, append, occurrence };
297
- }
298
- // v3 dialogue speaker: a single inline speaker — an actor, OR a non-actor kind
299
- // (system|broadcast|offscreen|group) with an optional label.
300
- export function dialogueTemplate(f) {
301
- const actorId = strOf(f.actor).trim();
302
- const speakerKind = strOf(f.kind).trim();
303
- const label = strOf(f.label).trim();
304
- if (actorId && speakerKind) {
305
- throw new CliError("dialogue: --actor and --kind are mutually exclusive.", {
306
- exitCode: EXIT_USAGE,
307
- errorCode: "SPEAKER_AMBIGUOUS",
308
- hint: "Keep --actor for a character, or --kind for a non-actor source.",
309
- data: { expected: ["exactly one of --actor <actor_id> or --kind <non-actor kind>"], actual: ["--actor", "--kind"] },
310
- });
311
- }
312
- if (actorId && label) {
313
- throw new CliError("dialogue: --label is only valid with --kind.", {
314
- exitCode: EXIT_USAGE,
315
- errorCode: "SPEAKER_LABEL_WITHOUT_KIND",
316
- hint: "Remove --label for an actor line, or use --kind for a labeled non-actor source.",
317
- data: { expected: ["omit --label with --actor, or pair --label with --kind"], actual: ["--actor", "--label"] },
318
- });
319
- }
320
- if (actorId)
321
- return { op: "dialogue.speaker.set", actor_id: actorId };
322
- if (speakerKind)
323
- return { op: "dialogue.speaker.set", kind: speakerKind, label: label || undefined };
324
- throw new CliError("dialogue: pass --actor <id> or --kind <system|broadcast|offscreen|group>.", {
325
- exitCode: EXIT_USAGE,
326
- errorCode: "DIALOGUE_SPEAKER_MISSING",
327
- hint: "Set --actor for an actor line, or --kind for a non-actor line.",
328
- data: { expected: ["--actor <actor_id> or --kind <non-actor kind>"], actual: ["<missing>"] },
329
- });
330
- }
331
- // Translate one parsed verb line into a patch op dict (the SAME ops `patch`
332
- // consumes). `do` = the human/agent-friendly notation for those ops: no JSON,
333
- // no field-name guessing — the verbs you already type. Multipolar verbs
334
- // (delete/move/insert/merge/describe) pick their op by the address kind.
335
- function repeatedDoFlag(raw) {
336
- if (raw === undefined)
337
- return [];
338
- return Array.isArray(raw) ? raw.map(strOf) : [strOf(raw)];
339
- }
340
- function doInsertFlags(flags) {
341
- return {
342
- type: flags["type"],
343
- content: flags["content"],
344
- emotion: flags["emotion"],
345
- parenthetical: flags["parenthetical"],
346
- actionId: flags["action-id"],
347
- at: flags["at"],
348
- before: flags["before"],
349
- after: flags["after"],
350
- actor: flags["actor"],
351
- speaker: flags["speaker"],
352
- speakerState: flags["speaker-state"],
353
- kind: flags["kind"],
354
- label: flags["label"],
355
- location: flags["location"],
356
- time: flags["time"],
357
- space: flags["space"],
358
- sceneId: flags["scene-id"],
359
- states: repeatedDoFlag(flags["state"]),
360
- };
361
- }
362
- export function lineToOp(verb, args, flags, scriptVersion = 3) {
363
- const a0 = strOf(args[0]);
364
- const a1 = strOf(args[1]);
365
- const parseAddress = (raw) => scriptVersion === 4 ? parseV4Address(raw) : parseAnyAddress(raw);
366
- switch (verb) {
367
- case "replace":
368
- return flags["regex"]
369
- ? { op: "action.content.regex-replace", at: a0, pattern: regexPattern(strOf(flags["from"])), to: flags["to"] ?? "", all: Boolean(flags["all"]) }
370
- : { op: "action.content.replace", at: a0, from: strOf(flags["from"]), to: flags["to"] ?? "", all: Boolean(flags["all"]) };
371
- case "type":
372
- return { op: "action.type.set", at: a0, type: a1 };
373
- case "actor":
374
- return { op: "action.actor.set", at: a0, actor_id: a1 };
375
- case "transition":
376
- return { ...transitionTemplate(a1, { process: flags["process"], contrast: flags["contrast"], clear: Boolean(flags["clear"]) }), at: a0 };
377
- case "emotion":
378
- if (scriptVersion === 4)
379
- throw doErr("emotion belongs to Script v3; use parenthetical for Script v4");
380
- return { ...emotionTemplate({ emotion: args[1], clear: Boolean(flags["clear"]) }), at: a0 };
381
- case "parenthetical":
382
- if (scriptVersion === 3)
383
- throw doErr("parenthetical belongs to Script v4; use emotion for Script v3");
384
- if (Boolean(flags["remove"]) === (flags["set"] !== undefined)) {
385
- throw doErr("parenthetical needs exactly one of --set <text> or --remove");
386
- }
387
- return Boolean(flags["remove"])
388
- ? { op: "action.parenthetical.remove", at: a0 }
389
- : { op: "action.parenthetical.set", at: a0, parenthetical: strOf(flags["set"]) };
390
- case "timestamp":
391
- return buildTimestampOperation(a0, flags["set"], Boolean(flags["remove"]));
392
- case "scene-ref": {
393
- const sceneRefFlags = {
394
- states: repeatedDoFlag(flags["state"]),
395
- clear: Boolean(flags["clear"]),
396
- remove: Boolean(flags["remove"]),
397
- append: Boolean(flags["append"]),
398
- occurrence: flags["occurrence"],
399
- };
400
- assertSceneRefCommandFlags(scriptVersion, sceneRefFlags);
401
- if (scriptVersion === 4) {
402
- return sceneRefFlags.remove
403
- ? { op: "scene.ref.remove", at: a0, target: a1 }
404
- : { op: "scene.ref.set", at: a0, target: a1, state_ids: sceneRefFlags.states };
405
- }
406
- return {
407
- ...contextTemplate(a1, {
408
- state: sceneRefFlags.states[0],
409
- clear: sceneRefFlags.clear,
410
- remove: sceneRefFlags.remove,
411
- append: sceneRefFlags.append,
412
- occurrence: sceneRefFlags.occurrence,
413
- }),
414
- at: a0,
415
- };
416
- }
417
- case "dialogue":
418
- if (scriptVersion === 3 && flags["state"] !== undefined) {
419
- throw doErr("dialogue --state belongs to Script v4");
420
- }
421
- return {
422
- ...dialogueTemplate({ actor: flags["actor"], kind: flags["kind"], label: flags["label"] }),
423
- ...(scriptVersion === 4 && flags["state"] !== undefined ? { state_id: flags["state"] } : {}),
424
- at: a0,
425
- };
426
- case "rename":
427
- return { op: "asset.rename", target: a0, name: a1 };
428
- case "role":
429
- return { op: "asset.role.set", target: a0, role_type: a1 };
430
- case "worldview":
431
- return { op: "meta.worldview.set", worldview: a0 };
432
- case "synopsis": {
433
- if (args.length === 0)
434
- throw doErr("synopsis needs <text> or <episode_id> <text>");
435
- if (args.length > 2)
436
- throw doErr("synopsis text with spaces must be quoted");
437
- if (args.length === 1) {
438
- if (/^ep_/.test(a0) || /^ep[1-9A-HJ-NP-Za-km-z]{6}$/.test(a0)) {
439
- throw doErr(`synopsis for ${a0} needs text`);
440
- }
441
- return { op: "meta.synopsis.set", synopsis: a0 };
442
- }
443
- const addr = parseAddress(a0);
444
- if (addr.kind !== "episode")
445
- throw doErr(`synopsis target must be an episode id or omitted for global (${a0})`);
446
- return { op: "episode.synopsis.set", episode_id: "id" in addr ? addr.id : addr.episodeId, synopsis: a1 };
447
- }
448
- case "alias": {
449
- const add = flags["add"] ?? [];
450
- const remove = flags["remove"] ?? [];
451
- if (add.length)
452
- return { op: "asset.alias.add", target: a0, alias: add };
453
- if (remove.length)
454
- return { op: "asset.alias.remove", target: a0, alias: remove };
455
- throw doErr("alias needs --add <alias> or --remove <alias>");
456
- }
457
- case "describe": {
458
- const addr = parseAddress(a0);
459
- if (addr.kind === "state")
460
- return { op: "state.describe", target: a0, description: a1 };
461
- if (addr.kind === "asset")
462
- return { op: "asset.describe", target: a0, description: a1 };
463
- throw doErr(`describe cannot operate on a ${addr.kind} address (${a0}); use an asset or asset/state target`);
464
- }
465
- case "extend": {
466
- if (a0 !== "global")
467
- parseAddress(a0);
468
- if (flags["clear"]) {
469
- if (args.length >= 3)
470
- throw doErr("extend --clear takes no value (drop --clear to set, or drop the value to delete)");
471
- return { op: "extend.clear", at: a0, key: a1 || undefined };
472
- }
473
- if (args.length < 3)
474
- throw doErr("extend needs <addr> <key> <value> (or --clear)");
475
- let value = args[2];
476
- if (flags["json-value"]) {
477
- try {
478
- value = JSON.parse(strOf(args[2]));
479
- }
480
- catch {
481
- throw doErr("extend --json-value: value is not valid JSON");
482
- }
483
- }
484
- return { op: "extend.set", at: a0, key: a1, value };
485
- }
486
- case "state-add":
487
- return { op: "state.add", target: a0, name: a1, description: flags["description"], state_id: flags["state-id"] };
488
- case "state-rename":
489
- return { op: "state.rename", target: a0, name: a1 };
490
- case "state-delete":
491
- return { op: "state.delete", target: a0, strategy: flags["strategy"], replacement: flags["replacement"] };
492
- case "add-actor":
493
- return { op: "actor.add", actor_id: flags["id"], name: a0, role_type: flags["role"], description: flags["description"], aliases: flags["alias"] ?? undefined };
494
- case "add-location":
495
- return { op: "location.add", location_id: flags["id"], name: a0, description: flags["description"] };
496
- case "add-prop":
497
- return { op: "prop.add", prop_id: flags["id"], name: a0, description: flags["description"] };
498
- case "add-episode":
499
- return { op: "episode.add", title: flags["title"], episode_id: flags["id"] };
500
- case "importance":
501
- return { op: "importance.set", target: a0, importance: a1 };
502
- case "split":
503
- return scriptVersion === 4
504
- ? { op: "scene.split", at: a0, at_action: flags["at"], new_scene_id: flags["new-scene-id"] }
505
- : { op: "scene.split", at: a0, at_index: Number(flags["at"]), new_scene_id: flags["new-scene-id"] };
506
- case "delete": {
507
- const addr = parseAddress(a0);
508
- if (addr.kind === "action")
509
- return { op: "action.delete", at: a0 };
510
- if (addr.kind === "scene")
511
- return { op: "scene.delete", at: a0, force: Boolean(flags["force"]) };
512
- if (addr.kind === "state")
513
- return { op: "state.delete", target: a0, strategy: flags["strategy"], replacement: flags["replacement"] };
514
- if (addr.kind === "asset")
515
- return { op: "asset.delete", target: a0, strategy: flags["strategy"], replacement: flags["replacement"] };
516
- throw doErr(`delete cannot operate on a ${addr.kind} address (${a0})`);
517
- }
518
- case "move": {
519
- assertMoveCommandFlags(scriptVersion, {
520
- at: flags["at"],
521
- before: flags["before"],
522
- after: flags["after"],
523
- });
524
- const addr = parseAddress(a0);
525
- if (addr.kind === "scene") {
526
- return scriptVersion === 4
527
- ? { op: "scene.move", at: a0, to: a1, before: flags["before"], after: flags["after"] }
528
- : { op: "scene.move", at: a0, to: a1, at_index: flags["at"] };
529
- }
530
- if (addr.kind === "action") {
531
- return scriptVersion === 4
532
- ? { op: "action.move", at: a0, to: a1, before: flags["before"], after: flags["after"] }
533
- : { op: "action.move", at: a0, to: a1 };
534
- }
535
- throw doErr(`move cannot operate on a ${addr.kind} address (${a0}); move an action or a scene`);
536
- }
537
- case "merge": {
538
- const addr = parseAddress(a0);
539
- if (addr.kind === "scene")
540
- return { op: "scene.merge", from: a0, into: strOf(flags["into"]) };
541
- if (addr.kind === "asset")
542
- return { op: "asset.merge", from: a0, into: strOf(flags["into"]) };
543
- throw doErr(`merge cannot operate on a ${addr.kind} address (${a0}); merge two assets or two scenes`);
544
- }
545
- case "insert": {
546
- const addr = parseAddress(a0);
547
- const insertFlags = doInsertFlags(flags);
548
- if (addr.kind === "episode") {
549
- assertInsertCommandFlags(scriptVersion, "scene", insertFlags);
550
- return {
551
- op: "scene.insert",
552
- at: a0,
553
- location: flags["location"],
554
- time: flags["time"],
555
- space: flags["space"],
556
- ...(scriptVersion === 4
557
- ? { location_state_ids: insertFlags.states, before: flags["before"], after: flags["after"] }
558
- : { at_index: flags["at"], before: flags["before"], after: flags["after"] }),
559
- scene_id: flags["scene-id"],
560
- };
561
- }
562
- if (addr.kind === "scene") {
563
- assertInsertCommandFlags(scriptVersion, "action", insertFlags);
564
- return {
565
- op: "action.insert",
566
- at: a0,
567
- type: flags["type"],
568
- content: flags["content"],
569
- before: flags["before"],
570
- after: flags["after"],
571
- actor_id: flags["actor"],
572
- kind: flags["kind"],
573
- label: flags["label"],
574
- ...(scriptVersion === 4
575
- ? {
576
- action_id: flags["action-id"],
577
- state_id: flags["speaker-state"],
578
- parenthetical: flags["parenthetical"],
579
- }
580
- : {
581
- at_index: flags["at"],
582
- speaker_id: flags["speaker"],
583
- emotion: flags["emotion"],
584
- }),
585
- };
586
- }
587
- throw doErr(`insert needs ep_NNN (scene insert) or ep_NNN/scn_NNN (action insert), got a ${addr.kind} address (${a0})`);
588
- }
589
- default:
590
- throw doErr(`unknown verb '${verb}' (structural/edit/create verbs are supported; queries are not)`);
591
- }
592
- }
593
- export function actionAddress(epId, sceneId, idx) {
594
- return `${epId}/${sceneId}#${idx}`;
595
- }
596
- // The action's authored timeline position, carried in extend.timestamp as a
597
- // "M:SS" / "MM:SS" string (episode-local by convention). Empty string when the
598
- // action carries no timestamp. This is the anchor event-level alignment reads:
599
- // an event's span is the delta between its first and last action timestamp.
600
- export function actionTimestamp(action) {
601
- const extend = isDict(action["extend"]) ? action["extend"] : {};
602
- return strOf(extend["timestamp"]).trim();
603
- }
604
- // First and last non-empty action timestamps within a scene, in document order.
605
- // Timestamps are monotonic within an episode, so first = t_start, last = t_end.
606
- export function sceneTimeSpan(scene) {
607
- let t_start = "";
608
- let t_end = "";
609
- for (const action of asList(scene["actions"])) {
610
- const ts = actionTimestamp(action);
611
- if (!ts)
612
- continue;
613
- if (!t_start)
614
- t_start = ts;
615
- t_end = ts;
616
- }
617
- return { t_start, t_end };
618
- }
619
- export function actionDisplayFields(epId, sceneId, idx, action) {
620
- const actorId = actionActorId(action);
621
- const s = isDict(action["speaker"]) ? action["speaker"] : null;
622
- // For a non-actor speaker ({kind,label}) surface it under `speaker`; an actor
623
- // line surfaces under `actor` (its id). Narrative lines have neither.
624
- const speaker = s && !actorId ? (strOf(s["label"]).trim() || strOf(s["kind"]).trim()) : "";
625
- return {
626
- addr: actionAddress(epId, sceneId, idx),
627
- timestamp: actionTimestamp(action),
628
- type: strOf(action["type"]).trim() || "action",
629
- speaker,
630
- actor: actorId,
631
- emotion: strOf(action["emotion"]).trim(),
632
- content: strOf(action["content"]),
633
- };
634
- }
635
- export function formatInspectAction(epId, sceneId, idx, action) {
636
- const fields = actionDisplayFields(epId, sceneId, idx, action);
637
- const addr = strOf(fields["addr"]);
638
- const type = strOf(fields["type"]);
639
- const delivery = strOf(fields["delivery"]);
640
- const tag = delivery ? `${type} ${delivery}` : type;
641
- // Prefer the speaker_id (concrete) over actor_id (asset), and skip both when
642
- // the action is narrative (no speaker). Format kept on a single line so agents
643
- // can grep the output.
644
- const speakerId = strOf(fields["speaker"]);
645
- const actorId = strOf(fields["actor"]);
646
- const who = speakerId || actorId;
647
- const emotion = strOf(fields["emotion"]);
648
- const timestamp = strOf(fields["timestamp"]);
649
- const content = strOf(fields["content"]);
650
- const meta = [tag, timestamp ? `t=${timestamp}` : "", emotion ? `emotion=${emotion}` : "", who].filter((v) => v).join(" ");
651
- const prefix = `${addr} [${meta}]`;
652
- return content ? `${prefix} ${content}` : prefix;
653
- }
654
- // ---------------------------------------------------------------------------
655
- // command_script_patch
656
- // ---------------------------------------------------------------------------
657
- export const SKIPPABLE_EDIT_CODES = new Set([
658
- "REGEX_NO_MATCH",
659
- "FROM_TEXT_NOT_FOUND",
660
- "OVERLAP_DIALOGUE_UNSUPPORTED",
661
- ]);
662
- export function applyPatchOperationsForSession(session, source, operations) {
663
- return applyVersionedMutations(session.version, session.script, source, operations);
664
- }
665
- function v4Counts(script) {
666
- return {
667
- episodes: script.episodes.length,
668
- scenes: script.episodes.reduce((sum, episode) => sum + episode.scenes.length, 0),
669
- actions: script.episodes.reduce((sum, episode) => sum + episode.scenes.reduce((sceneSum, scene) => sceneSum + scene.actions.length, 0), 0),
670
- actors: script.actors.length,
671
- locations: script.locations.length,
672
- props: script.props.length,
673
- states: [...script.actors, ...script.locations, ...script.props]
674
- .reduce((sum, asset) => sum + asset.states.length, 0),
675
- };
676
- }
677
- function v4CanonicalIds(script) {
678
- return [
679
- ...script.actors.flatMap((asset) => [
680
- asset.actor_id,
681
- ...asset.states.map((state) => `${asset.actor_id}/${state.state_id}`),
682
- ]),
683
- ...script.locations.flatMap((asset) => [
684
- asset.location_id,
685
- ...asset.states.map((state) => `${asset.location_id}/${state.state_id}`),
686
- ]),
687
- ...script.props.flatMap((asset) => [
688
- asset.prop_id,
689
- ...asset.states.map((state) => `${asset.prop_id}/${state.state_id}`),
690
- ]),
691
- ...script.episodes.flatMap((episode) => [
692
- episode.episode_id,
693
- ...episode.scenes.flatMap((scene) => [
694
- scene.scene_id,
695
- ...scene.actions.map((action) => action.action_id),
696
- ]),
697
- ]),
698
- ];
699
- }
700
- function orderedIntersection(left, right) {
701
- return left.filter((value) => right.has(value));
702
- }
703
- function v4OperationTargets(operation) {
704
- const values = [];
705
- const isIdentity = (value) => {
706
- if (value === "global")
707
- return true;
708
- if (isV4Id("episode", value)
709
- || isV4Id("scene", value)
710
- || isV4Id("action", value)
711
- || isV4Id("actor", value)
712
- || isV4Id("location", value)
713
- || isV4Id("prop", value))
714
- return true;
715
- const slash = value.indexOf("/");
716
- if (slash < 0 || slash !== value.lastIndexOf("/"))
717
- return false;
718
- const owner = value.slice(0, slash);
719
- const state = value.slice(slash + 1);
720
- return (isV4Id("actor", owner)
721
- || isV4Id("location", owner)
722
- || isV4Id("prop", owner)) && (state === "default" || isV4Id("state", state));
723
- };
724
- const add = (value) => {
725
- if (typeof value !== "string" || value.trim() === "")
726
- return;
727
- const normalized = value.trim();
728
- if (isIdentity(normalized))
729
- values.push(normalized);
730
- };
731
- const first = (...fields) => {
732
- for (const field of fields) {
733
- const value = operation[field];
734
- if (typeof value === "string" && value.trim() !== "")
735
- return value;
736
- }
737
- return undefined;
738
- };
739
- const addState = (ownerValue, stateValue) => {
740
- const owner = strOf(ownerValue).trim();
741
- const state = strOf(stateValue).trim();
742
- if (owner && state)
743
- add(`${owner}/${state}`);
744
- };
745
- const addStates = (ownerValue, stateValues) => {
746
- if (!Array.isArray(stateValues))
747
- return;
748
- stateValues.forEach((state) => addState(ownerValue, state));
749
- };
750
- const addPlacement = () => {
751
- add(operation["before"]);
752
- add(operation["after"]);
753
- };
754
- const kind = strOf(operation["op"]);
755
- switch (kind) {
756
- case "action.parenthetical.set":
757
- case "action.parenthetical.remove":
758
- case "action.timestamp.set":
759
- case "action.timestamp.remove":
760
- case "action.content.replace":
761
- case "action.content.regex-replace":
762
- case "action.type.set":
763
- case "action.delete":
764
- case "action.transition.clear":
765
- add(operation["at"]);
766
- break;
767
- case "action.actor.set":
768
- case "dialogue.speaker.set":
769
- add(operation["at"]);
770
- add(operation["actor_id"]);
771
- addState(operation["actor_id"], operation["state_id"]);
772
- break;
773
- case "action.insert":
774
- add(operation["at"]);
775
- add(first("action_id", "id"));
776
- add(operation["actor_id"]);
777
- addState(operation["actor_id"], operation["state_id"]);
778
- addPlacement();
779
- break;
780
- case "action.move":
781
- add(operation["at"]);
782
- add(operation["to"]);
783
- addPlacement();
784
- break;
785
- case "action.transition.set":
786
- add(operation["at"]);
787
- add(operation["target"]);
788
- break;
789
- case "scene.ref.set":
790
- case "scene.ref.remove":
791
- add(operation["at"]);
792
- add(operation["target"]);
793
- addStates(operation["target"], operation["state_ids"]);
794
- break;
795
- case "actor.add":
796
- add(first("actor_id", "id"));
797
- break;
798
- case "location.add":
799
- add(first("location_id", "id"));
800
- break;
801
- case "prop.add":
802
- add(first("prop_id", "id"));
803
- break;
804
- case "state.add": {
805
- const owner = operation["target"];
806
- add(owner);
807
- addState(owner, first("state_id", "id"));
808
- break;
809
- }
810
- case "state.rename":
811
- case "state.describe":
812
- add(operation["target"]);
813
- break;
814
- case "state.delete": {
815
- const target = strOf(operation["target"]).trim();
816
- add(target);
817
- const slash = target.indexOf("/");
818
- if (slash > 0)
819
- addState(target.slice(0, slash), operation["replacement"]);
820
- break;
821
- }
822
- case "asset.rename":
823
- case "asset.describe":
824
- case "asset.role.set":
825
- case "asset.alias.set":
826
- case "asset.alias.add":
827
- case "asset.alias.remove":
828
- case "importance.set":
829
- add(operation["target"]);
830
- break;
831
- case "asset.merge":
832
- add(first("from", "source"));
833
- add(first("into", "target"));
834
- break;
835
- case "asset.delete":
836
- add(operation["target"]);
837
- if (operation["strategy"] === "replace")
838
- add(operation["replacement"]);
839
- break;
840
- case "episode.add":
841
- add(first("episode_id", "id"));
842
- break;
843
- case "episode.synopsis.set":
844
- add(first("episode_id", "target", "at"));
845
- break;
846
- case "meta.worldview.set":
847
- case "meta.synopsis.set":
848
- add("global");
849
- break;
850
- case "scene.insert": {
851
- const location = first("location", "location_id");
852
- add(first("at", "episode_id"));
853
- add(first("scene_id", "id"));
854
- add(location);
855
- addStates(location, operation["location_state_ids"]);
856
- addPlacement();
857
- break;
858
- }
859
- case "scene.move":
860
- add(operation["at"]);
861
- add(operation["to"]);
862
- addPlacement();
863
- break;
864
- case "scene.delete":
865
- add(operation["at"]);
866
- break;
867
- case "scene.split":
868
- add(operation["at"]);
869
- add(first("at_action", "action_id"));
870
- add(first("new_scene_id", "scene_id"));
871
- break;
872
- case "scene.merge":
873
- add(operation["from"]);
874
- add(operation["into"]);
875
- break;
876
- case "extend.set":
877
- case "extend.clear":
878
- add(operation["at"]);
879
- break;
880
- default:
881
- throw new Error(`V4 plan target mapping is missing for operation ${kind}`);
882
- }
883
- return [...new Set(values)];
884
- }
885
- export function buildV4MutationPlan(session, operations, options = {}) {
886
- if (session.version !== 4) {
887
- throw new CliError("A v4 mutation plan requires Script v4.", {
888
- exitCode: EXIT_USAGE,
889
- errorCode: "V4_PLAN_VERSION_INVALID",
890
- data: { actual: [`Script v${session.version}`] },
891
- });
892
- }
893
- const original = requireStructurallyReadableScriptV4(session.script);
894
- const proposed = structuredClone(original);
895
- const originalIds = v4CanonicalIds(original);
896
- const applied = [];
897
- const steps = [];
898
- for (const [index, operation] of operations.entries()) {
899
- const beforeIds = v4CanonicalIds(proposed);
900
- const beforeSet = new Set(beforeIds);
901
- const before = v4Counts(proposed);
902
- let status = "applied";
903
- try {
904
- applied.push(...applyPatchOperationsV4(proposed, [operation]));
905
- }
906
- catch (error) {
907
- if (error instanceof CliError
908
- && error.errorCode
909
- && options.skipCodes?.has(error.errorCode)) {
910
- status = "skipped";
911
- }
912
- else {
913
- throw error;
914
- }
915
- }
916
- const afterIds = v4CanonicalIds(proposed);
917
- const afterSet = new Set(afterIds);
918
- steps.push({
919
- index,
920
- operation,
921
- targets: v4OperationTargets(operation),
922
- status,
923
- before,
924
- after: v4Counts(proposed),
925
- created_ids: afterIds.filter((id) => !beforeSet.has(id)),
926
- removed_ids: beforeIds.filter((id) => !afterSet.has(id)),
927
- retained_ids: orderedIntersection(beforeIds, afterSet),
928
- });
929
- }
930
- const proposedIds = v4CanonicalIds(proposed);
931
- const originalSet = new Set(originalIds);
932
- const proposedSet = new Set(proposedIds);
933
- const targets = [...new Set(steps.flatMap((step) => step.targets))];
934
- const touched = new Set([
935
- ...targets,
936
- ...steps.flatMap((step) => step.created_ids),
937
- ...steps.flatMap((step) => step.removed_ids),
938
- ]);
939
- const plan = {
940
- version: 1,
941
- script_version: 4,
942
- baseline: session.baselineHash,
943
- operations,
944
- targets,
945
- steps,
946
- before: v4Counts(original),
947
- after: v4Counts(proposed),
948
- created_ids: proposedIds.filter((id) => !originalSet.has(id)),
949
- removed_ids: originalIds.filter((id) => !proposedSet.has(id)),
950
- retained_ids: orderedIntersection(originalIds, proposedSet),
951
- untouched_ids: orderedIntersection(originalIds, proposedSet)
952
- .filter((id) => !touched.has(id)),
953
- validation: validateScriptV4(proposed),
954
- };
955
- return {
956
- plan,
957
- digest: `sha256:${sha256Text(JSON.stringify(sortDeep(plan)))}`,
958
- applied,
959
- };
960
- }
961
- const V4_PLANNED_ID_FIELDS = {
962
- "actor.add": "actor_id",
963
- "location.add": "location_id",
964
- "prop.add": "prop_id",
965
- "state.add": "state_id",
966
- "episode.add": "episode_id",
967
- "scene.insert": "scene_id",
968
- "scene.split": "new_scene_id",
969
- "action.insert": "action_id",
970
- };
971
- export function assertV4PlanHasExplicitNewIds(operations) {
972
- for (const operation of operations) {
973
- const kind = strOf(operation["op"]);
974
- const field = V4_PLANNED_ID_FIELDS[kind];
975
- if (!field || strOf(operation[field]).trim())
976
- continue;
977
- const idKind = field === "new_scene_id" ? "scene" : field.replace(/_id$/, "");
978
- throw new CliError("Planned creation operations require an explicit candidate ID.", {
979
- exitCode: EXIT_USAGE,
980
- errorCode: "V4_PLAN_ID_REQUIRED",
981
- hint: `Generate a candidate with \`scriptctl ids --kind ${idKind} --count 1\`, then include it in the operation.`,
982
- data: { expected: [`${kind}.${field}`], actual: [`${kind}.${field}=<missing>`] },
983
- });
984
- }
985
- }
986
- // ---------------------------------------------------------------------------
987
- // Single-op helpers
988
- // ---------------------------------------------------------------------------
989
- export async function applySingleScriptOpToSession(session, opts, op) {
990
- const plan = strOf(opts["plan"]).trim();
991
- if (plan) {
992
- throw new CliError("Single-point writes do not use plan digests.", {
993
- exitCode: EXIT_USAGE,
994
- errorCode: "MULTI_PLAN_USAGE_INVALID",
995
- hint: "Remove --plan from this single-point edit.",
996
- data: { actual: [plan] },
997
- });
998
- }
999
- return applyScriptOpsToSession(session, opts, [op]);
1000
- }
1001
- export async function applyScriptOpsToSession(session, opts, operations) {
1002
- const workspace = strOf(opts["workspace_path"] || "workspace");
1003
- const applied = applyPatchOperationsForSession(session, scriptSourceText(workspace), operations);
1004
- const opName = applied.length === 1 ? applied[0] : "script.ops";
1005
- const [newRevision, idempotent] = await saveScriptSession(session, opts, opName);
1006
- const validation = validateSession(session);
1007
- await syncValidationResult(session, validation, newRevision);
1008
- const passed = Boolean(validation["passed"]);
1009
- const warnings = mutationValidationWarnings(session, validation);
1010
- // One outcome line: what changed + revision (remote) + validation verdict.
1011
- const rev = session.remote ? `; rev ${newRevision}` : "";
1012
- const resultLine = `${applied.join(", ")} applied${rev}; validation ${passed ? "passed" : "needs repair"}`;
1013
- const issues = summarizeIssues(asList(validation["issues"]));
1014
- const warningLines = summarizeIssues(warnings);
1015
- const report = {
1016
- text: [resultLine, ...warningLines].join("\n"),
1017
- data: {
1018
- op: opName,
1019
- changed: applied.length > 0,
1020
- revision: session.remote ? newRevision : undefined,
1021
- idempotent: session.remote ? idempotent : undefined,
1022
- validation,
1023
- issues,
1024
- warnings,
1025
- script_path: session.artifactLabel,
1026
- },
1027
- };
1028
- return [report, EXIT_OK];
1029
- }
1030
- export async function applySingleScriptOp(opts, op) {
1031
- const session = await loadScriptForEdit(opts);
1032
- return applySingleScriptOpToSession(session, opts, op);
1033
- }
1034
- export function summarizeScriptOp(_script, op) {
1035
- const kind = strOf(op["op"]);
1036
- if (kind === "actor.add")
1037
- return `Added actor ${op["name"] || op["actor_name"]}${op["role_type"] ? ` (${op["role_type"]})` : ""}`;
1038
- if (kind === "location.add")
1039
- return `Added location ${op["name"] || op["location_name"]}`;
1040
- if (kind === "prop.add")
1041
- return `Added prop ${op["name"] || op["prop_name"]}`;
1042
- if (kind === "episode.add")
1043
- return `Added episode${op["episode_id"] ? ` ${op["episode_id"]}` : " (generated ID)"}${op["title"] ? `: ${op["title"]}` : ""}`;
1044
- if (kind === "meta.synopsis.set")
1045
- return "Updated script synopsis";
1046
- if (kind === "episode.synopsis.set")
1047
- return `Updated episode synopsis ${op["episode_id"] ?? op["target"] ?? op["at"]}`;
1048
- if (kind === "state.add")
1049
- return `Added state ${op["state_id"]}: ${op["name"] || op["state_name"]} to ${op["target"]}`;
1050
- if (kind === "importance.set")
1051
- return `Set ${op["target"]} importance to ${op["importance"]}`;
1052
- if (kind === "scene.ref.set")
1053
- return `Set reference ${op["target"]} on ${op["at"]}${op["state"] ? ` (state ${op["state"]})` : ""}`;
1054
- if (kind === "extend.set")
1055
- return `Set extend.${op["key"]} on ${op["at"]}`;
1056
- if (kind === "extend.clear")
1057
- return op["key"] ? `Removed extend.${op["key"]} from ${op["at"]}` : `Cleared extend on ${op["at"]}`;
1058
- if (kind === "action.timestamp.set")
1059
- return `Set timestamp on ${op["at"]}`;
1060
- if (kind === "action.timestamp.remove")
1061
- return `Removed timestamp from ${op["at"]}`;
1062
- if (kind.startsWith("state."))
1063
- return `Applied ${kind}: ${op["target"]}`;
1064
- if (kind.startsWith("dialogue."))
1065
- return `Applied ${kind}: ${op["at"]}`;
1066
- return `Applied ${kind}`;
1067
- }
1068
- // Accept `/re/flags` as-is; wrap a bare pattern as `/pattern/` so
1069
- // `replace --regex --from '^\s*\[[^\]]*\]'` works without the user typing slashes.
1070
- export function regexPattern(raw) {
1071
- const s = raw.trim();
1072
- if (s.length >= 2 && s.startsWith("/") && s.lastIndexOf("/") > 0)
1073
- return s;
1074
- return `/${s}/`;
1075
- }
1076
- // The selector-driven write runner. Resolves `opts` to its matched actions
1077
- // (range/region + predicates) and applies one op template to each, as a single
1078
- // in-memory pass committed once. Guardrail: with no --apply it's a DRY-RUN that
1079
- // reports the blast radius and writes nothing; --apply commits. Per-action
1080
- // "no match here / overlap dialogue" errors are skipped (a sweep); anything else
1081
- // aborts the whole edit before any write. Shared by every selector-capable verb.
1082
- export async function applySelectorEditsToSession(session, opts, template, verbLabel) {
1083
- const workspace = strOf(opts["workspace_path"] || "workspace");
1084
- const apply = Boolean(opts["apply"]);
1085
- const opName = strOf(template["op"]);
1086
- const script = session.script;
1087
- const refs = session.version === 3
1088
- ? resolveActionTargets(script, opts).map((target) => `${target.epId}/${target.sceneId}#${target.idx}`)
1089
- : resolveActionTargetsV4(requireStructurallyReadableScriptV4(script), opts, { allowOrdinals: false })
1090
- .map((target) => target.action.action_id);
1091
- const operations = refs.map((ref) => ({ ...template, at: ref }));
1092
- const multiV4 = session.version === 4 && refs.length > 1;
1093
- const planned = multiV4
1094
- ? buildV4MutationPlan(session, operations, { skipCodes: SKIPPABLE_EDIT_CODES })
1095
- : null;
1096
- const planDigest = planned?.digest ?? null;
1097
- const suppliedPlan = strOf(opts["plan"]).trim();
1098
- if (suppliedPlan && (!multiV4 || !apply)) {
1099
- throw new CliError("A plan digest is only accepted for a v4 multi-target apply.", {
1100
- exitCode: EXIT_USAGE,
1101
- errorCode: "MULTI_PLAN_USAGE_INVALID",
1102
- hint: "Remove --plan, or apply the same v4 multi-target selection that produced the digest.",
1103
- data: { actual: [suppliedPlan] },
1104
- });
1105
- }
1106
- if (multiV4 && apply && !suppliedPlan) {
1107
- throw new CliError("A v4 multi-target write requires its dry-run plan digest.", {
1108
- exitCode: EXIT_USAGE,
1109
- errorCode: "MULTI_PLAN_REQUIRED",
1110
- hint: "Run the same command without --apply, review the full plan, then retry with `--apply --plan <digest>`.",
1111
- data: { expected: [planDigest ?? ""], actual: ["<missing>"] },
1112
- });
1113
- }
1114
- if (multiV4 && apply && suppliedPlan !== planDigest) {
1115
- throw new CliError("The supplied digest does not match the current targets and operations.", {
1116
- exitCode: EXIT_INPUT,
1117
- errorCode: "MULTI_PLAN_MISMATCH",
1118
- hint: "Review the newly computed dry-run plan, then apply its exact digest.",
1119
- data: { expected: [planDigest ?? ""], actual: [suppliedPlan] },
1120
- });
1121
- }
1122
- const source = scriptSourceText(workspace);
1123
- let applied = planned?.plan.steps.filter((step) => step.status === "applied").length ?? 0;
1124
- let skipped = planned?.plan.steps.filter((step) => step.status === "skipped").length ?? 0;
1125
- if (!planned) {
1126
- for (const ref of refs) {
1127
- try {
1128
- applyPatchOperationsForSession(session, source, [{ ...template, at: ref }]);
1129
- applied += 1;
1130
- }
1131
- catch (err) {
1132
- if (err instanceof CliError && err.errorCode && SKIPPABLE_EDIT_CODES.has(err.errorCode)) {
1133
- skipped += 1;
1134
- continue;
1135
- }
1136
- throw err;
1137
- }
1138
- }
1139
- }
1140
- else if (apply) {
1141
- for (const step of planned.plan.steps) {
1142
- if (step.status === "applied") {
1143
- applyPatchOperationsForSession(session, source, [step.operation]);
1144
- }
1145
- }
1146
- }
1147
- const displayedRefs = multiV4 ? refs : refs.slice(0, 12);
1148
- const blast = [
1149
- `verb: ${verbLabel} (${opName})`,
1150
- `matched: ${refs.length} action(s)`,
1151
- `${apply ? "applied" : "would-apply"}: ${applied}`,
1152
- `${apply ? "skipped" : "would-skip"}: ${skipped}`,
1153
- ...(displayedRefs.length ? [`targets: ${displayedRefs.join(", ")}${refs.length > displayedRefs.length ? ` … (+${refs.length - displayedRefs.length} more)` : ""}`] : []),
1154
- ...(planDigest ? [`plan_digest: ${planDigest}`] : []),
1155
- ];
1156
- if (!apply) {
1157
- const legacyValidation = planned ? null : validateSession(session);
1158
- const passed = planned
1159
- ? planned.plan.validation.ok
1160
- : Boolean(legacyValidation?.["passed"]);
1161
- const plannedIssueLines = planned
1162
- ? [...planned.plan.validation.errors, ...planned.plan.validation.warnings]
1163
- .map((issue) => `${issue.path}: ${issue.code} - ${issue.message}`)
1164
- : null;
1165
- const legacyIssueLines = legacyValidation === null
1166
- ? []
1167
- : summarizeIssues(asList(legacyValidation["issues"]));
1168
- const issues = plannedIssueLines ?? legacyIssueLines;
1169
- const hint = refs.length === 0
1170
- ? "Widen the selection with --in, --grep, or predicates."
1171
- : planDigest
1172
- ? `Run again with --apply --plan ${planDigest} to commit this exact plan${passed ? "." : "; validation issues will remain available as follow-up diagnostics."}`
1173
- : `Run again with --apply to commit${passed ? "." : "; validation issues will remain available as follow-up diagnostics."}`;
1174
- const lines = [...blast, `validation: ${passed ? "would pass" : "would need repair"}; no write`, ...issues, hint];
1175
- const report = {
1176
- text: lines.join("\n"),
1177
- data: {
1178
- op: `${opName}.dry-run`,
1179
- changed: false,
1180
- matched: refs.length,
1181
- applied,
1182
- skipped,
1183
- issues,
1184
- script_path: session.artifactLabel,
1185
- ...(planDigest ? {
1186
- baseline: session.baselineHash,
1187
- plan_digest: planDigest,
1188
- operations,
1189
- targets: refs,
1190
- plan: planned?.plan,
1191
- } : {}),
1192
- },
1193
- };
1194
- return [report, EXIT_OK];
1195
- }
1196
- if (refs.length === 0) {
1197
- return [{
1198
- text: [...blast, "Widen the selection with --in, --grep, or predicates."].join("\n"),
1199
- data: {
1200
- op: opName,
1201
- changed: false,
1202
- matched: 0,
1203
- script_path: session.artifactLabel,
1204
- },
1205
- }, EXIT_OK];
1206
- }
1207
- const [newRevision, idempotent] = await saveScriptSession(session, opts, opName);
1208
- const validation = validateSession(session);
1209
- await syncValidationResult(session, validation, newRevision);
1210
- const passed = Boolean(validation["passed"]);
1211
- const warnings = mutationValidationWarnings(session, validation);
1212
- const rev = session.remote ? `; rev ${newRevision}` : "";
1213
- const issues = summarizeIssues(asList(validation["issues"]));
1214
- const warningLines = summarizeIssues(warnings);
1215
- const report = {
1216
- text: [...blast, `validation: ${passed ? "passed" : "needs repair"}${rev}`, ...warningLines].join("\n"),
1217
- data: {
1218
- op: opName,
1219
- changed: applied > 0,
1220
- matched: refs.length,
1221
- applied,
1222
- skipped,
1223
- revision: session.remote ? newRevision : undefined,
1224
- idempotent: session.remote ? idempotent : undefined,
1225
- validation,
1226
- issues,
1227
- warnings,
1228
- script_path: session.artifactLabel,
1229
- ...(planDigest ? {
1230
- baseline: session.baselineHash,
1231
- plan_digest: planDigest,
1232
- operations,
1233
- targets: refs,
1234
- plan: planned?.plan,
1235
- } : {}),
1236
- },
1237
- };
1238
- return [report, EXIT_OK];
1239
- }
1240
- export async function applySelectorEdits(opts, template, verbLabel) {
1241
- const session = await loadScriptForEdit(opts);
1242
- return applySelectorEditsToSession(session, opts, template, verbLabel);
1243
- }
1244
- export { sortDeep };
1245
- // ===========================================================================
1246
- // 0.6.0 plural-noun query commands (replace `commandScriptInspect --target X`)
1247
- // ===========================================================================
1248
- //
1249
- // Each command is a thin read-only wrapper around the underlying script
1250
- // document. They all return a CommandOutput shaped like inspect's existing output but
1251
- // without the `--target` flag — the verb itself encodes the target. Filters
1252
- // use `--in <addr>` (compose with the address parsers) plus per-target
1253
- // predicates (--name / --kind / --has / --grep / --context / --type / --actor
1254
- // / --speaker / --severity / --code / --has-{actor,location,prop}).
1255
- // Resolve the speaker_id → source actor mapping once per call. Used by
1256
- // commandActions's --actor filter when the action speaks via a speaker.
1257
- // v3: a dialogue line carries a single inline speaker — an actor ({actor_id})
1258
- // or a non-actor source ({kind, label?}). These read that shape.
1259
- // The actor id behind an action's speaker, or "" for a non-actor / narrative line.
1260
- export function actionActorId(action) {
1261
- const s = action["speaker"];
1262
- if (isDict(s) && strOf(s["actor_id"]).trim())
1263
- return strOf(s["actor_id"]).trim();
1264
- return "";
1265
- }
1266
- // A human label for the speaker: the actor's name (resolved via `names`), or a
1267
- // non-actor kind's label / kind, or "" when the line has no speaker.
1268
- export function actionSpeakerLabel(action, actorNames) {
1269
- const s = action["speaker"];
1270
- if (!isDict(s))
1271
- return "";
1272
- const actorId = strOf(s["actor_id"]).trim();
1273
- if (actorId)
1274
- return actorNames?.get(actorId) || actorId;
1275
- const kind = strOf(s["kind"]).trim();
1276
- if (kind)
1277
- return strOf(s["label"]).trim() || kind;
1278
- return "";
1279
- }
1280
- export function actorIdsInAction(action) {
1281
- const ids = new Set();
1282
- const id = actionActorId(action);
1283
- if (id)
1284
- ids.add(id);
1285
- return ids;
1286
- }
1287
- // Build a grep matcher. /pattern/flags → RegExp, otherwise literal substring.
1288
- // Pre-flight checks block the common ReDoS shapes before they hit V8's regex
1289
- // engine: nested quantifiers like (a+)+, (a*)+, (a*|b*)+ etc. compile fine
1290
- // but hang the process on adversarial input. Since --grep accepts caller-
1291
- // controlled patterns and runs over every action in scope, the safe move is
1292
- // to reject patterns with quantifier-on-group-with-internal-quantifier and
1293
- // cap the pattern length.
1294
- export function buildGrepMatcher(raw) {
1295
- if (!raw)
1296
- return null;
1297
- const m = /^\/(.+)\/([gimsuy]*)$/.exec(raw);
1298
- if (m) {
1299
- const pattern = m[1];
1300
- if (isDangerousRegex(pattern)) {
1301
- throw new CliError("regex pattern has nested quantifiers (ReDoS risk) or exceeds the length limit.", {
1302
- exitCode: EXIT_USAGE,
1303
- errorCode: "REGEX_UNSAFE",
1304
- hint: "Rewrite the regex to avoid nested quantifiers, or use a literal substring (drop the /…/ wrapper).",
1305
- 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)}`] },
1306
- });
1307
- }
1308
- try {
1309
- const re = new RegExp(pattern, m[2]);
1310
- return (hay) => {
1311
- re.lastIndex = 0;
1312
- return re.test(hay);
1313
- };
1314
- }
1315
- catch {
1316
- // Malformed regex — treat as literal.
1317
- }
1318
- }
1319
- return (hay) => hay.includes(raw);
1320
- }
1321
- export function buildReport(op, lines) {
1322
- const outputLines = lines.length > 0 ? lines : ["No matches."];
1323
- return {
1324
- text: outputLines.join("\n"),
1325
- data: {
1326
- op,
1327
- changed: false,
1328
- },
1329
- };
1330
- }
1331
- export function buildTableReport(op, lines, rowColumns, rows) {
1332
- const report = buildReport(op, lines);
1333
- report.data["row_columns"] = rowColumns;
1334
- report.data["rows"] = rows;
1335
- return report;
1336
- }
1337
- // ----- summary --------------------------------------------------------------
1338
- export function synopsisPreview(text, limit) {
1339
- const oneLine = text.replace(/\s+/g, " ").trim();
1340
- return oneLine.length > limit ? `${oneLine.slice(0, limit)}…` : oneLine;
1341
- }
1342
- export function episodeInSelector(selector, epId, scenes) {
1343
- if (selector.isEmpty)
1344
- return true;
1345
- if (selector.matchesScene(epId, "scn_000000"))
1346
- return true;
1347
- for (const scene of scenes) {
1348
- if (selector.matchesScene(epId, strOf(scene["scene_id"])))
1349
- return true;
1350
- }
1351
- return false;
1352
- }
1353
- export function nameMaps(script) {
1354
- const out = { actor: new Map(), location: new Map(), prop: new Map() };
1355
- for (const a of asList(script["actors"]))
1356
- out.actor.set(strOf(a["actor_id"]), strOf(a["actor_name"]));
1357
- for (const l of asList(script["locations"]))
1358
- out.location.set(strOf(l["location_id"]), strOf(l["location_name"]));
1359
- for (const p of asList(script["props"]))
1360
- out.prop.set(strOf(p["prop_id"]), strOf(p["prop_name"]));
1361
- return out;
1362
- }
1363
- export function formatScene(epId, scene, names) {
1364
- const ctx = sceneRefs(scene);
1365
- const env = isDict(scene["environment"]) ? scene["environment"] : {};
1366
- const space = strOf(env["space"]) || "-";
1367
- const time = strOf(env["time"]) || "-";
1368
- const locations = asList(ctx["locations"]).map((r) => {
1369
- const id = strOf(r["location_id"]);
1370
- return `${id}(${names.location.get(id) || "?"})`;
1371
- });
1372
- const actors = asList(ctx["actors"]).map((r) => {
1373
- const id = strOf(r["actor_id"]);
1374
- return `${id}(${names.actor.get(id) || "?"})`;
1375
- });
1376
- const props = asList(ctx["props"]).map((r) => {
1377
- const id = strOf(r["prop_id"]);
1378
- return `${id}(${names.prop.get(id) || "?"})`;
1379
- });
1380
- const actionCount = asList(scene["actions"]).length;
1381
- const { t_start, t_end } = sceneTimeSpan(scene);
1382
- const timePart = t_start || t_end ? ` t=${t_start || "?"}..${t_end || "?"}` : "";
1383
- return `${epId}/${scene["scene_id"]} [${space} ${time}] location=${locations.join(",") || "-"} actors=${actors.join(",") || "-"} props=${props.join(",") || "-"} actions=${actionCount}${timePart}`;
1384
- }
1385
- export const HAS_FILTERS = new Set(["transition", "speaker"]);
1386
- // Resolve a selection (--in range/region selector + --type/--actor/--speaker/
1387
- // --grep/--has predicates, AND-combined) to the matching actions, in document
1388
- // order. The single matcher behind both `actions` queries and selector-driven
1389
- // writes. Does NOT enforce "at least one filter" — that policy is caller-owned
1390
- // (queries refuse a bare dump; writes gate on --all). Validates the --has value.
1391
- export function resolveActionTargets(script, opts) {
1392
- const selector = parseInSelector(strOf(opts["in"]));
1393
- const timestampRange = actionTimestampFilter(opts);
1394
- const typeFilter = strOf(opts["type"]).trim();
1395
- const actorFilter = strOf(opts["actor"]).trim();
1396
- const hasFilter = strOf(opts["has"]).trim();
1397
- // Whitelist --has: silently accepting unknown values means a typo like
1398
- // "state_changes" (underscore) passed the filter-missing guard but bypassed
1399
- // every concrete predicate, returning the whole script.
1400
- if (hasFilter && !HAS_FILTERS.has(hasFilter)) {
1401
- throw new CliError("--has value invalid.", {
1402
- exitCode: EXIT_USAGE,
1403
- errorCode: "HAS_FILTER_INVALID",
1404
- hint: "Use a supported --has value.",
1405
- data: { expected: [`--has: one of ${[...HAS_FILTERS].join(", ")}`], actual: [hasFilter] },
1406
- });
1407
- }
1408
- const grepMatcher = buildGrepMatcher(strOf(opts["grep"]));
1409
- const out = [];
1410
- for (const ep of asList(script["episodes"])) {
1411
- const epId = strOf(ep["episode_id"]);
1412
- for (const scene of asList(ep["scenes"])) {
1413
- const sceneId = strOf(scene["scene_id"]);
1414
- if (!selector.matchesScene(epId, sceneId))
1415
- continue;
1416
- const actions = asList(scene["actions"]);
1417
- for (let i = 0; i < actions.length; i++) {
1418
- if (!selector.matchesAction(epId, sceneId, i))
1419
- continue;
1420
- const a = actions[i];
1421
- if (timestampRange
1422
- && !actionTimestampMatches(isDict(a["extend"]) ? a["extend"]["timestamp"] : undefined, timestampRange, actionAddress(epId, sceneId, i)))
1423
- continue;
1424
- if (typeFilter && strOf(a["type"]).trim() !== typeFilter)
1425
- continue;
1426
- if (actorFilter && !actorIdsInAction(a).has(actorFilter))
1427
- continue;
1428
- if (hasFilter === "transition" && !isDict(a["transition_prompt"]))
1429
- continue;
1430
- if (hasFilter === "speaker" && !isDict(a["speaker"]))
1431
- continue;
1432
- if (grepMatcher && !grepMatcher(strOf(a["content"])))
1433
- continue;
1434
- out.push({ epId, sceneId, idx: i, action: a });
1435
- }
1436
- }
1437
- }
1438
- return out;
1439
- }
1440
- // Whether a selection in `opts` has any filter at all (scope or predicate).
1441
- export function selectionHasAnyFilter(opts) {
1442
- return Boolean(strOf(opts["in"]).trim() ||
1443
- strOf(opts["grep"]) || strOf(opts["type"]).trim() || strOf(opts["actor"]).trim() ||
1444
- strOf(opts["has"]).trim());
1445
- }
1446
- // Collapse a set of episode ids into sorted, comma-joined ranges:
1447
- // {ep_001, ep_002, ep_003, ep_007} → "ep_001..ep_003,ep_007". Keeps the state
1448
- // arc / appearance lines readable even when an item spans dozens of episodes.
1449
- export function compactEpisodeRanges(ids) {
1450
- const nums = [...new Set([...ids])]
1451
- .map((id) => ({ id, n: idNum(id, "ep") }))
1452
- .filter((x) => Number.isFinite(x.n))
1453
- .sort((a, b) => a.n - b.n);
1454
- if (nums.length === 0)
1455
- return "";
1456
- const parts = [];
1457
- let start = nums[0];
1458
- let prev = nums[0];
1459
- const flush = () => parts.push(start.id === prev.id ? start.id : `${start.id}..${prev.id}`);
1460
- for (let i = 1; i < nums.length; i++) {
1461
- const cur = nums[i];
1462
- if (cur.n === prev.n + 1) {
1463
- prev = cur;
1464
- continue;
1465
- }
1466
- flush();
1467
- start = cur;
1468
- prev = cur;
1469
- }
1470
- flush();
1471
- return parts.join(",");
1472
- }
1473
- // One pass over scene context: for each asset id of `kind`, the set of episodes
1474
- // and count of scenes it is referenced in. "Appearance" = presence in a scene's
1475
- // context (the canonical who/what-is-in-this-scene list direct-init populates).
1476
- export function assetAppearanceCounts(script, kind) {
1477
- const idKey = kind === "actor" ? "actor_id" : kind === "location" ? "location_id" : "prop_id";
1478
- const pluralKey = kind === "actor" ? "actors" : kind === "location" ? "locations" : "props";
1479
- const out = new Map();
1480
- for (const ep of asList(script["episodes"])) {
1481
- const epId = strOf(ep["episode_id"]);
1482
- for (const scene of asList(ep["scenes"])) {
1483
- const ctx = sceneRefs(scene);
1484
- const seen = new Set();
1485
- for (const ref of asList(ctx[pluralKey])) {
1486
- const id = strOf(ref[idKey]);
1487
- if (!id || seen.has(id))
1488
- continue;
1489
- seen.add(id);
1490
- const entry = out.get(id) ?? { episodes: new Set(), scenes: 0 };
1491
- entry.episodes.add(epId);
1492
- entry.scenes += 1;
1493
- out.set(id, entry);
1494
- }
1495
- }
1496
- }
1497
- return out;
1498
- }
1499
- export function listAssetsByKind(script, kind, opts) {
1500
- const lines = [];
1501
- const rows = [];
1502
- const [key, idKey, nameKey] = (() => {
1503
- switch (kind) {
1504
- case "actor": return ["actors", "actor_id", "actor_name"];
1505
- case "location": return ["locations", "location_id", "location_name"];
1506
- case "prop": return ["props", "prop_id", "prop_name"];
1507
- }
1508
- })();
1509
- // Build the set of asset ids referenced inside the --in scope. A range or
1510
- // multi-region selector takes the union of context refs over every matched
1511
- // scene; a bare single action point (e.g. ep_001/scn_003#2) keeps the legacy
1512
- // "narrow to that one action's actor" behavior.
1513
- // WHOLE_SCRIPT ('--in *') means "all assets" — it must NOT narrow to the set
1514
- // of assets referenced in scene context (that would drop registered-but-not-
1515
- // yet-placed assets). Only a real address-region selector narrows.
1516
- let scopeIds = null;
1517
- if (!opts.selector.isEmpty && opts.selector !== WHOLE_SCRIPT) {
1518
- scopeIds = new Set();
1519
- const single = selectorSingleActionPoint(opts.selector);
1520
- const pluralKey = kind === "actor" ? "actors" : kind === "location" ? "locations" : "props";
1521
- for (const ep of asList(script["episodes"])) {
1522
- const epId = strOf(ep["episode_id"]);
1523
- for (const scene of asList(ep["scenes"])) {
1524
- const sceneId = strOf(scene["scene_id"]);
1525
- if (!opts.selector.matchesScene(epId, sceneId))
1526
- continue;
1527
- if (single) {
1528
- // Single action point: matchesScene already isolates the target
1529
- // scene. Legacy narrowing is implemented for actor only.
1530
- if (kind === "actor") {
1531
- const a = asList(scene["actions"])[single.idx];
1532
- const aid = a ? actionActorId(a) : "";
1533
- if (aid)
1534
- scopeIds.add(aid);
1535
- }
1536
- continue;
1537
- }
1538
- const ctx = sceneRefs(scene);
1539
- for (const ref of asList(ctx[pluralKey])) {
1540
- scopeIds.add(strOf(ref[idKey]));
1541
- }
1542
- }
1543
- }
1544
- }
1545
- // Appearance counts (scenes / episodes) computed in one pass, only when asked
1546
- // — keeps the default listing lean.
1547
- const appearances = opts.counts ? assetAppearanceCounts(script, kind) : null;
1548
- for (const asset of asList(script[key])) {
1549
- const id = strOf(asset[idKey]);
1550
- const name = strOf(asset[nameKey]);
1551
- if (opts.id && opts.id !== id)
1552
- continue;
1553
- if (opts.name && !name.includes(opts.name))
1554
- continue;
1555
- if (scopeIds && !scopeIds.has(id))
1556
- continue;
1557
- const aliases = asList(asset["aliases"]).map((s) => strOf(s));
1558
- const role = strOf(asset["role_type"]);
1559
- const importance = strOf(asset["importance"]);
1560
- const descPresent = strOf(asset["description"]).trim() ? "yes" : "missing";
1561
- const states = asList(asset["states"]).length;
1562
- const extra = [];
1563
- if (aliases.length > 0)
1564
- extra.push(`aliases=(${aliases.join(",")})`);
1565
- if (importance)
1566
- extra.push(`importance=${importance}`);
1567
- if (role)
1568
- extra.push(`role=${role}`);
1569
- extra.push(`states=${states}`, `description=${descPresent}`);
1570
- if (appearances) {
1571
- const seen = appearances.get(id);
1572
- const eps = seen ? seen.episodes.size : 0;
1573
- const scns = seen ? seen.scenes : 0;
1574
- const arc = seen && eps > 0 ? ` episodes=${compactEpisodeRanges(seen.episodes)}` : "";
1575
- extra.push(`scenes=${scns}`, `episodes_count=${eps}${arc}`);
1576
- }
1577
- lines.push(`${kind} ${id}: ${name || "-"} ${extra.join(" ")}`);
1578
- const seen = appearances?.get(id);
1579
- rows.push({
1580
- addr: `${kind}:${id}`,
1581
- kind,
1582
- id,
1583
- name,
1584
- aliases,
1585
- importance,
1586
- role,
1587
- states,
1588
- description_present: descPresent === "yes",
1589
- ...(appearances
1590
- ? {
1591
- scenes: seen?.scenes ?? 0,
1592
- episodes_count: seen?.episodes.size ?? 0,
1593
- episodes: seen ? compactEpisodeRanges(seen.episodes) : "",
1594
- }
1595
- : {}),
1596
- });
1597
- }
1598
- return {
1599
- lines,
1600
- rows,
1601
- rowColumns: [
1602
- "addr",
1603
- "kind",
1604
- "id",
1605
- "name",
1606
- "aliases",
1607
- "importance",
1608
- "role",
1609
- "states",
1610
- "description_present",
1611
- ...(appearances ? ["scenes", "episodes_count", "episodes"] : []),
1612
- ],
1613
- };
1614
- }
1615
- export function splitSpeakerList(raw) {
1616
- if (Array.isArray(raw))
1617
- return raw.map((v) => strOf(v)).filter((v) => v);
1618
- return strOf(raw).split(",").map((s) => s.trim()).filter((s) => s);
1619
- }
1620
- export function blankCreateReport(session, validation, idempotent) {
1621
- const passed = Boolean(validation["passed"]);
1622
- const resultLines = [`created: blank script (Script v${session.version})`, `validation: ${passed ? "passed" : "needs repair"}`];
1623
- if (session.remote) {
1624
- resultLines.push(`revision: ${session.revision}`);
1625
- if (idempotent !== null)
1626
- resultLines.push(`idempotent: ${String(idempotent).toLowerCase()}`);
1627
- }
1628
- return {
1629
- text: resultLines.join("\n"),
1630
- data: {
1631
- op: "script.create",
1632
- changed: true,
1633
- validation,
1634
- script_path: session.artifactLabel,
1635
- ...(session.remote ? { revision: session.revision, idempotent } : {}),
1636
- },
1637
- };
1638
- }
1639
- // ----- add-* (register new entities) ----------------------------------------
1640
- // Read the single positional <name> arg shared by add-actor/location/prop, or
1641
- // throw the common ARGS_MISSING usage error with a verb-specific example.
1642
- export function requireNameArg(opts, verb, example) {
1643
- const args = asList(opts["_args"]);
1644
- if (args.length < 1) {
1645
- throw new CliError("Name missing.", {
1646
- exitCode: EXIT_USAGE,
1647
- errorCode: "ARGS_MISSING",
1648
- hint: example,
1649
- data: { expected: ["<name>"], actual: ["<empty>"] },
1650
- });
1651
- }
1652
- return args[0];
1653
- }
1654
- //# sourceMappingURL=lib.js.map