@lingjingai/scriptctl 0.62.0 → 0.62.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,15 @@
1
+ # 0.62.1
2
+
3
+ ## Added
4
+ - `scriptctl refs` and `sc refs` locate asset and appearance references with scene/action addresses, surrounding text, and pagination. Explicit scene bindings, speakers, and textual mentions are reported separately; mentions do not imply presence or a particular appearance.
5
+ - The screenplay SDK exports read-only `references` and `formatReferences`, shared by the CLI and review agents.
6
+ - The Mastra screenplay review agent exposes `refs` during both episode review and whole-series convergence, querying the current in-memory document after edits.
7
+
8
+ ## Changed
9
+ - Review instructions and the packaged scriptctl skill document reference lookup and distinguish read-only `refs` from the binding mutation `ref`.
10
+
11
+ ## Fixed
12
+ - None.
13
+
14
+ ## Breaking
15
+ - None.
package/dist/bin.js CHANGED
@@ -4552,6 +4552,67 @@ function spanAddresses(doc2, actions) {
4552
4552
  });
4553
4553
  }
4554
4554
 
4555
+ // packages/screenplay/dist/references.js
4556
+ function references(doc2, address, opts = {}) {
4557
+ const offset = opts.offset ?? 0, limit = opts.limit ?? 20, context = opts.context ?? 3;
4558
+ for (const [name, value, minimum] of [["offset", offset, 0], ["limit", limit, 1], ["context", context, 0]]) {
4559
+ if (!Number.isSafeInteger(value) || value < minimum)
4560
+ throw new Error(`${name} must be an integer >= ${minimum}`);
4561
+ }
4562
+ const node = resolve6(doc2, address);
4563
+ if (node.t !== "asset" && node.t !== "state")
4564
+ throw new Error("references requires an asset or asset/state address; use read for episodes/scenes/actions");
4565
+ const asset2 = node.asset;
4566
+ const state2 = node.t === "state" ? node.state.id : null;
4567
+ const names = [.../* @__PURE__ */ new Set([asset2.id, asset2.name, ...asset2.aliases])].filter(Boolean);
4568
+ const hits = [];
4569
+ for (const ep of doc2.episodes)
4570
+ for (const scene of ep.scenes) {
4571
+ const bindings = [...scene.location ? [scene.location] : [], ...scene.actors, ...scene.props].filter((ref2) => ref2.id === asset2.id && (state2 === null || ref2.states.includes(state2)));
4572
+ if (bindings.length)
4573
+ hits.push({ kind: "scene_binding", scene, matched: bindings.flatMap((ref2) => ref2.states) });
4574
+ for (const action of scene.actions) {
4575
+ if (action.speaker?.id === asset2.id && (state2 === null || action.speaker.state === state2)) {
4576
+ hits.push({ kind: "speaker", scene, action, matched: [asset2.id] });
4577
+ }
4578
+ if (state2 === null) {
4579
+ const matched = names.filter((name) => action.content.includes(name));
4580
+ if (matched.length)
4581
+ hits.push({ kind: "text_mention", scene, action, matched });
4582
+ }
4583
+ }
4584
+ }
4585
+ const end = offset + limit;
4586
+ return {
4587
+ asset_id: asset2.id,
4588
+ state_id: state2,
4589
+ total: hits.length,
4590
+ next_offset: end < hits.length ? end : null,
4591
+ items: hits.slice(offset, end).map(({ kind, scene, action, matched }) => {
4592
+ const index = action ? scene.actions.indexOf(action) : -1;
4593
+ const nearby = action ? scene.actions.slice(Math.max(0, index - context), index + context + 1) : [];
4594
+ const gutter = Math.max(0, ...nearby.map((row) => row.anchor.length));
4595
+ return {
4596
+ kind,
4597
+ address: action?.anchor ?? scene.anchor,
4598
+ scene_address: scene.anchor,
4599
+ episode: scene.ep.no,
4600
+ matched,
4601
+ text: [formatSceneHead(doc2, scene), ...nearby.map((row) => (row === action ? "> " : " ") + formatAction(doc2, row, gutter))].join("\n")
4602
+ };
4603
+ })
4604
+ };
4605
+ }
4606
+ function formatReferences(result) {
4607
+ return [
4608
+ `${result.asset_id}${result.state_id === null ? "" : "/" + result.state_id} ${result.total} references \xB7 showing ${result.items.length}`,
4609
+ "scene_binding=explicit scene presence; speaker=explicit speaker; text_mention=name/alias mention only (not proof of presence).",
4610
+ ...result.items.map((hit) => `${hit.address} ${hit.kind} ep=${hit.episode}
4611
+ ${hit.text}`),
4612
+ result.next_offset === null ? "end" : `Continue: --offset ${result.next_offset}`
4613
+ ].join("\n\n");
4614
+ }
4615
+
4555
4616
  // packages/screenplay/dist/tools.js
