akari-video 0.1.13 → 0.1.15
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/bin/akari.mjs +8 -3
- package/package.json +1 -1
- package/src/cli.mjs +12 -7
- package/src/messages.mjs +26 -2
- package/src/update-check.mjs +66 -25
- package/vendor/.akari-capability-sources.json +2 -0
- package/vendor/docs/contract-2026-07-17-data-contract-versioning.md +8 -0
- package/vendor/docs/contract-2026-07-25-r6-audio-tracks-and-trim.md +1 -1
- package/vendor/docs/contract-2026-08-23-captions-emphasis-words-v0.md +76 -0
- package/vendor/docs/contract-2026-08-23-stroke-persistence.md +75 -0
- package/vendor/packages/akari-launcher/package.json +1 -1
- package/vendor/packages/decision-cards/README.md +12 -0
- package/vendor/packages/decision-cards/package.json +3 -2
- package/vendor/packages/edit-lint/src/edit-lint.mjs +59 -60
- package/vendor/packages/edit-store/lib/cut-adjacency.d.ts +19 -0
- package/vendor/packages/edit-store/lib/cut-adjacency.js +28 -0
- package/vendor/packages/edit-store/lib/edit-store.d.ts +2 -2
- package/vendor/packages/edit-store/lib/edit-store.js +3 -1
- package/vendor/packages/edit-store/lib/edit-v2-item-write.d.ts +53 -0
- package/vendor/packages/edit-store/lib/edit-v2-item-write.js +162 -0
- package/vendor/packages/edit-store/lib/index.d.ts +4 -0
- package/vendor/packages/edit-store/lib/index.js +4 -0
- package/vendor/packages/edit-store/lib/internal-model.js +52 -53
- package/vendor/packages/edit-store/lib/legacy-audio-view.d.ts +16 -0
- package/vendor/packages/edit-store/lib/legacy-audio-view.js +60 -0
- package/vendor/packages/edit-store/lib/migrate/index.d.ts +8 -2
- package/vendor/packages/edit-store/lib/migrate/index.js +103 -13
- package/vendor/packages/edit-store/lib/migrate/legacy-parse.js +3 -1
- package/vendor/packages/edit-store/lib/timeline-map.d.ts +16 -0
- package/vendor/packages/edit-store/lib/timeline-map.js +65 -15
- package/vendor/packages/edit-store/lib/track-transition-compatibility.d.ts +23 -0
- package/vendor/packages/edit-store/lib/track-transition-compatibility.js +79 -0
- package/vendor/packages/edit-store/lib/webview-kernel.js +65 -16
- package/vendor/packages/edit-store/lib/write-gate.d.ts +4 -0
- package/vendor/packages/edit-store/lib/write-gate.js +38 -1
- package/vendor/packages/overlay-runtime/package.json +2 -1
- package/vendor/packages/pen-visuals/package.json +1 -0
- package/vendor/packages/schemas/bin/validate-captions.mjs +51 -2
- package/vendor/packages/schemas/bin/validate-research-plan.mjs +55 -7
- package/vendor/packages/schemas/captions.schema.json +21 -2
- package/vendor/packages/schemas/examples/captions-emphasis-words-empty-word/captions.json +16 -0
- package/vendor/packages/schemas/examples/captions-emphasis-words-invalid-id/captions.json +16 -0
- package/vendor/packages/schemas/examples/captions-emphasis-words-missing-emotion/captions.json +16 -0
- package/vendor/packages/schemas/examples/captions-emphasis-words-range-invalid/captions.json +17 -0
- package/vendor/packages/schemas/examples/captions-emphasis-words-valid/captions.json +31 -0
- package/vendor/packages/schemas/fixtures/review/valid-strokes/review.json +1 -1
- package/vendor/packages/schemas/research-plan.schema.json +24 -2
- package/vendor/packages/schemas/review.schema.json +18 -0
- package/vendor/packages/schemas/test/fixtures/research-plan/invalid-nested-cutaway/research-plan.json +25 -0
- package/vendor/packages/schemas/test/fixtures/research-plan/valid-legacy-without-shot-ids/research-plan.json +29 -0
- package/vendor/packages/schemas/test/fixtures/research-plan/valid-visual-storyboard/research-plan.json +72 -0
- package/vendor/packages/schemas/test/validate-captions.test.mjs +37 -0
- package/vendor/packages/schemas/test/validate-research-plan.test.mjs +18 -0
- package/vendor/skills/address-review/bin/list.mjs +12 -0
- package/vendor/skills/address-review/dev-fixtures/fixture-project/review.json +3 -0
- package/vendor/skills/address-review/test/review-store.test.mjs +6 -0
- package/vendor/skills/compile-review-session/bin/core/compiler.mjs +5 -0
- package/vendor/skills/compile-review-session/test/compiler.test.mjs +9 -0
- package/vendor/skills/compile-review-session/test/ui-events.test.mjs +1 -0
- package/vendor/skills/edit-plan/SKILL.md +6 -3
- package/vendor/skills/edit-plan/beat-sync.md +17 -3
- package/vendor/skills/edit-plan/emphasis-detection.md +14 -9
- package/vendor/skills/research-plan/SKILL.md +1 -1
- package/vendor/skills/research-plan/storyboard.md +30 -1
package/bin/akari.mjs
CHANGED
|
@@ -11,14 +11,19 @@ import { runCapabilityCommand } from '../src/capability-command.mjs';
|
|
|
11
11
|
import { runStoreCommand } from '../src/store-command.mjs';
|
|
12
12
|
import { runAssetsCommand } from '../src/assets-command.mjs';
|
|
13
13
|
import { runMigrateCommand } from '../src/migrate-command.mjs';
|
|
14
|
-
import { maybeApplyPendingUpdateOnLaunch,
|
|
15
|
-
import { describeCliHelp } from '../src/messages.mjs';
|
|
14
|
+
import { maybeApplyPendingUpdateOnLaunch, resolveInstalledVersionInfo } from '../src/update-check.mjs';
|
|
15
|
+
import { describeCliHelp, describeInstalledVersions } from '../src/messages.mjs';
|
|
16
16
|
|
|
17
17
|
// `akari --version` / `-v`: インストール済みの版を表示するだけの最小コマンド
|
|
18
18
|
// (タスク契約 2026-08-11-update-u4-cli-self-update の受け入れ条件 —
|
|
19
19
|
// `akari update` / `--rollback` 後にインストール先の版を観測する手段として必要)。
|
|
20
20
|
async function printVersion() {
|
|
21
|
-
|
|
21
|
+
const versionInfo = resolveInstalledVersionInfo({ env: process.env });
|
|
22
|
+
// 1 行目は update / rollback の既存機械観測契約として CLI 版だけを維持する。
|
|
23
|
+
console.log(`v${versionInfo.cliVersion}`);
|
|
24
|
+
for (const line of describeInstalledVersions(versionInfo)) {
|
|
25
|
+
console.log(line);
|
|
26
|
+
}
|
|
22
27
|
return { exitCode: 0 };
|
|
23
28
|
}
|
|
24
29
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "akari-video",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.15",
|
|
4
4
|
"description": "AKARI Video launcher CLI — start an AI-edited video project from any directory: scaffold, connection check, then hand over to Claude Code (or opencode). AKARI Video を opencode や Claude Code で、どのディレクトリからでも始めるための `akari` ランチャー CLI。接続確認(doctor)→ 未セットアップならプロジェクト雛形を作成 → AI エージェントを起動する。外部 npm 依存ゼロ(Node.js 組み込みモジュールのみ)。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/cli.mjs
CHANGED
|
@@ -6,7 +6,7 @@ import { resolveLauncherAssets } from './repo-assets.mjs';
|
|
|
6
6
|
import { detectProjectState } from './project-state.mjs';
|
|
7
7
|
import { findClaudeExecutable, findOpencodeExecutable } from './path-lookup.mjs';
|
|
8
8
|
import { loadTaskLabels } from './task-labels.mjs';
|
|
9
|
-
import { describeInstalledVersions, describeIntake, claudeMissingGuidance, opencodeMissingGuidance, describeUpdateCommand, describeVersionStatus, formatUpdateNotice } from './messages.mjs';
|
|
9
|
+
import { describeForceReinstall, describeInstalledVersions, describeIntake, claudeMissingGuidance, opencodeMissingGuidance, describeUpdateCommand, describeVersionStatus, formatUpdateNotice } from './messages.mjs';
|
|
10
10
|
import { resolveEffectiveProjectRoot } from './first-run.mjs';
|
|
11
11
|
import { maybeShowAssetIntroNotice } from './sounds-setup.mjs';
|
|
12
12
|
import {
|
|
@@ -14,9 +14,9 @@ import {
|
|
|
14
14
|
compareVersions,
|
|
15
15
|
isValidFeedShape,
|
|
16
16
|
readCacheSync,
|
|
17
|
-
readInstalledAppVersion,
|
|
18
17
|
readOwnVersion,
|
|
19
18
|
recordDismissalSync,
|
|
19
|
+
refreshUpdateFeed,
|
|
20
20
|
resolveCachePath,
|
|
21
21
|
resolveInstalledVersionInfo,
|
|
22
22
|
triggerBackgroundRefresh
|
|
@@ -188,8 +188,8 @@ function defaultSpawnOpencode(opencodePath, args, projectRoot) {
|
|
|
188
188
|
* 自己更新を試みず、キャッシュに載っている最新版の通知を今後出さないよう記録するだけ
|
|
189
189
|
* (既存挙動を維持)。`--force` は同じ版の本体も再導入し、`--rollback` は直前 1 世代
|
|
190
190
|
* (`~/.akari/app-previous/`)へ戻す。
|
|
191
|
-
*
|
|
192
|
-
*
|
|
191
|
+
* 通常時にネットワークへ触れるのは自己更新の DL 区間のみ。`--force` だけはキャッシュが
|
|
192
|
+
* 未取得なら、復旧経路を塞がないためフィードの同期取得を 1 回試す。
|
|
193
193
|
*/
|
|
194
194
|
export async function runUpdateCommand(args, options = {}) {
|
|
195
195
|
const log = options.log ?? ((line) => console.log(line));
|
|
@@ -197,7 +197,7 @@ export async function runUpdateCommand(args, options = {}) {
|
|
|
197
197
|
const versionInfo = resolveCommandVersionInfo(options, env);
|
|
198
198
|
const currentVersion = versionInfo.currentVersion;
|
|
199
199
|
const cachePath = resolveCachePath(env);
|
|
200
|
-
|
|
200
|
+
let cache = readCacheSync(cachePath);
|
|
201
201
|
const dismissRequested = args.includes('--dismiss');
|
|
202
202
|
const rollbackRequested = args.includes('--rollback');
|
|
203
203
|
const forceRequested = args.includes('--force');
|
|
@@ -219,10 +219,15 @@ export async function runUpdateCommand(args, options = {}) {
|
|
|
219
219
|
return { exitCode: 0 };
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
+
if (forceRequested && !cache?.feed) {
|
|
223
|
+
await (options.refreshUpdateFeed ?? refreshUpdateFeed)({ env, fetchImpl: options.fetchImpl });
|
|
224
|
+
cache = readCacheSync(cachePath);
|
|
225
|
+
}
|
|
226
|
+
|
|
222
227
|
const feed = cache?.feed;
|
|
223
228
|
const updateAvailable = isValidFeedShape(feed) && compareVersions(feed.product, currentVersion) > 0;
|
|
224
229
|
const reinstallRequested = forceRequested && isValidFeedShape(feed) && compareVersions(feed.product, currentVersion) >= 0;
|
|
225
|
-
const hasManagedApp =
|
|
230
|
+
const hasManagedApp = versionInfo.managedApp === true;
|
|
226
231
|
const selfUpdateEligible = (updateAvailable || reinstallRequested)
|
|
227
232
|
&& !!feed.components?.app?.url
|
|
228
233
|
&& !!feed.components?.app?.sha256
|
|
@@ -240,7 +245,7 @@ export async function runUpdateCommand(args, options = {}) {
|
|
|
240
245
|
}
|
|
241
246
|
log(`最新バージョン: v${feed.product}`);
|
|
242
247
|
if (forceRequested) {
|
|
243
|
-
log(
|
|
248
|
+
log(describeForceReinstall(versionInfo, feed.product));
|
|
244
249
|
}
|
|
245
250
|
|
|
246
251
|
return (options.applySelfUpdate ?? applySelfUpdate)({
|
package/src/messages.mjs
CHANGED
|
@@ -90,6 +90,14 @@ export function describeVersionStatus(versionOrInfo, cache) {
|
|
|
90
90
|
|
|
91
91
|
export function describeInstalledVersions(versionOrInfo) {
|
|
92
92
|
const info = normalizeVersionInfo(versionOrInfo);
|
|
93
|
+
if (info.installRefNeedsRepair) {
|
|
94
|
+
const installRefPath = info.installRefPath ?? '~/.akari/app/.akari-install-ref';
|
|
95
|
+
return [
|
|
96
|
+
`CLI バージョン: v${info.cliVersion}`,
|
|
97
|
+
`本体版を判定できません(\`${installRefPath}\` が壊れています)。`,
|
|
98
|
+
'修復するには `akari update --force` を実行してください。'
|
|
99
|
+
];
|
|
100
|
+
}
|
|
93
101
|
if (!info.appVersion) {
|
|
94
102
|
return [
|
|
95
103
|
`現在のバージョン: v${info.currentVersion}`,
|
|
@@ -104,6 +112,13 @@ export function describeInstalledVersions(versionOrInfo) {
|
|
|
104
112
|
return lines;
|
|
105
113
|
}
|
|
106
114
|
|
|
115
|
+
export function describeForceReinstall(versionOrInfo, targetVersion) {
|
|
116
|
+
const info = normalizeVersionInfo(versionOrInfo);
|
|
117
|
+
return info.installRefNeedsRepair
|
|
118
|
+
? `--force: 版を判定できない本体 → v${targetVersion} を入れ直します。`
|
|
119
|
+
: `--force: 本体 v${info.currentVersion} → v${targetVersion} を入れ直します。`;
|
|
120
|
+
}
|
|
121
|
+
|
|
107
122
|
function normalizeVersionInfo(value) {
|
|
108
123
|
if (typeof value === 'string') {
|
|
109
124
|
return { cliVersion: value, appVersion: null, currentVersion: value, mismatch: false };
|
|
@@ -112,11 +127,15 @@ function normalizeVersionInfo(value) {
|
|
|
112
127
|
}
|
|
113
128
|
|
|
114
129
|
function versionRelationLabel(info) {
|
|
115
|
-
return compareVersions(info.appVersion, info.cliVersion) < 0 ? '本体が古い' : 'CLI
|
|
130
|
+
return compareVersions(info.appVersion, info.cliVersion) < 0 ? '本体が古い' : 'CLI が古い';
|
|
116
131
|
}
|
|
117
132
|
|
|
118
133
|
function formatVersionMismatch(info) {
|
|
119
|
-
|
|
134
|
+
const relation = versionRelationLabel(info);
|
|
135
|
+
const guidance = relation === '本体が古い'
|
|
136
|
+
? '`akari update` で本体を更新してください。'
|
|
137
|
+
: '`npm i -g akari-video@latest` で CLI を更新してください。';
|
|
138
|
+
return `⚠ CLI v${info.cliVersion} / 本体 v${info.appVersion} → ${relation}。${guidance}`;
|
|
120
139
|
}
|
|
121
140
|
|
|
122
141
|
/**
|
|
@@ -168,6 +187,11 @@ export function describeUpdateCommand({ currentVersion, versionInfo, cache, dism
|
|
|
168
187
|
lines.push(`リリースノート: ${feed.notes_url}`);
|
|
169
188
|
}
|
|
170
189
|
|
|
190
|
+
if (info.installRefNeedsRepair) {
|
|
191
|
+
lines.push('本体版を判定できないため、更新判定を行いません。');
|
|
192
|
+
return lines;
|
|
193
|
+
}
|
|
194
|
+
|
|
171
195
|
if (compareVersions(feed.product, info.currentVersion) <= 0) {
|
|
172
196
|
lines.push('お使いのバージョンは最新です。');
|
|
173
197
|
return lines;
|
package/src/update-check.mjs
CHANGED
|
@@ -65,29 +65,49 @@ export function readOwnVersion() {
|
|
|
65
65
|
return JSON.parse(raw).version;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
/** install-ref を「有効・未記録・破損」の 3 状態で読む内部表現。 */
|
|
69
|
+
function readInstalledAppVersionInfo(env = process.env) {
|
|
70
|
+
const path = resolveInstallRefPath(env);
|
|
71
|
+
try {
|
|
72
|
+
const raw = readFileSync(path, 'utf8').trim();
|
|
73
|
+
const match = raw.match(/^v?(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)$/);
|
|
74
|
+
return match
|
|
75
|
+
? { status: 'valid', version: match[1], path }
|
|
76
|
+
: { status: 'invalid', version: null, path };
|
|
77
|
+
} catch (error) {
|
|
78
|
+
return {
|
|
79
|
+
status: error?.code === 'ENOENT' ? 'missing' : 'invalid',
|
|
80
|
+
version: null,
|
|
81
|
+
path
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
68
86
|
/**
|
|
69
87
|
* 実際に render-cut / edit-lint を実行する本体の導入版。
|
|
70
|
-
* install.sh / self-update.mjs が書く `vX.Y.Z`
|
|
88
|
+
* install.sh / self-update.mjs が書く `vX.Y.Z` を読む。互換 API として版または null を返し、
|
|
89
|
+
* 未記録と破損の区別は `resolveInstalledVersionInfo()` が保持する。
|
|
71
90
|
*/
|
|
72
91
|
export function readInstalledAppVersion(env = process.env) {
|
|
73
|
-
|
|
74
|
-
const raw = readFileSync(resolveInstallRefPath(env), 'utf8').trim();
|
|
75
|
-
const match = raw.match(/^v?(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)$/);
|
|
76
|
-
return match?.[1] ?? null;
|
|
77
|
-
} catch {
|
|
78
|
-
return null;
|
|
79
|
-
}
|
|
92
|
+
return readInstalledAppVersionInfo(env).version;
|
|
80
93
|
}
|
|
81
94
|
|
|
82
95
|
/** 更新判定に使う版と、CLI / 本体のずれを一度に解決する。 */
|
|
83
96
|
export function resolveInstalledVersionInfo({ env = process.env, cliVersion = readOwnVersion() } = {}) {
|
|
84
|
-
const
|
|
97
|
+
const installRef = readInstalledAppVersionInfo(env);
|
|
98
|
+
const installedAppVersion = installRef.version;
|
|
85
99
|
const currentVersion = installedAppVersion ?? cliVersion;
|
|
86
100
|
return {
|
|
87
101
|
cliVersion,
|
|
88
102
|
appVersion: installedAppVersion,
|
|
89
103
|
currentVersion,
|
|
90
|
-
source:
|
|
104
|
+
source: installRef.status === 'valid'
|
|
105
|
+
? 'install-ref'
|
|
106
|
+
: installRef.status === 'invalid' ? 'invalid-install-ref' : 'cli-fallback',
|
|
107
|
+
installRefStatus: installRef.status,
|
|
108
|
+
installRefPath: installRef.path,
|
|
109
|
+
installRefNeedsRepair: installRef.status === 'invalid',
|
|
110
|
+
managedApp: installRef.status !== 'missing',
|
|
91
111
|
mismatch: installedAppVersion !== null && compareVersions(cliVersion, installedAppVersion) !== 0
|
|
92
112
|
};
|
|
93
113
|
}
|
|
@@ -135,8 +155,18 @@ function writeCacheSync(cachePath, cache) {
|
|
|
135
155
|
/**
|
|
136
156
|
* キャッシュと現在版から、新版通知を出すべきかを判定する(同期・純粋関数・I/O なし)。
|
|
137
157
|
*/
|
|
138
|
-
export function evaluateUpdateStatus({ currentVersion, cache, cliVersion = currentVersion, appVersion = null, source = 'cli-fallback', mismatch = false }) {
|
|
139
|
-
const versionDetails = {
|
|
158
|
+
export function evaluateUpdateStatus({ currentVersion, cache, cliVersion = currentVersion, appVersion = null, source = 'cli-fallback', installRefStatus, installRefPath, installRefNeedsRepair, managedApp, mismatch = false }) {
|
|
159
|
+
const versionDetails = {
|
|
160
|
+
currentVersion,
|
|
161
|
+
cliVersion,
|
|
162
|
+
appVersion,
|
|
163
|
+
source,
|
|
164
|
+
installRefStatus,
|
|
165
|
+
installRefPath,
|
|
166
|
+
installRefNeedsRepair,
|
|
167
|
+
managedApp,
|
|
168
|
+
mismatch
|
|
169
|
+
};
|
|
140
170
|
const feed = cache?.feed;
|
|
141
171
|
if (!isValidFeedShape(feed)) {
|
|
142
172
|
return { available: false, ...versionDetails };
|
|
@@ -215,16 +245,8 @@ export async function maybeStageInBackground({ env = process.env, feed, fetchImp
|
|
|
215
245
|
return stageSelfUpdate({ env, feed, log: () => {}, fetchImpl, timeoutMs, extract });
|
|
216
246
|
}
|
|
217
247
|
|
|
218
|
-
/**
|
|
219
|
-
|
|
220
|
-
* すべて沈黙して return する(何も throw しない)。`dismissed` は既存キャッシュから
|
|
221
|
-
* 引き継ぐ(fetch のたびに既読状態が消えないように)。
|
|
222
|
-
*
|
|
223
|
-
* フィード取得・キャッシュ反映が成功した後、契約 §11 のバックグラウンド staging も
|
|
224
|
-
* 同じ沈黙原則のもとで試みる(`maybeStageInBackground`)。成功したときだけ
|
|
225
|
-
* キャッシュへ `staged`(版・sha256・staged_at)を追記する。
|
|
226
|
-
*/
|
|
227
|
-
export async function runBackgroundFetch({ env = process.env, fetchImpl = globalThis.fetch, launcherRoot } = {}) {
|
|
248
|
+
/** フィードを 1 回取得し、正常なら既読状態を保ったままキャッシュへ反映する。 */
|
|
249
|
+
export async function refreshUpdateFeed({ env = process.env, fetchImpl = globalThis.fetch } = {}) {
|
|
228
250
|
const feedUrl = resolveFeedUrl(env);
|
|
229
251
|
const cachePath = resolveCachePath(env);
|
|
230
252
|
try {
|
|
@@ -241,15 +263,34 @@ export async function runBackgroundFetch({ env = process.env, fetchImpl = global
|
|
|
241
263
|
}
|
|
242
264
|
const feed = await response.json();
|
|
243
265
|
if (!isValidFeedShape(feed)) {
|
|
244
|
-
return;
|
|
266
|
+
return null;
|
|
245
267
|
}
|
|
246
268
|
const existing = readCacheSync(cachePath);
|
|
247
|
-
|
|
269
|
+
const next = {
|
|
248
270
|
schema: CACHE_SCHEMA,
|
|
249
271
|
fetched_at: new Date().toISOString(),
|
|
250
272
|
feed,
|
|
251
273
|
dismissed: existing?.dismissed ?? {}
|
|
252
|
-
}
|
|
274
|
+
};
|
|
275
|
+
writeCacheSync(cachePath, next);
|
|
276
|
+
return next;
|
|
277
|
+
} catch {
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* バックグラウンド fetch 本体。フィード取得失敗は沈黙し、成功後は契約 §11 の staging を
|
|
284
|
+
* 同じ沈黙原則で試す。成功したときだけキャッシュへ `staged` を追記する。
|
|
285
|
+
*/
|
|
286
|
+
export async function runBackgroundFetch({ env = process.env, fetchImpl = globalThis.fetch, launcherRoot } = {}) {
|
|
287
|
+
const cachePath = resolveCachePath(env);
|
|
288
|
+
try {
|
|
289
|
+
const refreshed = await refreshUpdateFeed({ env, fetchImpl });
|
|
290
|
+
const feed = refreshed?.feed;
|
|
291
|
+
if (!feed) {
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
253
294
|
|
|
254
295
|
const staged = await maybeStageInBackground({ env, feed, fetchImpl, launcherRoot });
|
|
255
296
|
if (staged?.ok) {
|
|
@@ -40,6 +40,8 @@
|
|
|
40
40
|
"docs/contract-2026-08-13-avatar-drive-v0.md",
|
|
41
41
|
"docs/contract-2026-08-14-avatar-vrm-v0.md",
|
|
42
42
|
"docs/contract-2026-08-18-v1-render-parity.md",
|
|
43
|
+
"docs/contract-2026-08-23-captions-emphasis-words-v0.md",
|
|
44
|
+
"docs/contract-2026-08-23-stroke-persistence.md",
|
|
43
45
|
"packages/akari-launcher/package.json",
|
|
44
46
|
"packages/akari-launcher/README.md",
|
|
45
47
|
"packages/akari-tools/package.json",
|
|
@@ -97,3 +97,11 @@ edit.json の `version` は変わらないし、edit.json が `version: 1` に
|
|
|
97
97
|
task `2026-08-20-v2-audio-tracks` に限り、「機能追加禁止・バグ修正のみ」の明示承認済み・1 回限りの例外として、v0/v1 の `audio.sfx[]`・`audio.narration[]`・`audio.bgm` を v2 の audio lane `tracks[].items[]` へ移す変換を追加した。出力側の `at` / `duration` は整数フレームへ確定し、素材側の `in` / `out` と fade / `bgm.in` は秒のまま保持する。実尺が旧形式だけでは決まらない音声は `duration: 0` センチネルとし、この変換器では ffprobe しない。トップレベル `audio` は `master` が宣言されている場合だけ残す。
|
|
98
98
|
|
|
99
99
|
これは凍結前に許可された最後の機能追加である。今後この変換器へさらに変換能力を足さず、§6 の期限どおり本体から分離・削除する。
|
|
100
|
+
|
|
101
|
+
### 6.2 filter レイヤー転写と emphasis_words 移送(2026-08-23・1 回限りの例外)
|
|
102
|
+
|
|
103
|
+
task `2026-08-23-migrate-filter-emphasis-exception` に限り、2026-08-23 オーナー裁定による「機能追加禁止・バグ修正のみ」の明示承認済み・1 回限りの例外として、v0/v1 の独立した `kind: "filter"` レイヤーを v2 の filter source へ転写し、トップレベル `emphasis_words[]` を edit.json v2 から除外して object ルートの `captions.json.emphasis_words[]` へ移送する変換を追加した。media 系レイヤー(`video` / `baked`)に直付けされた `filter` は v2 に等価表現が無いため転写対象外とし、理由付きで変換を停止する。移送時は edit.json と captions.json の原文をそれぞれ退避し、1 手の revert で両方を復元する。移送先が無い、配列ルートである、または既に `emphasis_words` を持つ場合は理由付きで停止する。
|
|
104
|
+
|
|
105
|
+
2026-08-21 の廃止裁定は fieldtest 60 本を母集団とし、本番リールでの使用が調査圏外だったという母集団瑕疵があったため、本例外で既存データを損失なく移す。
|
|
106
|
+
|
|
107
|
+
これ以後この変換器へさらに変換能力を足さず、§6 の期限どおり本体から分離・削除する。
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
|
|
67
67
|
## 5. §2 追記 — sfx フェード(audio-clip-fades, 2026-08-18・オーナー裁定「クリップ主義」T2)
|
|
68
68
|
|
|
69
|
-
BGM をクリップ化する裁定(内部リポ `
|
|
69
|
+
BGM をクリップ化する裁定(内部リポ `akari-video-internal` の該当タスク)に伴い、
|
|
70
70
|
「音楽をクリップ(audio.sfx[])として置いても BGM ベッドと同じフェード表現ができる」を
|
|
71
71
|
満たすため、`sfxItem` に optional の `fade_in` / `fade_out`(秒・0 以上)を追加のみ拡張する
|
|
72
72
|
(`version` 不変・`contract-2026-07-17-data-contract-versioning.md` の原則に従う)。
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# captions.json v0 語レベル演出(emphasis_words)データ契約
|
|
2
|
+
|
|
3
|
+
- 日付: 2026-08-23
|
|
4
|
+
- 状態: 実装ラウンドの SSOT(`captions.json` の席と優先順を確定)
|
|
5
|
+
- 前提: [edit.json v1 語レベル演出契約](contract-2026-07-23-edit-json-v1-emphasis-words.md)
|
|
6
|
+
- スコープ: `captions.json` の object ルートに置くトップレベル任意フィールド
|
|
7
|
+
`emphasis_words[]` と、旧 `edit.json` 席との読取優先順
|
|
8
|
+
|
|
9
|
+
## 背景
|
|
10
|
+
|
|
11
|
+
字幕表示に属する語レベル演出は、編集タイムラインではなく字幕の SSOT である `captions.json` 側へ置く。
|
|
12
|
+
`edit.json` v2 から `emphasis_words` を廃止した 2026-08-21 裁定は維持し、v2 の exact-keys に席を
|
|
13
|
+
戻さない。一方、その裁定の根拠だった fieldtest 60 本の使用 0 件は母集団外の本番リールを含んでおらず、
|
|
14
|
+
本番リールでは 15 語が実際に使用されていたため、「語レベル演出自体が不要」という根拠は訂正する。
|
|
15
|
+
|
|
16
|
+
## 1. 席
|
|
17
|
+
|
|
18
|
+
`captions.json` が object ルートのときだけ、トップレベルに `emphasis_words[]` を任意で置ける。
|
|
19
|
+
|
|
20
|
+
```jsonc
|
|
21
|
+
{
|
|
22
|
+
"emphasis_words": [
|
|
23
|
+
{
|
|
24
|
+
"id": "e-0001",
|
|
25
|
+
"src": "main",
|
|
26
|
+
"t_start": 12.08,
|
|
27
|
+
"t_end": 12.44,
|
|
28
|
+
"word": "最高",
|
|
29
|
+
"emotion": "joy",
|
|
30
|
+
"style_hint": "size-pulse"
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
"captions": [ /* 既存のまま */ ]
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
従来の配列ルート(`[{ ...caption... }]`)にはトップレベルのフィールドを置けないため、
|
|
38
|
+
`emphasis_words[]` の席はない。語レベル演出を書く場合は object ルートへ移し、既存配列を
|
|
39
|
+
`captions[]` に包む。
|
|
40
|
+
|
|
41
|
+
## 2. レコード契約と差分
|
|
42
|
+
|
|
43
|
+
レコード形、フィールド語彙、source 秒アンカー、実測 word-level タイムスタンプを写す規律、
|
|
44
|
+
選定規律、劣化規約はすべて
|
|
45
|
+
[edit.json v1 語レベル演出契約](contract-2026-07-23-edit-json-v1-emphasis-words.md) と同じである。
|
|
46
|
+
本契約が定める差分は次の 2 点だけである。
|
|
47
|
+
|
|
48
|
+
1. 配列の置き場を `edit.json.emphasis_words` から、object ルートの
|
|
49
|
+
`captions.json.emphasis_words` へ移す。
|
|
50
|
+
2. `edit.json` v2 へは書かない。v0/v1 の旧席は後方互換の読取専用として残す。
|
|
51
|
+
|
|
52
|
+
したがって各レコードは `{ id, word, emotion, src?, t_start, t_end, style_hint? }` で、`id` は
|
|
53
|
+
`^e-\d{4}$` かつファイル内一意、`word` と `emotion` は空でない文字列、時刻は source 秒で
|
|
54
|
+
`0 <= t_start < t_end` とする。`emotion` は `joy` / `pain` / `surprise` / `anger` / `sadness` /
|
|
55
|
+
`emphasis` を標準語彙として使うが、v1 契約どおり enum 強制はしない。`style_hint` も描画側への
|
|
56
|
+
提案に留まる。
|
|
57
|
+
|
|
58
|
+
## 3. 読取優先順
|
|
59
|
+
|
|
60
|
+
消費側は次の優先順で 1 つの席だけを読む。
|
|
61
|
+
|
|
62
|
+
1. object ルートの `captions.json` に `emphasis_words` キーが在れば、その値を採用する。
|
|
63
|
+
2. キーが無ければ、v0/v1 の `edit.json.emphasis_words` を後方互換として読む。
|
|
64
|
+
3. どちらにも無ければ語レベル演出なしとする。
|
|
65
|
+
|
|
66
|
+
両方の席が在る場合もマージしない。`captions.json` 側だけを採用し、警告は出さない。これにより
|
|
67
|
+
新しい字幕 SSOT が常に優先される一方、`captions.json` に席を持たない既存 v0/v1 プロジェクトは
|
|
68
|
+
従来どおり `edit.json` 側だけで描画され、回帰しない。
|
|
69
|
+
|
|
70
|
+
## 4. 検証責務
|
|
71
|
+
|
|
72
|
+
`captions.schema.json` は object ルートだけに任意の `emphasis_words[]` を定義し、要素の必須項目、
|
|
73
|
+
型、`id` 形式、非負時刻、非空の `word` / `emotion` を検査する。JSON Schema 標準では兄弟値を
|
|
74
|
+
比較できない `t_end > t_start` と、配列内の `id` 一意性は `validate-captions.mjs` が検査する。
|
|
75
|
+
語と `captions[].words[]` の実測値の突き合わせは v1 契約と同じく書き手の規律であり、静的検証では
|
|
76
|
+
行わない。
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
---
|
|
2
|
+
lifecycle: implemented
|
|
3
|
+
created: 2026-08-23
|
|
4
|
+
updated: 2026-08-23
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 注釈ストローク永続表示契約
|
|
8
|
+
|
|
9
|
+
- 日付: 2026-08-23
|
|
10
|
+
- 状態: **実装済み**
|
|
11
|
+
- 前提: `contract-2026-08-11-review-session-ui-events.md`、
|
|
12
|
+
`contract-2026-07-20-review-json-v1-annotation-model.md`
|
|
13
|
+
- スコープ: Theia shell の出力プレビュー、review session の `strokes.json` 読み出し、
|
|
14
|
+
compile-review-session と address-review の追跡導線
|
|
15
|
+
|
|
16
|
+
## 1. セッション中の表示
|
|
17
|
+
|
|
18
|
+
- pen / rect は従来どおり正規化座標(プレビューフレーム左上を `(0, 0)`、右下を `(1, 1)`)で
|
|
19
|
+
記録する。表示時に現在の content rect へ写像し直すため、ウィンドウのリサイズと出力比率の
|
|
20
|
+
変更で座標は変わらない。
|
|
21
|
+
- pointerup 後は従来のグロー・きらめき・600 ms フェードをそのまま再生し、その後段の静的
|
|
22
|
+
ビットマップへ同じ正規化図形を残す。新しい録音セッションの開始時に前セッションの表示を
|
|
23
|
+
クリアし、録音終了では消さない。
|
|
24
|
+
- 描線 canvas は非描画モードで `pointer-events: none` とする。ペンまたは四角モードのドラッグ中
|
|
25
|
+
だけ既存どおり入力面になる。
|
|
26
|
+
- 注釈パネルの「描線を表示」チェックは既定 ON。OFF は残留描線と明示的に再表示した描線を隠し、
|
|
27
|
+
データを削除しない。ON に戻すと保持した正規化座標から即時再描画する。
|
|
28
|
+
|
|
29
|
+
## 2. 既存セッションの読み出しと再表示
|
|
30
|
+
|
|
31
|
+
`readReviewSessionStrokes({projectRootUri, sessionId})` は
|
|
32
|
+
`review/sessions/<sessionId>/strokes.json` を読み、次を返す。
|
|
33
|
+
|
|
34
|
+
```jsonc
|
|
35
|
+
{
|
|
36
|
+
"sessionId": "s-0001",
|
|
37
|
+
"strokes": [/* pen / rect。frame と recTStart/recTEnd を保持 */],
|
|
38
|
+
"warnings": []
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
- `strokes.json` 欠落は `strokes: []` として正常終了する。
|
|
43
|
+
- 配列ルート、または `version: 1` でない `{strokes:[]}` は旧形式として寛容に読む。
|
|
44
|
+
- JSON 破損、未知要素、値域外要素は描線単位で除外して warning に残す。セッション一覧と他の
|
|
45
|
+
描線を巻き込んで失敗させない。
|
|
46
|
+
- 注釈パネルの各録音済みセッションにある「描線」から再表示できる。表示メッセージには
|
|
47
|
+
`target.tab`(edit URI)と先頭ストロークの `target.recT` を添え、`frame.sourceT/cutIndex` で
|
|
48
|
+
プレビューを同じフレームへシークする。
|
|
49
|
+
|
|
50
|
+
## 3. compile 後の原本参照
|
|
51
|
+
|
|
52
|
+
review.json の data `version` は 0 のまま据え置く。compile-review-session はペアになった pen / rect
|
|
53
|
+
へ、既存フィールドを変えず次の任意フィールドを追加する。
|
|
54
|
+
|
|
55
|
+
```jsonc
|
|
56
|
+
"strokeRefs": [{
|
|
57
|
+
"sessionId": "s-0001",
|
|
58
|
+
"strokeId": "st-0001",
|
|
59
|
+
"sessionRef": "s-0001/st-0001"
|
|
60
|
+
}]
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
- `strokeRefs` は `null`、省略、または 1 件以上の配列。欠落は従来データとして正常である。
|
|
64
|
+
- pen は従来どおり最大 100 点の `strokes[].points` も埋め込み、`strokeRefs` から無加工の原本へ
|
|
65
|
+
戻れる。rect は従来どおり `targetKind:"region"` + `region.box` を埋め込み、同じ `strokeRefs`
|
|
66
|
+
から `strokes.json` 内の rect 原本へ戻れる。
|
|
67
|
+
- address-review の一覧は `strokeRefs` を
|
|
68
|
+
`review/sessions/<sessionId>/strokes.json#<strokeId>` として表示する。
|
|
69
|
+
|
|
70
|
+
## 4. 互換性
|
|
71
|
+
|
|
72
|
+
- 追加フィールドのみを使い、既存フィールドの削除・意味変更・data version bump は行わない。
|
|
73
|
+
- 読み手は未知フィールドを保持し、任意フィールドの欠落を旧データとして扱い、既知より大きい
|
|
74
|
+
data version を推測変換しない。
|
|
75
|
+
- `packages/preview-server` は本契約の対象外であり、WebUI の表示挙動は変更しない。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "akari-video",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.15",
|
|
4
4
|
"description": "AKARI Video launcher CLI — start an AI-edited video project from any directory: scaffold, connection check, then hand over to Claude Code (or opencode). AKARI Video を opencode や Claude Code で、どのディレクトリからでも始めるための `akari` ランチャー CLI。接続確認(doctor)→ 未セットアップならプロジェクト雛形を作成 → AI エージェントを起動する。外部 npm 依存ゼロ(Node.js 組み込みモジュールのみ)。 [akari-video npm vendor: bin/akari.mjs is reference-only. These CLI entrypoints are not included in the akari-video npm package. Run them from a full AKARI Video app installation (normally ~/.akari/app) or a monorepo checkout.]",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|---|---|
|
|
10
10
|
| `report-helper.mjs` | `127.0.0.1` のみにバインドするローカル HTTP ヘルパー。`report.html` の配信・`decisions.json` の read/write・commit を仲介する |
|
|
11
11
|
| `report-template.html` | data 属性でカードを宣言する report.html の雛形。単選・真偽チェック・整数スライダ・配列型の複数選択に対応する。カード種別のハードコードなし。ヘルパー経由なら操作可能、`file://` 直開き等で fetch 失敗時は全操作ボタンが disabled になり案内文言を出す(安全劣化) |
|
|
12
|
+
| `render-research-plan-report.mjs` | `research-plan.json` から固定 5 面の自己完結 HTML を生成する。絵コンテ面は画像 / 文字プレースホルダーのカード面と、主軸 + カットアウェイの読み取り専用 SVG 構造面を切り替えられる |
|
|
12
13
|
| `examples/report.html` + `examples/report.html.decisions.json` | 動作サンプル一式(既存 4 カード + `direction`)。AI 推奨を既定値に入れた `decisions.json` 雛形付き |
|
|
13
14
|
| `test/direction-card.test.mjs` | ローカル Chrome を headless 起動して、演出カードの保存と既存 4 カードの非退行を実測するテスト |
|
|
14
15
|
|
|
@@ -54,6 +55,17 @@ curl -X POST http://127.0.0.1:8791/api/commit
|
|
|
54
55
|
npm test --workspace @akari-video/decision-cards
|
|
55
56
|
```
|
|
56
57
|
|
|
58
|
+
### research-plan のビジュアル絵コンテ
|
|
59
|
+
|
|
60
|
+
```sh
|
|
61
|
+
node packages/decision-cards/render-research-plan-report.mjs \
|
|
62
|
+
planning/research-plan.json \
|
|
63
|
+
planning/research-plan-report.html
|
|
64
|
+
node packages/decision-cards/report-helper.mjs planning/research-plan-report.html
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
画像は生成時に data URI へ埋め込むため、出力 HTML は外部依存を持たない。`image_path` が無い、または画像を読めないショットは `shot_type` + `description` のプレースホルダーへ安全に劣化する。旧形式に `sequence` / `cutaway_of` が無い場合も生成は成功し、構造面だけが「構造情報なし」になる。
|
|
68
|
+
|
|
57
69
|
## edit-plan スキルからの参照方法
|
|
58
70
|
|
|
59
71
|
公開リポの `.claude/skills/edit-plan/` は本パッケージを以下のように参照する想定:
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@akari-video/decision-cards",
|
|
3
3
|
"version": "0.0.0",
|
|
4
4
|
"private": true,
|
|
5
|
-
"description": "決定カード v0 ランタイム。report-helper(ローカル HTTP サーバ)+ report-template(カード付きレポート HTML の雛形)+ 動作サンプル。外部 npm 依存ゼロ(Node.js 組み込みモジュールのみ)。 [akari-video npm vendor: report-helper.mjs is reference-only. These CLI entrypoints are not included in the akari-video npm package. Run them from a full AKARI Video app installation (normally ~/.akari/app) or a monorepo checkout.]",
|
|
5
|
+
"description": "決定カード v0 ランタイム。report-helper(ローカル HTTP サーバ)+ report-template(カード付きレポート HTML の雛形)+ 動作サンプル。外部 npm 依存ゼロ(Node.js 組み込みモジュールのみ)。 [akari-video npm vendor: report-helper.mjs is reference-only; render-research-plan-report.mjs is reference-only. These CLI entrypoints are not included in the akari-video npm package. Run them from a full AKARI Video app installation (normally ~/.akari/app) or a monorepo checkout.]",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"start": "node report-helper.mjs",
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
"akariVideoVendor": {
|
|
12
12
|
"execution": "reference-only",
|
|
13
13
|
"omittedBin": {
|
|
14
|
-
"decision-cards-helper": "report-helper.mjs"
|
|
14
|
+
"decision-cards-helper": "report-helper.mjs",
|
|
15
|
+
"research-plan-report": "render-research-plan-report.mjs"
|
|
15
16
|
},
|
|
16
17
|
"guidance": "These CLI entrypoints are not included in the akari-video npm package. Run them from a full AKARI Video app installation (normally ~/.akari/app) or a monorepo checkout."
|
|
17
18
|
}
|