@oh-story/dsh 0.1.17 → 0.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -14
- package/lib/client.js +147 -96
- package/lib/client.js.map +3 -3
- package/lib/drama/manifest.json +77 -247
- package/lib/drama/skills/short-drama/SKILL.md +9 -1
- package/lib/drama/skills/short-drama/references/creator-documents.md +51 -23
- package/lib/drama/skills/short-drama/references/reference-roles.md +1 -1
- package/lib/drama/skills/short-drama/scripts/creator_markdown_check.py +442 -129
- package/lib/drama/skills/short-drama/scripts/project_tool.py +54 -1
- package/lib/drama/skills/short-drama-assets/SKILL.md +2 -6
- package/lib/drama/skills/short-drama-assets/references/continuity-lock.md +9 -3
- package/lib/drama/skills/short-drama-assets/references/era-anchors.md +3 -3
- package/lib/drama/skills/short-drama-assets/references/location-and-view.md +4 -0
- package/lib/drama/skills/short-drama-develop/references/adaptation-craft.md +2 -2
- package/lib/drama/skills/short-drama-develop/references/episode-design.md +19 -4
- package/lib/drama/skills/short-drama-develop/references/genre-cards//347/263/273/347/273/237/346/265/201.md +1 -1
- package/lib/drama/skills/short-drama-edit/SKILL.md +1 -1
- package/lib/drama/skills/short-drama-edit/scripts/edit_tool.py +28 -6
- package/lib/drama/skills/short-drama-edit/scripts/selftest.py +1 -1
- package/lib/drama/skills/short-drama-image-prompts/SKILL.md +1 -5
- package/lib/drama/skills/short-drama-novel-analyze/references/aggregation-and-entities.md +2 -2
- package/lib/drama/skills/short-drama-produce/SKILL.md +2 -0
- package/lib/drama/skills/short-drama-review/SKILL.md +0 -4
- package/lib/drama/skills/short-drama-review/references/production-quality-gates.md +1 -1
- package/lib/drama/skills/short-drama-storyboard/SKILL.md +9 -9
- package/lib/drama/skills/short-drama-storyboard/references/blocking-playbooks.md +43 -13
- package/lib/drama/skills/short-drama-storyboard/references/keyframe-craft.md +5 -5
- package/lib/drama/skills/short-drama-storyboard/references/production-shot-grammar.md +5 -5
- package/lib/drama/skills/short-drama-storyboard/references/shot-craft.md +27 -3
- package/lib/drama/skills/short-drama-storyboard/references/stage-contract.md +2 -1
- package/lib/drama/skills/short-drama-video-prompts/SKILL.md +6 -8
- package/lib/drama/skills/short-drama-video-prompts/references/camera-audio-continuity.md +16 -1
- package/lib/drama/skills/short-drama-video-prompts/references/delivery-profile.md +23 -6
- package/lib/drama/skills/short-drama-video-prompts/references/motion-recipe.md +2 -2
- package/lib/drama/skills/short-drama-video-prompts/references/production-prompt-grammar.md +8 -1
- package/lib/drama/skills/short-drama-video-prompts/references/seedance-2.0.md +41 -2
- package/lib/drama/skills/short-drama-video-prompts/references/seedance-2.5.md +1 -1
- package/lib/drama/skills/short-drama-video-prompts/references/target-model-profile.md +5 -1
- package/lib/drama/skills/short-drama-write/SKILL.md +7 -3
- package/lib/drama/skills/short-drama-write/references/screenplay-format.md +1 -1
- package/lib/drama/skills/short-drama-write/scripts/duration_estimate.py +94 -1
- package/lib/drama/skills/short-drama-write/scripts/screenplay_index.py +13 -4
- package/lib/drama/skills/short-drama-write/scripts/selftest.py +3 -77
- package/lib/index.js +18 -14
- package/lib/index.js.map +2 -2
- package/lib/novel-to-game/README.md +20 -34
- package/lib/novel-to-game/README_ZH.md +20 -34
- package/lib/novel-to-game/VERSION +1 -1
- package/lib/novel-to-game/examples/jin-ping-mei/build/BUILD_BRIEF.md +2 -6
- package/lib/novel-to-game/examples/jin-ping-mei/build/app/js/audio.js +33 -39
- package/lib/novel-to-game/examples/jin-ping-mei/qa/README.md +2 -2
- package/lib/novel-to-game/manifest.json +46 -46
- package/lib/novel-to-game/skills/game-art-direction/SKILL.md +1 -1
- package/lib/novel-to-game/skills/game-build/references/baked-sprite-workflow.md +2 -3
- package/lib/novel-to-game/skills/game-build/references/blender-asset-workflow.md +6 -7
- package/lib/novel-to-game/skills/game-build/references/build-brief-contract.md +2 -2
- package/lib/novel-to-game/skills/game-build/references/generative-media-pipeline.md +1 -4
- package/lib/novel-to-game/skills/game-build/references/playable-model-contract.md +1 -3
- package/lib/novel-to-game/skills/game-build/references/tts-production-contract.md +1 -3
- package/lib/novel-to-game/skills/game-concept/SKILL.md +1 -1
- package/lib/novel-to-game/skills/game-qa/SKILL.md +3 -4
- package/lib/novel-to-game/skills/game-qa/references/qa-contract.md +1 -1
- package/lib/novel-to-game/skills/game-qa/references/test-design-method.md +3 -2
- package/lib/novel-to-game/skills/novel-game-analyze/SKILL.md +13 -14
- package/lib/novel-to-game/skills/novel-game-analyze/references/gameability-protocol.md +1 -2
- package/lib/novel-to-game/skills/novel-to-game/SKILL.md +4 -4
- package/lib/novel-to-game/skills/novel-to-game/references/intake-method.md +2 -3
- package/lib/novel-to-game/skills/novel-to-game/references/pipeline-contract.md +0 -8
- package/lib/oh-story/manifest.json +49 -49
- package/lib/oh-story/skills/story/SKILL.md +2 -2
- package/lib/oh-story/skills/story/VERSION +1 -1
- package/lib/oh-story/skills/story-deslop/SKILL.md +2 -2
- package/lib/oh-story/skills/story-import/SKILL.md +5 -5
- package/lib/oh-story/skills/story-import/references/deep-analysis.md +1 -1
- package/lib/oh-story/skills/story-import/references/import-report.md +1 -1
- package/lib/oh-story/skills/story-import/references/import-tracking.md +1 -1
- package/lib/oh-story/skills/story-import/references/outline-reverse.md +1 -1
- package/lib/oh-story/skills/story-import/scripts/tracking_commit.py +6 -1
- package/lib/oh-story/skills/story-long-analyze/SKILL.md +2 -2
- package/lib/oh-story/skills/story-long-write/SKILL.md +2 -2
- package/lib/oh-story/skills/story-long-write/references/agent-calls.md +3 -3
- package/lib/oh-story/skills/story-long-write/references/tracking-transaction.md +2 -2
- package/lib/oh-story/skills/story-long-write/scripts/tracking_commit.py +6 -1
- package/lib/oh-story/skills/story-review/SKILL.md +8 -7
- package/lib/oh-story/skills/story-review/references/agent-prompts.md +7 -7
- package/lib/oh-story/skills/story-review/references/tracking-transaction.md +2 -2
- package/lib/oh-story/skills/story-review/scripts/tracking_commit.py +6 -1
- package/lib/oh-story/skills/story-setup/SKILL.md +6 -6
- package/lib/oh-story/skills/story-short-write/SKILL.md +2 -2
- package/lib/oh-story/skills/story-short-write/references/agent-calls.md +3 -3
- package/lib/oh-story/skills/story-short-write/references/workflow-design.md +2 -2
- package/lib/oh-story/skills/story-short-write/references/workflow-revision.md +1 -1
- package/lib/types/client/game-preview-state.d.ts +34 -0
- package/lib/types/client/game-preview-state.d.ts.map +1 -0
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/video-studio.d.ts +24 -0
- package/lib/types/client/video-studio.d.ts.map +1 -1
- package/lib/types/host-python.d.ts +10 -3
- package/lib/types/host-python.d.ts.map +1 -1
- package/lib/types/workspace-route.d.ts +6 -0
- package/lib/types/workspace-route.d.ts.map +1 -1
- package/package.json +21 -21
- package/lib/drama/skills/short-drama-assets/assets/character-look.example.jsonl +0 -3
- package/lib/drama/skills/short-drama-assets/assets/continuity.example.jsonl +0 -4
- package/lib/drama/skills/short-drama-assets/assets/decisions.example.jsonl +0 -5
- package/lib/drama/skills/short-drama-assets/assets/location-view.example.jsonl +0 -3
- package/lib/drama/skills/short-drama-assets/assets/occurrences.example.jsonl +0 -5
- package/lib/drama/skills/short-drama-assets/assets/prop-state.example.jsonl +0 -3
- package/lib/drama/skills/short-drama-assets/examples/minimal/characters.jsonl +0 -2
- package/lib/drama/skills/short-drama-assets/examples/minimal/looks.jsonl +0 -2
- package/lib/drama/skills/short-drama-assets/scripts/asset_check.py +0 -267
- package/lib/drama/skills/short-drama-assets/scripts/selftest.py +0 -89
- package/lib/drama/skills/short-drama-image-prompts/examples/minimal-image-prompt-specs.jsonl +0 -2
- package/lib/drama/skills/short-drama-image-prompts/scripts/image_prompt_check.py +0 -443
- package/lib/drama/skills/short-drama-image-prompts/scripts/selftest.py +0 -95
- package/lib/drama/skills/short-drama-review/assets/finding-template.jsonl +0 -2
- package/lib/drama/skills/short-drama-review/assets/supersession-decision.example.json +0 -42
- package/lib/drama/skills/short-drama-review/assets/verdict-template.json +0 -32
- package/lib/drama/skills/short-drama-review/examples/minimal-findings.jsonl +0 -2
- package/lib/drama/skills/short-drama-review/examples/minimal-verdict.json +0 -34
- package/lib/drama/skills/short-drama-review/scripts/review_check.py +0 -325
- package/lib/drama/skills/short-drama-review/scripts/selftest.py +0 -87
- package/lib/drama/skills/short-drama-storyboard/assets/coverage-audition.example.jsonl +0 -2
- package/lib/drama/skills/short-drama-storyboard/assets/revision-lineage.fragment.json +0 -12
- package/lib/drama/skills/short-drama-storyboard/assets/scene-visual-plan.example.jsonl +0 -2
- package/lib/drama/skills/short-drama-storyboard/scripts/selftest.py +0 -191
- package/lib/drama/skills/short-drama-storyboard/scripts/storyboard_check.py +0 -824
- package/lib/drama/skills/short-drama-video-prompts/assets/coverage-scope.fragment.json +0 -21
- package/lib/drama/skills/short-drama-video-prompts/assets/motion-terminal.example.jsonl +0 -2
- package/lib/drama/skills/short-drama-video-prompts/assets/performance.fragment.json +0 -38
- package/lib/drama/skills/short-drama-video-prompts/examples/minimal-music-specs.jsonl +0 -2
- package/lib/drama/skills/short-drama-video-prompts/scripts/container_check.py +0 -329
- package/lib/drama/skills/short-drama-video-prompts/scripts/motion_timing_check.py +0 -451
- package/lib/drama/skills/short-drama-video-prompts/scripts/music_spec_check.py +0 -327
- package/lib/drama/skills/short-drama-video-prompts/scripts/selftest.py +0 -82
- package/lib/drama/skills/short-drama-write/scripts/voice_sheet_check.py +0 -416
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""Offline self-test for screenplay indexing and
|
|
2
|
+
"""Offline self-test for screenplay indexing and duration estimates."""
|
|
3
3
|
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|
|
6
|
-
import hashlib
|
|
7
6
|
import json
|
|
8
7
|
import sys
|
|
9
8
|
import tempfile
|
|
@@ -11,7 +10,6 @@ from pathlib import Path
|
|
|
11
10
|
|
|
12
11
|
from duration_estimate import StaleIndex, estimate, index_blocks
|
|
13
12
|
from screenplay_index import build_index
|
|
14
|
-
from voice_sheet_check import check
|
|
15
13
|
|
|
16
14
|
MINIMUM_PYTHON = (3, 9)
|
|
17
15
|
if sys.version_info < MINIMUM_PYTHON:
|
|
@@ -23,12 +21,6 @@ def require(condition: bool, message: str) -> None:
|
|
|
23
21
|
raise AssertionError(message)
|
|
24
22
|
|
|
25
23
|
|
|
26
|
-
def codes(result: dict[str, object]) -> set[str]:
|
|
27
|
-
findings = result["findings"]
|
|
28
|
-
assert isinstance(findings, list)
|
|
29
|
-
return {finding["code"] for finding in findings}
|
|
30
|
-
|
|
31
|
-
|
|
32
24
|
def measure_text(body: str, project: dict[str, object] | None = None) -> dict[str, object]:
|
|
33
25
|
"""Index a screenplay the documented way, then estimate from that index.
|
|
34
26
|
|
|
@@ -85,7 +77,7 @@ def test_duration_uses_the_projects_own_rates() -> None:
|
|
|
85
77
|
|
|
86
78
|
|
|
87
79
|
def test_production_tags_are_not_performed_time() -> None:
|
|
88
|
-
report = measure_text("[画面文字]
|
|
80
|
+
report = measure_text("[画面文字] 店门告示:暂停营业\n\n他把门关上。\n")
|
|
89
81
|
require(report["counts"]["production_tag_lines"] == 1, "tag counted separately")
|
|
90
82
|
require(report["counts"]["action_paragraphs"] == 1, "tag is not an action")
|
|
91
83
|
|
|
@@ -146,72 +138,6 @@ def main() -> int:
|
|
|
146
138
|
speakers=["陈予安"],
|
|
147
139
|
)
|
|
148
140
|
require(summary["review_status"] == "clean", "valid screenplay index")
|
|
149
|
-
index_bytes = index_path.read_bytes()
|
|
150
|
-
records = [
|
|
151
|
-
json.loads(line) for line in index_bytes.decode("utf-8").splitlines()
|
|
152
|
-
]
|
|
153
|
-
dialogue = next(record for record in records if record.get("kind") == "dialogue")
|
|
154
|
-
|
|
155
|
-
header = {
|
|
156
|
-
"record_type": "sources",
|
|
157
|
-
"schema_version": "1.0.0",
|
|
158
|
-
"sources": {
|
|
159
|
-
"screenplay-index": {
|
|
160
|
-
"owner": "short-drama-write",
|
|
161
|
-
"artifact": "剧集/EP001/screenplay-index.jsonl",
|
|
162
|
-
"hash": hashlib.sha256(index_bytes).hexdigest(),
|
|
163
|
-
}
|
|
164
|
-
},
|
|
165
|
-
}
|
|
166
|
-
line = {
|
|
167
|
-
"line_id": "LINE-001",
|
|
168
|
-
"channel": "sync",
|
|
169
|
-
"speaker_display": "陈予安",
|
|
170
|
-
"line_text": "我回来了。",
|
|
171
|
-
"source_ref": {"src": "screenplay-index", "record_id": dialogue["block_id"]},
|
|
172
|
-
}
|
|
173
|
-
sheet = [header, line]
|
|
174
|
-
result = check(sheet, records, screenplay.read_bytes())
|
|
175
|
-
require(result["status"] == "pass", "faithful voice sheet")
|
|
176
|
-
require(result["lines"] == 1, "the sources header is not a voice line")
|
|
177
|
-
|
|
178
|
-
# A sheet written before the compact form still resolves; real projects
|
|
179
|
-
# hold both spellings and neither is rewritten.
|
|
180
|
-
expanded = [
|
|
181
|
-
dict(
|
|
182
|
-
line,
|
|
183
|
-
source_ref={
|
|
184
|
-
"owner": "short-drama-write",
|
|
185
|
-
"artifact": "剧集/EP001/screenplay-index.jsonl",
|
|
186
|
-
"hash": hashlib.sha256(index_bytes).hexdigest(),
|
|
187
|
-
"record_id": dialogue["block_id"],
|
|
188
|
-
},
|
|
189
|
-
)
|
|
190
|
-
]
|
|
191
|
-
require(
|
|
192
|
-
check(expanded, records, screenplay.read_bytes())["status"] == "pass",
|
|
193
|
-
"expanded voice sheet",
|
|
194
|
-
)
|
|
195
|
-
|
|
196
|
-
undeclared = [header, dict(line, source_ref={"src": "screenplay", "record_id": "X"})]
|
|
197
|
-
require(
|
|
198
|
-
"VOICE_SOURCE_REF_UNDECLARED"
|
|
199
|
-
in codes(check(undeclared, records, screenplay.read_bytes())),
|
|
200
|
-
"src without a sources entry was not detected",
|
|
201
|
-
)
|
|
202
|
-
|
|
203
|
-
unbound = [header, dict(line, source_ref={"record_id": dialogue["block_id"]})]
|
|
204
|
-
require(
|
|
205
|
-
"VOICE_SOURCE_REF_MISSING"
|
|
206
|
-
in codes(check(unbound, records, screenplay.read_bytes())),
|
|
207
|
-
"source_ref naming no upstream snapshot was not detected",
|
|
208
|
-
)
|
|
209
|
-
|
|
210
|
-
changed = [header, dict(line, line_text="我走了。")]
|
|
211
|
-
require(
|
|
212
|
-
check(changed, records, screenplay.read_bytes())["status"] == "fail",
|
|
213
|
-
"changed voice line was not detected",
|
|
214
|
-
)
|
|
215
141
|
|
|
216
142
|
test_duration_reports_counts_without_rates()
|
|
217
143
|
test_duration_uses_the_projects_own_rates()
|
|
@@ -221,7 +147,7 @@ def main() -> int:
|
|
|
221
147
|
test_comments_are_not_production_content()
|
|
222
148
|
test_an_index_from_other_bytes_is_refused()
|
|
223
149
|
|
|
224
|
-
print("
|
|
150
|
+
print("8 self-tests passed")
|
|
225
151
|
return 0
|
|
226
152
|
|
|
227
153
|
|
package/lib/index.js
CHANGED
|
@@ -129,7 +129,7 @@ var DSH_SKILL_BRIDGE = [
|
|
|
129
129
|
"Never start another Agent runtime, session transport, Dashboard, SSE stream, polling loop, or model configuration.",
|
|
130
130
|
"All seven upstream Oh Story specialist Roles are bundled. Invoke one with oh_story_role and a self-contained prompt.",
|
|
131
131
|
"Never inspect .claude/agents, .codex/agents, .opencode/agents, .agents/agents, .zcode, or .story-deployed to decide whether a Role is available.",
|
|
132
|
-
"Oh Story Roles are reached only through oh_story_role. Never start one through a generic subagent or Task tool \u2014 not DSH's subagent or subagent_fork tools and not
|
|
132
|
+
"Oh Story Roles are reached only through oh_story_role. Never start one through a generic subagent or Task tool \u2014 not DSH's subagent or subagent_fork tools, not invoke_subagent, and not an Agent tool \u2014 and never pass a Role name as subagent_type, agent_type, agent, or TypeName, even where the upstream text below describes that for another host.",
|
|
133
133
|
"Use only DSH-visible tools. DSH sandbox and permission policy remain authoritative.",
|
|
134
134
|
// Upstream deploys these 「与作者协作」 rules only in its CLAUDE.md/AGENTS.md
|
|
135
135
|
// templates, which DSH does not install.
|
|
@@ -166,7 +166,7 @@ var DSH_DRAMA_BRIDGE = [
|
|
|
166
166
|
"The \u77ED\u5267 tab is the creator workspace. Never start dashboard_server.py, another web server, Dashboard, Agent runtime, session transport, or model configuration.",
|
|
167
167
|
"Drama Skills uses a creator-first contract: each episode keeps only the requested documents, up to five creator-facing sources at \u5267\u96C6/<EP>/\u5267\u672C.md, \u89C6\u89C9\u8BBE\u5B9A.md, \u5206\u955C.md, \u56FE\u7247\u63D0\u793A\u8BCD.md, and \u89C6\u9891\u63D0\u793A\u8BCD.md. Never precreate empty documents, backfill nominal stages, or start work the creator did not request. Persisted reviews use creator-readable Markdown under \u5BA1\u67E5/; an oral review writes nothing.",
|
|
168
168
|
"\u5267\u96C6/<EP>/\u526A\u8F91\u5355.md is the v0.7 assembly record, not a sixth creative truth: the five creator documents stay the creative truth. It is written after readable media exists and records what reaches the cut \u2014 which footage or accepted static keyframes are kept or left unused and why, each cut's in/out timing, its subtitles, \u753B\u9762\u6587\u5B57 overlays, \u97F3\u6548 cues, \u914D\u97F3 and \u73AF\u5883\u58F0, post-processing such as shot-match correction or an external mix, and the delivery spec including optional \u9897\u7C92 grain and \u63A5\u955C\u5339\u914D. It never changes a line, a shot's job, or a declared duration; changing any of those means returning to the document that owns it.",
|
|
169
|
-
"For a v0.6 project, never create a parallel JSON/JSONL lifecycle truth, indexes, fingerprints, coverage tables, or QA records
|
|
169
|
+
"For a v0.6 project, never create a parallel JSON/JSONL lifecycle truth, indexes, fingerprints, coverage tables, or QA records; Drama 0.9.1 no longer bundles the legacy JSON checkers, and creator_markdown_check.py is the structural check.",
|
|
170
170
|
"Never upgrade a v0.5 structured project in place or mix both contracts in one project root. Keep legacy production/audit artifacts read-only and pinned to v0.5; migrate only into a new creator-first root with manual per-episode creator confirmation.",
|
|
171
171
|
"Use only tools visible in the current DSH preset and preserve the upstream project ownership, freshness, review, and explicit production-confirmation contracts.",
|
|
172
172
|
"Use oh_story_production only for semantic production-view intents (open/focus, explicit shot order, or tracking a job that this Agent is actually executing). Cosmetic canvas layout remains creator-controlled. The tool changes only the Session projection: it does not edit creator documents, generate media, or authorize production.",
|
|
@@ -489,6 +489,8 @@ function createVideoRecapSkillProvider(skillRoot = defaultVideoRecapSkillRoot())
|
|
|
489
489
|
import { execFile } from "node:child_process";
|
|
490
490
|
import { promisify } from "node:util";
|
|
491
491
|
var execFileAsync = promisify(execFile);
|
|
492
|
+
var DRAMA_PYTHON = [3, 9];
|
|
493
|
+
var VIDEO_PYTHON = [3, 10];
|
|
492
494
|
async function commandOutput(command, args) {
|
|
493
495
|
try {
|
|
494
496
|
const { stdout, stderr } = await execFileAsync(command, [...args], { encoding: "utf8", timeout: 5e3, maxBuffer: 4 * 1024 * 1024 });
|
|
@@ -497,21 +499,22 @@ async function commandOutput(command, args) {
|
|
|
497
499
|
return void 0;
|
|
498
500
|
}
|
|
499
501
|
}
|
|
500
|
-
function pythonVersion(value) {
|
|
502
|
+
function pythonVersion(value, floor) {
|
|
503
|
+
const minimum = `${String(floor[0])}.${String(floor[1])}`;
|
|
501
504
|
const match = /Python\s+(\d+)\.(\d+)(?:\.(\d+))?/u.exec(value ?? "");
|
|
502
|
-
if (match === null) return { ok: false };
|
|
505
|
+
if (match === null) return { ok: false, minimum };
|
|
503
506
|
const major = Number(match[1]);
|
|
504
507
|
const minor = Number(match[2]);
|
|
505
|
-
return { ok: major >
|
|
508
|
+
return { ok: major > floor[0] || major === floor[0] && minor >= floor[1], version: match[0].replace(/^Python\s+/u, ""), minimum };
|
|
506
509
|
}
|
|
507
|
-
async function hostPython(probe = commandOutput) {
|
|
510
|
+
async function hostPython(floor, probe = commandOutput) {
|
|
508
511
|
let fallback;
|
|
509
512
|
for (const command of ["python3", "python"]) {
|
|
510
|
-
const parsed = pythonVersion(await probe(command, ["--version"]));
|
|
513
|
+
const parsed = pythonVersion(await probe(command, ["--version"]), floor);
|
|
511
514
|
if (parsed.ok) return { command, probe: parsed };
|
|
512
515
|
if (parsed.version !== void 0) fallback ??= { command, probe: parsed };
|
|
513
516
|
}
|
|
514
|
-
return fallback ?? { command: "python3", probe: { ok: false } };
|
|
517
|
+
return fallback ?? { command: "python3", probe: { ok: false, minimum: pythonVersion(void 0, floor).minimum } };
|
|
515
518
|
}
|
|
516
519
|
|
|
517
520
|
// src/native-hooks.ts
|
|
@@ -1482,7 +1485,7 @@ async function dramaPreflight() {
|
|
|
1482
1485
|
if (dramaPreflightCache !== void 0 && dramaPreflightCache.expires > Date.now()) return dramaPreflightCache.value;
|
|
1483
1486
|
dramaPreflightInFlight ??= (async () => {
|
|
1484
1487
|
try {
|
|
1485
|
-
const python = await hostPython();
|
|
1488
|
+
const python = await hostPython(DRAMA_PYTHON);
|
|
1486
1489
|
const adapterConfig = await ensureDramaAdapterConfig(defaultDramaSkillRoot(), { python: python.command });
|
|
1487
1490
|
const value = { python: python.probe, adapterConfig, adapters: dramaAdapterStatuses() };
|
|
1488
1491
|
dramaPreflightCache = { expires: Date.now() + 3e4, value };
|
|
@@ -1495,7 +1498,7 @@ async function dramaPreflight() {
|
|
|
1495
1498
|
}
|
|
1496
1499
|
async function videoPreflight() {
|
|
1497
1500
|
if (videoPreflightCache !== void 0 && videoPreflightCache.expires > Date.now()) return videoPreflightCache.value;
|
|
1498
|
-
const python = (await hostPython()).probe;
|
|
1501
|
+
const python = (await hostPython(VIDEO_PYTHON)).probe;
|
|
1499
1502
|
const [ffmpegOutput, ffmpegFilters, ffprobeOutput] = await Promise.all([
|
|
1500
1503
|
commandOutput("ffmpeg", ["-version"]),
|
|
1501
1504
|
commandOutput("ffmpeg", ["-hide_banner", "-filters"]),
|
|
@@ -1815,9 +1818,10 @@ async function previewDigest(realm, projectRoot) {
|
|
|
1815
1818
|
await visit(app, "");
|
|
1816
1819
|
return { ready, version: createHash2("sha256").update(entries.sort().join("\n")).digest("hex").slice(0, 16) };
|
|
1817
1820
|
}
|
|
1818
|
-
function
|
|
1821
|
+
function gameProjectTitle(content, fallback) {
|
|
1819
1822
|
const heading = content?.split(/\r?\n/u).find((line) => /^#\s+/u.test(line));
|
|
1820
|
-
|
|
1823
|
+
const title = heading?.replace(/^#\s+/u, "").replace(/^(?:PRODUCT[_ ]BRIEF|产品简报)/iu, "").replace(/^[\s·・::|—–-]+/u, "").trim().replace(/^《([^《》]+)》$/u, "$1").trim();
|
|
1824
|
+
return title || fallback;
|
|
1821
1825
|
}
|
|
1822
1826
|
async function workspaceGameProjects(realm, files, sessionId, maxBytes) {
|
|
1823
1827
|
const roots = [...new Set(files.flatMap((file) => {
|
|
@@ -1843,7 +1847,7 @@ async function workspaceGameProjects(realm, files, sessionId, maxBytes) {
|
|
|
1843
1847
|
return {
|
|
1844
1848
|
id: `workspace:${id}`,
|
|
1845
1849
|
root,
|
|
1846
|
-
title:
|
|
1850
|
+
title: gameProjectTitle(brief, id),
|
|
1847
1851
|
source: "workspace",
|
|
1848
1852
|
previewReady: preview.ready,
|
|
1849
1853
|
previewUrl: preview.ready ? `/oh-story/game-preview/workspace/${token(sessionId)}/${token(root)}/index.html` : void 0,
|
|
@@ -2142,7 +2146,7 @@ async function apply(context, config = {}) {
|
|
|
2142
2146
|
registerOhStoryProductionTool(context);
|
|
2143
2147
|
await registerOhStoryRoleTool(context);
|
|
2144
2148
|
registerWorkspaceRoute(context, { maxBytes: config.editorMaxBytes ?? 2097152, trustedHosts });
|
|
2145
|
-
await ensureDramaAdapterConfig(defaultDramaSkillRoot(), { python: (await hostPython()).command });
|
|
2149
|
+
await ensureDramaAdapterConfig(defaultDramaSkillRoot(), { python: (await hostPython(DRAMA_PYTHON)).command });
|
|
2146
2150
|
}
|
|
2147
2151
|
var index_default = { name, inject, Config, apply };
|
|
2148
2152
|
export {
|