4556
4617
  var NON_ACTOR_NAMES = ["\u65C1\u767D", "\u5E7F\u64AD", "\u753B\u5916", "\u7FA4\u58F0"];
4557
4618
  var NON_ACTOR_KIND = {
@@ -5679,6 +5740,15 @@ ${issues(d, {})}`
5679
5740
  ...opts["full"] ? { full: true } : {}
5680
5741
  }), "find"), state2));
5681
5742
  describeArguments(find2, ["\u6B63\u5219\uFF1B\u53EA\u6309 speaker/type \u8FC7\u6EE4\u65F6\u53EF\u7701\u7565"]);
5743
+ const refs = withScriptOpts(program.command("refs <addr>"), "read").description("\u53EA\u8BFB\u5B9A\u4F4D\u8D44\u4EA7/\u9020\u578B\u7684\u573A\u666F\u7ED1\u5B9A\u3001\u8BF4\u8BDD\u5F15\u7528\u548C\u6B63\u6587\u63D0\u53CA\uFF0C\u8FD4\u56DE\u53EF read \u7684\u5730\u5740\u53CA\u4E0A\u4E0B\u6587").option("--offset <n>", "\u4ECE\u7B2C\u51E0\u6761\u5F15\u7528\u7EE7\u7EED\uFF08\u4ECE 0 \u5F00\u59CB\uFF09").option("--limit <n>", "\u672C\u6279\u5F15\u7528\u6570\uFF08\u9ED8\u8BA4 20\uFF09").option("--context <n>", "\u6B63\u6587\u547D\u4E2D\u524D\u540E\u5404\u51E0\u6761 action\uFF08\u9ED8\u8BA4 3\uFF09").action(dispatch((opts) => {
5744
+ const result = references(doc(opts), arg(opts), {
5745
+ offset: num(opts, "offset"),
5746
+ limit: num(opts, "limit"),
5747
+ context: num(opts, "context")
5748
+ });
5749
+ return [{ text: formatReferences(result), data: { op: "refs", changed: false, ...result } }, EXIT_OK];
5750
+ }, state2));
5751
+ describeArguments(refs, ["\u4EBA\u7269/\u573A\u666F/\u9053\u5177 ID \u6216\u540D\u79F0\uFF0C\u6216 <\u8D44\u4EA7>/<\u9020\u578B>\uFF1B\u6B63\u6587\u63D0\u53CA\u4E0D\u7B49\u4E8E\u5B9E\u9645\u51FA\u573A"]);
5682
5752
  const span2 = withScriptOpts(program.command("span <range>"), "read").description("\u628A\u4E00\u6BB5 action \u6362\u7B97\u6210\u96C6\u5185\u89C6\u9891\u65F6\u95F4\u7A97\u53E3\uFF08\u534A\u5F00\u533A\u95F4\uFF09").action(dispatch((opts) => text(() => span(doc(opts), arg(opts)), "span"), state2));
5683
5753
  describeArguments(span2, [`${ADDR}\uFF0C\u6216 \`\u8D77ID..\u6B62ID\``]);
5684
5754
  withScriptOpts(program.command("validate"), "read").description("\u8DD1\u6574\u672C\u6821\u9A8C").action(dispatch((opts) => text(() => validate(doc(opts)), "validate"), state2));