akari-video 0.1.73 → 0.1.76
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 +6 -2
- package/package.json +1 -1
- package/src/cli.mjs +9 -1
- package/src/kits.mjs +24 -25
- package/src/store-command.mjs +12 -6
- package/vendor/.akari-capability-sources.json +2 -0
- package/vendor/docs/contract-2026-07-13-asset-library.md +42 -4
- package/vendor/docs/contract-2026-08-02-creator-root-v1.md +6 -2
- package/vendor/docs/contract-2026-08-30-edit-json-v2-object-tree-v0.md +6 -4
- package/vendor/docs/contract-2026-09-02-asset-reference-model.md +55 -5
- package/vendor/docs/contract-2026-09-13-generation-v0.md +15 -3
- package/vendor/packages/akari-launcher/README.md +6 -2
- package/vendor/packages/akari-launcher/package.json +1 -1
- package/vendor/packages/akari-vibe/README.md +62 -0
- package/vendor/packages/akari-vibe/package.json +17 -0
- package/vendor/packages/asset-resolver/README.md +147 -9
- package/vendor/packages/asset-resolver/bin/akari-assets.mjs +91 -9
- package/vendor/packages/asset-resolver/src/add.mjs +298 -0
- package/vendor/packages/asset-resolver/src/bundle.mjs +3 -5
- package/vendor/packages/asset-resolver/src/import-artifacts.mjs +91 -0
- package/vendor/packages/asset-resolver/src/installed.mjs +39 -29
- package/vendor/packages/asset-resolver/src/library.mjs +104 -32
- package/vendor/packages/asset-resolver/src/resolve.mjs +11 -9
- package/vendor/packages/asset-resolver/src/state.mjs +39 -6
- package/vendor/packages/asset-resolver/test/add.test.mjs +488 -0
- package/vendor/packages/asset-resolver/test/cli-guards.test.mjs +80 -0
- package/vendor/packages/asset-resolver/test/helpers.mjs +2 -0
- package/vendor/packages/asset-resolver/test/installed-assets.test.mjs +4 -4
- package/vendor/packages/asset-resolver/test/library-migration.test.mjs +50 -0
- package/vendor/packages/asset-resolver/test/local-library.test.mjs +171 -0
- package/vendor/packages/audio-library-setup/README.md +6 -2
- package/vendor/packages/audio-library-setup/bin/beat-grid.mjs +6 -5
- package/vendor/packages/audio-library-setup/bin/declare-helper.mjs +2 -2
- package/vendor/packages/audio-library-setup/bin/fetch-akari-sounds.mjs +5 -4
- package/vendor/packages/audio-library-setup/bin/gallery-helper.mjs +2 -2
- package/vendor/packages/audio-library-setup/bin/register-drop-folder.mjs +3 -2
- package/vendor/packages/audio-library-setup/bin/review-sfx-mapping.mjs +6 -5
- package/vendor/packages/audio-library-setup/bin/suggest-bgm.mjs +7 -6
- package/vendor/packages/audio-library-setup/bin/suggest-sfx.mjs +6 -6
- package/vendor/packages/audio-library-setup/declare-server.mjs +7 -20
- package/vendor/packages/audio-library-setup/gallery-server.mjs +7 -14
- package/vendor/packages/audio-library-setup/shared/library-roots.mjs +33 -0
- package/vendor/packages/audio-library-setup/test/library-location.test.mjs +68 -0
- package/vendor/packages/creator-root/src/index.mjs +339 -1
- package/vendor/packages/creator-root/test/library-migration.test.mjs +313 -0
- package/vendor/packages/edit-lint/src/edit-lint.mjs +4 -4
- package/vendor/packages/edit-lint/src/library-reference.mjs +33 -16
- package/vendor/packages/edit-store/lib/caption-display.js +12 -3
- package/vendor/packages/edit-store/lib/caption-window.d.ts +2 -0
- package/vendor/packages/edit-store/lib/caption-window.js +8 -0
- package/vendor/packages/edit-store/lib/edit-v2-item-write.d.ts +5 -0
- package/vendor/packages/edit-store/lib/edit-v2-item-write.js +34 -1
- package/vendor/packages/edit-store/lib/generation-meta.d.ts +40 -2
- package/vendor/packages/edit-store/lib/generation-meta.js +21 -1
- package/vendor/packages/edit-store/lib/tree-ops.d.ts +0 -9
- package/vendor/packages/edit-store/lib/tree-ops.js +0 -24
- package/vendor/packages/edit-store/lib/webview-kernel.js +7 -0
- package/vendor/packages/schemas/fixtures/gen-models/openapi/fal_h3-ref.json +2 -2
- package/vendor/packages/schemas/fixtures/generation-meta/generating-placeholder.json +61 -0
- package/vendor/packages/schemas/fixtures/generation-meta/planned-next.json +85 -0
- package/vendor/packages/schemas/fixtures/generation-meta/still-next.json +106 -0
- package/vendor/packages/schemas/gen-models.json +4 -4
- package/vendor/packages/schemas/gen-models.schema.json +1 -0
- package/vendor/packages/schemas/generation-meta.schema.json +150 -0
- package/vendor/packages/schemas/test/gen-models-reference-tags.test.mjs +44 -0
- package/vendor/packages/schemas/test/generation-meta.test.mjs +12 -1
- package/vendor/skills/akari/SKILL.md +5 -0
- package/vendor/skills/declare-audio/SKILL.md +8 -3
- package/vendor/skills/declare-audio/after-save.md +7 -2
- package/vendor/skills/declare-audio/launch.md +8 -4
- package/vendor/skills/edit-plan/beat-sync.md +7 -3
- package/vendor/skills/edit-plan/expression-selection.md +5 -2
- package/vendor/skills/edit-plan/report-guide.md +6 -2
- package/vendor/skills/harvest-asset/SKILL.md +7 -2
- package/vendor/skills/setup-audio-library/SKILL.md +7 -2
- package/vendor/skills/setup-audio-library/assisted-fetch.md +6 -2
- package/vendor/skills/setup-audio-library/drop-folder.md +6 -2
- package/vendor/skills/setup-audio-library/first-party.md +6 -2
- package/vendor/skills/setup-audio-library/gallery.md +7 -4
- package/vendor/skills/setup-audio-library/store-unlock.md +5 -1
- package/vendor/skills/setup-library/fetch-and-validate.md +5 -1
- package/vendor/templates/project-default/AGENTS.md +6 -2
- package/vendor/templates/project-default/CLAUDE.md +6 -2
package/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# akari-launcher(`akari` コマンド)
|
|
2
2
|
|
|
3
|
+
ライブラリの置き場は既定で作業場の `library/`。作業場が無いときは従来の `~/.akari/assets/` を使う。
|
|
4
|
+
`akari-assets list`(または `akari assets list`)の先頭行で実際の置き場を確認する。
|
|
5
|
+
以下の `<ライブラリの置き場>` はその表示先を指し、音源はその下の `audio/` に入る。
|
|
6
|
+
|
|
3
7
|
「UI に依存したくない。opencode 単体でも、どんなディレクトリでも始められるように」を
|
|
4
8
|
実現する薄いラッパー CLI。npm パッケージ名は `akari-video`、提供するコマンド名は `akari`
|
|
5
9
|
(npm の `akari` は別プロダクトが取得済みのため。オーナー裁定 2026-07-21 §8-2)。
|
|
@@ -24,7 +28,7 @@ akari
|
|
|
24
28
|
├─ 4. 公式音源ライブラリ(AKARI Sounds)の初回セットアップ(src/sounds-setup.mjs):
|
|
25
29
|
│ 未導入かつ TTY のとき生涯 1 回だけ [Y/n](既定 Yes)を聞き、Yes なら
|
|
26
30
|
│ packages/audio-library-setup/bin/fetch-akari-sounds.mjs で一括ダウンロード。
|
|
27
|
-
│ n は marker
|
|
31
|
+
│ n は marker(<ライブラリの置き場>/audio/.akari-sounds-declined.json)を書いて以後
|
|
28
32
|
│ 聞かない。再入口は `akari sounds`。失敗しても起動は止めない
|
|
29
33
|
│
|
|
30
34
|
└─ 5. 最後に opencode を exec する
|
|
@@ -48,7 +52,7 @@ DL・sha256 検証・適用まで実行。それ以外(npm グローバル / g
|
|
|
48
52
|
`akari store <connect|status|install|download|disconnect>`(AKARI Store 連携。マイページで発行した
|
|
49
53
|
接続トークンを `~/.akari/store-credentials.json`(0600)に保存し、購入済み一覧の確認と
|
|
50
54
|
配布物の取得ができる。`install <productId> [--from <zip>]` は購入パックを展開し、`PACK.json` の
|
|
51
|
-
収載素材を
|
|
55
|
+
収載素材を `<ライブラリの置き場>/installed.json` へ登録する。`--from` は開発・オフライン導入時に手元の
|
|
52
56
|
zip を使う。`src/store-command.mjs`)/
|
|
53
57
|
`akari assets <list|fetch|sync|...>`(素材カタログの一覧・取得・同期。
|
|
54
58
|
`packages/asset-resolver` の CLI への薄い委譲で、カタログ合成・entitlements 判定・
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "akari-video",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.76",
|
|
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
|
@@ -7,7 +7,7 @@ import { detectProjectState } from './project-state.mjs';
|
|
|
7
7
|
import { findClaudeExecutable, findExecutable, findOpencodeExecutable } from './path-lookup.mjs';
|
|
8
8
|
import { loadTaskLabels } from './task-labels.mjs';
|
|
9
9
|
import { describeForceReinstall, describeInstalledVersions, describeIntake, claudeMissingGuidance, opencodeMissingGuidance, describeUpdateCacheFallback, describeUpdateCommand, describeVersionStatus, formatUpdateNotice } from './messages.mjs';
|
|
10
|
-
import { resolveEffectiveProjectRoot } from './first-run.mjs';
|
|
10
|
+
import { defaultLoadCreatorRootModule, resolveEffectiveProjectRoot } from './first-run.mjs';
|
|
11
11
|
import { maybeShowAssetIntroNotice } from './sounds-setup.mjs';
|
|
12
12
|
import {
|
|
13
13
|
checkForUpdateSync,
|
|
@@ -82,6 +82,14 @@ export async function run(args, options = {}) {
|
|
|
82
82
|
projectRoot = await resolveEffectiveProjectRoot({ projectRoot, env, platform, now, log, assets, autoConfirm, options });
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
try {
|
|
86
|
+
const creatorRoot = await defaultLoadCreatorRootModule(assets);
|
|
87
|
+
const migration = await creatorRoot?.migrateAssetLibrary({ env, platform, automatic: true, notify: log });
|
|
88
|
+
for (const failure of migration?.failures ?? []) log(`素材の移行を再試行します: ${failure.message}`);
|
|
89
|
+
} catch (error) {
|
|
90
|
+
log(`素材の移行を再試行します: ${error.message}`);
|
|
91
|
+
}
|
|
92
|
+
|
|
85
93
|
let state = detectProjectState(projectRoot);
|
|
86
94
|
|
|
87
95
|
if (!state.scaffolded) {
|
package/src/kits.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { pathToFileURL } from 'node:url';
|
|
1
2
|
import { spawnSync } from 'node:child_process';
|
|
2
3
|
import { createHash } from 'node:crypto';
|
|
3
4
|
import {
|
|
@@ -7,6 +8,12 @@ import {
|
|
|
7
8
|
import path from 'node:path';
|
|
8
9
|
|
|
9
10
|
import { resolveLauncherAssets } from './repo-assets.mjs';
|
|
11
|
+
const creatorRootModulePath = resolveLauncherAssets().creatorRootModulePath;
|
|
12
|
+
const creatorRoot = creatorRootModulePath ? await import(pathToFileURL(creatorRootModulePath).href) : null;
|
|
13
|
+
function resolveAssetLibraryRoots(env) {
|
|
14
|
+
if (!creatorRoot) throw new Error('creator-root が見つからないため素材の置き場を解決できません。AKARI Video を再インストールしてください。');
|
|
15
|
+
return creatorRoot.resolveAssetLibraryRoots(env);
|
|
16
|
+
}
|
|
10
17
|
|
|
11
18
|
const KITS_SCHEMA = 'akari-installed-kits/v0';
|
|
12
19
|
const INSTALLED_ASSETS_SCHEMA = 'akari-installed-assets/v0';
|
|
@@ -152,16 +159,8 @@ export function linkKitAssets(kitDir, manifest, home, options = {}) {
|
|
|
152
159
|
} else {
|
|
153
160
|
warnings.push(`素材 ${asset.category}/${asset.id} の検査ツールが見つからないため検査をスキップしました。`);
|
|
154
161
|
}
|
|
155
|
-
const destination = path.join(
|
|
156
|
-
const
|
|
157
|
-
const kitSubdir = path.relative(productRoot, kitDir);
|
|
158
|
-
const result = replaceSymlink(source, destination, {
|
|
159
|
-
...options,
|
|
160
|
-
relativeTarget: path.join(
|
|
161
|
-
'..', '..', 'assets', 'store', manifest.id, kitSubdir,
|
|
162
|
-
'assets', asset.category, asset.id
|
|
163
|
-
)
|
|
164
|
-
});
|
|
162
|
+
const destination = path.join(resolveAssetLibraryRoots({ ...(options.env ?? process.env), AKARI_HOME: home }).write, asset.category, asset.id);
|
|
163
|
+
const result = replaceSymlink(source, destination, options);
|
|
165
164
|
if (result.status === 'occupied') {
|
|
166
165
|
warnings.push(`既存の実ディレクトリを保持しました: ${destination}`);
|
|
167
166
|
} else if (result.status === 'permission-denied') {
|
|
@@ -174,8 +173,8 @@ export function linkKitAssets(kitDir, manifest, home, options = {}) {
|
|
|
174
173
|
return { linked, items, warnings };
|
|
175
174
|
}
|
|
176
175
|
|
|
177
|
-
function readInstalledAssetsIndex(home) {
|
|
178
|
-
const indexPath = path.join(
|
|
176
|
+
function readInstalledAssetsIndex(home, env = process.env) {
|
|
177
|
+
const indexPath = path.join(resolveAssetLibraryRoots({ ...env, AKARI_HOME: home }).write, 'installed.json');
|
|
179
178
|
if (!existsSync(indexPath)) return { schema: INSTALLED_ASSETS_SCHEMA, packs: {} };
|
|
180
179
|
const index = JSON.parse(readFileSync(indexPath, 'utf8'));
|
|
181
180
|
if (index?.schema !== INSTALLED_ASSETS_SCHEMA
|
|
@@ -185,38 +184,38 @@ function readInstalledAssetsIndex(home) {
|
|
|
185
184
|
return index;
|
|
186
185
|
}
|
|
187
186
|
|
|
188
|
-
function writeInstalledAssetsIndex(home, index) {
|
|
189
|
-
const indexPath = path.join(
|
|
187
|
+
function writeInstalledAssetsIndex(home, index, env = process.env) {
|
|
188
|
+
const indexPath = path.join(resolveAssetLibraryRoots({ ...env, AKARI_HOME: home }).write, 'installed.json');
|
|
190
189
|
mkdirSync(path.dirname(indexPath), { recursive: true });
|
|
191
190
|
const temporary = `${indexPath}.tmp-${process.pid}`;
|
|
192
191
|
writeFileSync(temporary, `${JSON.stringify(index, null, 2)}\n`, { mode: 0o600 });
|
|
193
192
|
renameSync(temporary, indexPath);
|
|
194
193
|
}
|
|
195
194
|
|
|
196
|
-
export function registerKitAssets(home, manifest, kitDir, items) {
|
|
195
|
+
export function registerKitAssets(home, manifest, kitDir, items, env = process.env) {
|
|
197
196
|
const root = path.resolve(kitDir);
|
|
198
|
-
const storeRoot = path.join(
|
|
197
|
+
const storeRoot = path.join(resolveAssetLibraryRoots({ ...env, AKARI_HOME: home }).write, 'store', manifest.id);
|
|
199
198
|
if (root !== storeRoot && !root.startsWith(`${storeRoot}${path.sep}`)) {
|
|
200
199
|
throw new Error(`キット素材の root が展開先の外を指しています: ${root}`);
|
|
201
200
|
}
|
|
202
|
-
const index = readInstalledAssetsIndex(home);
|
|
201
|
+
const index = readInstalledAssetsIndex(home, env);
|
|
203
202
|
index.packs[manifest.id] = {
|
|
204
203
|
version: manifest.version,
|
|
205
204
|
installedAt: new Date().toISOString(),
|
|
206
205
|
root,
|
|
207
206
|
items
|
|
208
207
|
};
|
|
209
|
-
writeInstalledAssetsIndex(home, index);
|
|
208
|
+
writeInstalledAssetsIndex(home, index, env);
|
|
210
209
|
return items;
|
|
211
210
|
}
|
|
212
211
|
|
|
213
|
-
function unregisterKitAssets(home, productId) {
|
|
214
|
-
const indexPath = path.join(
|
|
212
|
+
function unregisterKitAssets(home, productId, env = process.env) {
|
|
213
|
+
const indexPath = path.join(resolveAssetLibraryRoots({ ...env, AKARI_HOME: home }).write, 'installed.json');
|
|
215
214
|
if (!existsSync(indexPath)) return;
|
|
216
|
-
const index = readInstalledAssetsIndex(home);
|
|
215
|
+
const index = readInstalledAssetsIndex(home, env);
|
|
217
216
|
if (!Object.hasOwn(index.packs, productId)) return;
|
|
218
217
|
delete index.packs[productId];
|
|
219
|
-
writeInstalledAssetsIndex(home, index);
|
|
218
|
+
writeInstalledAssetsIndex(home, index, env);
|
|
220
219
|
}
|
|
221
220
|
|
|
222
221
|
export function linkKitSkills(kitDir, manifest, home, options = {}) {
|
|
@@ -276,20 +275,20 @@ export function writeKitsLedger(home, entry) {
|
|
|
276
275
|
return ledger;
|
|
277
276
|
}
|
|
278
277
|
|
|
279
|
-
export function removeKit(home, productId) {
|
|
278
|
+
export function removeKit(home, productId, env = process.env) {
|
|
280
279
|
const ledger = readKitsLedger(home);
|
|
281
280
|
const entry = ledger.kits.find((kit) => kit.id === productId);
|
|
282
281
|
if (!entry) return false;
|
|
283
282
|
for (const name of entry.skills ?? []) removeOwnedSymlink(path.join(home, 'kits', 'plugin', 'skills', name), entry.kitDir);
|
|
284
283
|
for (const asset of entry.assets ?? []) {
|
|
285
|
-
removeOwnedSymlink(path.join(
|
|
284
|
+
for (const root of resolveAssetLibraryRoots({ ...env, AKARI_HOME: home }).read) removeOwnedSymlink(path.join(root, asset.category, asset.id), entry.kitDir);
|
|
286
285
|
}
|
|
287
286
|
ledger.kits = ledger.kits.filter((kit) => kit.id !== productId);
|
|
288
287
|
const ledgerPath = path.join(home, 'kits', 'installed.json');
|
|
289
288
|
const temporary = `${ledgerPath}.tmp-${process.pid}`;
|
|
290
289
|
writeFileSync(temporary, `${JSON.stringify(ledger, null, 2)}\n`, { mode: 0o600 });
|
|
291
290
|
renameSync(temporary, ledgerPath);
|
|
292
|
-
unregisterKitAssets(home, productId);
|
|
291
|
+
unregisterKitAssets(home, productId, env);
|
|
293
292
|
return true;
|
|
294
293
|
}
|
|
295
294
|
|
package/src/store-command.mjs
CHANGED
|
@@ -20,6 +20,12 @@ import {
|
|
|
20
20
|
} from './store-device-connect.mjs';
|
|
21
21
|
import { readOwnVersion } from './update-check.mjs';
|
|
22
22
|
import { resolveLauncherAssets } from './repo-assets.mjs';
|
|
23
|
+
const creatorRootModulePath = resolveLauncherAssets().creatorRootModulePath;
|
|
24
|
+
const creatorRoot = creatorRootModulePath ? await import(pathToFileURL(creatorRootModulePath).href) : null;
|
|
25
|
+
function resolveAssetLibraryRoots(env) {
|
|
26
|
+
if (!creatorRoot) throw new Error('creator-root が見つからないため素材の置き場を解決できません。AKARI Video を再インストールしてください。');
|
|
27
|
+
return creatorRoot.resolveAssetLibraryRoots(env);
|
|
28
|
+
}
|
|
23
29
|
import {
|
|
24
30
|
checkRequires,
|
|
25
31
|
enableHint,
|
|
@@ -154,8 +160,7 @@ function flattenPackContents(pack, packRoot) {
|
|
|
154
160
|
}
|
|
155
161
|
|
|
156
162
|
function registerInstalledPack(env, productId, packPath) {
|
|
157
|
-
const
|
|
158
|
-
const indexPath = path.join(home, 'assets', 'installed.json');
|
|
163
|
+
const indexPath = path.join(resolveAssetLibraryRoots(env).write, 'installed.json');
|
|
159
164
|
const packRoot = path.dirname(packPath);
|
|
160
165
|
const pack = readJsonFile(packPath);
|
|
161
166
|
if ((typeof pack?.version !== 'string' && typeof pack?.version !== 'number')) {
|
|
@@ -319,7 +324,7 @@ export async function runStoreCommand(args, options = {}) {
|
|
|
319
324
|
log('使い方: akari store uninstall <productId>');
|
|
320
325
|
return { exitCode: 1 };
|
|
321
326
|
}
|
|
322
|
-
if (!removeKit(resolveAkariHome(env), productId)) {
|
|
327
|
+
if (!removeKit(resolveAkariHome(env), productId, env)) {
|
|
323
328
|
log(`導入済みの拡張キットが見つかりません: ${productId}`);
|
|
324
329
|
return { exitCode: 1 };
|
|
325
330
|
}
|
|
@@ -430,7 +435,7 @@ export async function runStoreCommand(args, options = {}) {
|
|
|
430
435
|
log('パック内に declarations.json が見つかりませんでした。zip の中身を確認してください。');
|
|
431
436
|
return { exitCode: 1 };
|
|
432
437
|
}
|
|
433
|
-
const destDir = path.join(
|
|
438
|
+
const destDir = path.join(resolveAssetLibraryRoots(env).write, 'audio');
|
|
434
439
|
mkdirSync(destDir, { recursive: true });
|
|
435
440
|
const dest = path.join(destDir, 'declarations.json');
|
|
436
441
|
if (existsSync(dest)) {
|
|
@@ -445,7 +450,7 @@ export async function runStoreCommand(args, options = {}) {
|
|
|
445
450
|
}
|
|
446
451
|
|
|
447
452
|
// 既知の導入手順が無い商品は素材置き場に展開して README を案内
|
|
448
|
-
const destDir = path.join(
|
|
453
|
+
const destDir = path.join(resolveAssetLibraryRoots(env).write, 'store', productId);
|
|
449
454
|
rmSync(destDir, { recursive: true, force: true });
|
|
450
455
|
cpSync(extractDir, destDir, { recursive: true });
|
|
451
456
|
const readme = findFile(destDir, 'README.md');
|
|
@@ -531,6 +536,7 @@ export async function runStoreCommand(args, options = {}) {
|
|
|
531
536
|
|
|
532
537
|
const hadInstalledKit = readKitsLedger(home).kits.length > 0;
|
|
533
538
|
const assetLinks = linkKitAssets(kitDir, manifest, home, {
|
|
539
|
+
env,
|
|
534
540
|
assets: options.assets,
|
|
535
541
|
spawnSyncImpl: options.spawnSync,
|
|
536
542
|
platform: options.platform
|
|
@@ -541,7 +547,7 @@ export async function runStoreCommand(args, options = {}) {
|
|
|
541
547
|
for (const blocker of skillLinks.blockers) log(`導入できません: ${blocker}`);
|
|
542
548
|
return { exitCode: 1 };
|
|
543
549
|
}
|
|
544
|
-
registerKitAssets(home, manifest, kitDir, assetLinks.items);
|
|
550
|
+
registerKitAssets(home, manifest, kitDir, assetLinks.items, env);
|
|
545
551
|
writeKitsLedger(home, {
|
|
546
552
|
id: manifest.id,
|
|
547
553
|
version: manifest.version,
|
|
@@ -74,6 +74,8 @@
|
|
|
74
74
|
"packages/akari-launcher/README.md",
|
|
75
75
|
"packages/akari-tools/package.json",
|
|
76
76
|
"packages/akari-tools/README.md",
|
|
77
|
+
"packages/akari-vibe/package.json",
|
|
78
|
+
"packages/akari-vibe/README.md",
|
|
77
79
|
"packages/analysis-report/package.json",
|
|
78
80
|
"packages/analysis-report/README.md",
|
|
79
81
|
"packages/asset-resolver/package.json",
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# 素材ライブラリ契約 v0
|
|
2
2
|
|
|
3
|
+
ライブラリの置き場は既定で作業場の `library/`。作業場が無いときは従来の `~/.akari/assets/` を使う。
|
|
4
|
+
`akari-assets list`(または `akari assets list`)の先頭行で実際の置き場を確認する。
|
|
5
|
+
以下の `<ライブラリの置き場>` はその表示先を指し、音源はその下の `audio/` に入る。
|
|
6
|
+
|
|
3
7
|
- 日付: 2026-07-13
|
|
4
8
|
- 状態: 設計確定
|
|
5
9
|
- 前提: 本体(エンジン)は合成だけ。素材とその知識は全部外側に置く
|
|
@@ -215,7 +219,7 @@ catalog に載せる素材は、取得元のライセンスが CC0 相当(帰
|
|
|
215
219
|
|---|---|---|
|
|
216
220
|
| `local` | `<プロジェクト>/assets/` | そのプロジェクトのみ |
|
|
217
221
|
| `shared` | プロジェクトから上位へ辿った各ディレクトリの `.akari/assets/`(2026-07-25 第三裁定で確定) | そのディレクトリ配下の全プロジェクト(事業・組織単位。複数層可) |
|
|
218
|
-
| `user` |
|
|
222
|
+
| `user` | `<ライブラリの置き場>/`(2026-07-25 第三裁定で確定) | そのマシンの全プロジェクト |
|
|
219
223
|
| `builtin` | 本リポの `assets/` | 製品出荷デフォルト |
|
|
220
224
|
| `catalog` | 本リポの `catalog/`(remote) | 取得して任意の層へ入庫 |
|
|
221
225
|
|
|
@@ -241,7 +245,7 @@ catalog に載せる素材は、取得元のライセンスが CC0 相当(帰
|
|
|
241
245
|
~~**確定裁定(2026-07-25 再裁定): プロジェクト外の置き場所は `~/.akari-video/` をベースに
|
|
242
246
|
統一する。** 初期案保留(旧「`.akari-video/` は初期案」項)はこれで解消。~~
|
|
243
247
|
|
|
244
|
-
|
|
248
|
+
**履歴(2026-07-25 第三裁定): 当時の user 素材は `~/.akari/` 直下だった。2026-09-21 から素材は作業場 `library/` に移行し、マシン状態のみ `~/.akari/` に残す。**
|
|
245
249
|
`~/.akari/` 直下には他ソフトウェアの既存物が併存する場合があるため、共存規約
|
|
246
250
|
(本節末尾を参照)を必ず守る。
|
|
247
251
|
|
|
@@ -250,7 +254,7 @@ catalog に載せる素材は、取得元のライセンスが CC0 相当(帰
|
|
|
250
254
|
|
|
251
255
|
確定事項(2026-07-25 第三裁定で更新。カッコ内は第二裁定時点の値):
|
|
252
256
|
|
|
253
|
-
- `user` 層:
|
|
257
|
+
- `user` 層: `<ライブラリの置き場>/`(第二裁定時点: `~/.akari-video/assets/`)
|
|
254
258
|
- `shared` 層: 上位ディレクトリの `.akari/assets/`(第二裁定時点: `.akari-video/assets/`)
|
|
255
259
|
- レシピ: `~/.akari/recipes/`(recipe v0 の現行表記のまま・変更不要。出所は
|
|
256
260
|
`docs/contract-2026-07-25-recipe-v0.md` §2 に追記)
|
|
@@ -380,7 +384,7 @@ catalog に載せる素材は、取得元のライセンスが CC0 相当(帰
|
|
|
380
384
|
- **カテゴリを増やさない**のが本改訂の要点である。新しい主題(ホワイトボード、ノート風、付箋…)は
|
|
381
385
|
既存カテゴリ + tags で表す。カテゴリ追加を提案するときは「既存 6 つのどの形にも当てはまらない
|
|
382
386
|
配布・消費のされ方か」を先に示す
|
|
383
|
-
- `audio` を `media`
|
|
387
|
+
- `audio` を `media` に畳む案は見送った。`<ライブラリの置き場>/audio/`(user 層)に実データがあり、
|
|
384
388
|
リポ外のユーザー資産の移設を伴うため。`audio` と `broll` は消費経路(音声トラック / 映像トラック)が
|
|
385
389
|
異なるので、形の軸としても分けたままで筋が通る
|
|
386
390
|
- 移行時の実績: `assets/` 3 件・`catalog/` 3 件のディレクトリ移動と `category` 値の書き換え、
|
|
@@ -419,3 +423,37 @@ catalog に載せる素材は、取得元のライセンスが CC0 相当(帰
|
|
|
419
423
|
**人が選んでコピーするか / コードが id で引くか**で置き場を決める。前者は `assets/` か `catalog/`、
|
|
420
424
|
後者は `presets/`。後者をここへ足すときは、解決するコードのパスと 1:1 で対応させ、その参照箇所を
|
|
421
425
|
表の INDEX.md に明記する。
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
## 手持ち素材の登録(2026-09-22)
|
|
429
|
+
|
|
430
|
+
`akari-assets add --plan / --apply` は利用者の生ファイルを置き場へ複製する。
|
|
431
|
+
出どころは meta.json の既存 tags に記録し、スキーマは増やさない。
|
|
432
|
+
|
|
433
|
+
| 機械用タグ | 意味 |
|
|
434
|
+
| --- | --- |
|
|
435
|
+
| `origin:own` / `origin:site` | ローカル取り込み / サイトからの取り込み |
|
|
436
|
+
| `site:<id>` | サイト識別子 |
|
|
437
|
+
| `folder:<名前>` | 取り込み元として渡されたフォルダ名 |
|
|
438
|
+
| `license:subscription` | サブスクリプション由来 |
|
|
439
|
+
| `pack:<id>` | 素材セット。置き場直下の packs.json は catalog/packs.json と同型 |
|
|
440
|
+
|
|
441
|
+
一覧ではこれらを `machineTags` に分け、表示・検索用の `tags` に残さない。
|
|
442
|
+
出どころはカタログ掲載(lab)、明示 origin タグ(site / own)、AKARI 配布元の source.url(lab)、
|
|
443
|
+
その他の source.url あり(site)、それ以外(own)の順で決める。
|
|
444
|
+
AKARI 配布元は URL を解析し、ホスト github.com かつパスの最初のセグメントが AkariLabs、
|
|
445
|
+
またはホスト akari-oss.app とそのサブドメインで判定する。壊れた URL は site とする。
|
|
446
|
+
素材ディレクトリの `CREDIT.txt` はクレジット文面 1 行。文面がある場合は
|
|
447
|
+
`license.attribution_required: true`、source がある場合はその attribution_required も true にする。
|
|
448
|
+
|
|
449
|
+
取り込みの既定は `license.scope: "private-owned"`、`spdx: "LicenseRef-user-owned"`、
|
|
450
|
+
`ai_training_allowed: false`、`price: 0`。利用者の手持ち素材として保管するための値であり、
|
|
451
|
+
素材そのものの著作権帰属・商用可否・再配布権を認定するものではない。
|
|
452
|
+
サイト由来は source ブロックに配布ページと元の利用条件を残す。
|
|
453
|
+
|
|
454
|
+
ローカル取り込みは全カテゴリに preview.png を置く。音は ffmpeg の波形、映像は先頭フレームを使い、
|
|
455
|
+
ffmpeg 不在・失敗時は Node 組み込みの zlib で生成した決定的なプレースホルダ PNG にする。
|
|
456
|
+
PNG の画像は元画像を複製し、その他の画像・font・scene3d はプレースホルダを使う。
|
|
457
|
+
still は画像を相対参照する fragment.html、scene3d はモデルを参照する data-akari-3d-scene 宣言の
|
|
458
|
+
fragment.html を生成する。これらを含む素材全体が validate-asset の exit 0 を通った場合だけ登録し、
|
|
459
|
+
非 0 の場合は failures に記録して素材を残さない。title は元ファイル名から拡張子を除いたものにする。
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# creator-root-v1(作業場)契約
|
|
2
2
|
|
|
3
|
+
ライブラリの置き場は既定で作業場の `library/`。作業場が無いときは従来の `~/.akari/assets/` を使う。
|
|
4
|
+
`akari-assets list`(または `akari assets list`)の先頭行で実際の置き場を確認する。
|
|
5
|
+
以下の `<ライブラリの置き場>` はその表示先を指し、音源はその下の `audio/` に入る。
|
|
6
|
+
|
|
3
7
|
- 日付: 2026-08-02
|
|
4
8
|
- 状態: **v1 ドラフト・要オーナーレビュー**(設計方針はオーナー承認済み 2026-08-02。
|
|
5
9
|
判断根拠・出典調査は非公開の内部記録で管理する)
|
|
@@ -41,8 +45,8 @@ AKARI Video がマシン上に持ってよい場所は次の 3 つ**だけ**で
|
|
|
41
45
|
- マシン状態の実パスは**既存実装の規約を追認**する(`~/.akari/` = 更新キャッシュ・接続マーカー・
|
|
42
46
|
可搬 Node runtime 等 / 資格情報は `~/.config/akari-video/credentials.env`)。新たな隠し場所を増やさない
|
|
43
47
|
- 原則: マシン状態には**ユーザーの内容物(作品・素材・記憶)を置かない**。
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
旧音源ライブラリの例外は 2026-09-21 の移行で回収した。素材は作業場 `library/` へ移し、
|
|
49
|
+
マシン設定の `library-location.json` に置き場を固定する(作業場なし・同期フォルダは移さない)。
|
|
46
50
|
|
|
47
51
|
- **secrets(API キー・トークン類)はマシン設定にのみ置く**。作業場は可視・バックアップ・
|
|
48
52
|
同期対象なので、secrets を混ぜてはならない
|
|
@@ -91,7 +91,7 @@ updated: 2026-08-30
|
|
|
91
91
|
- 字幕は**専用の段ではなくグループ**。HTML 袋と同じ形(袋 = captions.json・子 = 行)。畳める・前後へ動かせる・別グループの中に入れられる・行を「出す」は部品と同じ操作。段は全部無名になる(§2)
|
|
92
92
|
- 子(行)の時間は captions.json の**ソース秒**のまま(既存契約)。写しの `at` / `duration` は読み込み層がタイムライン写像で導出する(edit.json に焼かない)
|
|
93
93
|
- **行の分離**: `{ "id": "cap-42", "at": 1210, "duration": 48, "transform": { "y": -120 }, "source": { "kind": "caption", "path": "captions.json", "id": "c-0042" } }`。文字・スタイルは captions.json の行が正本のまま、位置と時間だけ木の側で上書きする
|
|
94
|
-
- **テロップに変換**: `source: { "kind": "telop", "preset": "…", "params": { "text": "…" }, "from": "captions.json#c-0042" }`。以後は独立したテロップ(`from` は来歴。元の行は `exclude`)
|
|
94
|
+
- **テロップに変換**: `source: { "kind": "telop", "preset": "…", "params": { "text": "…" }, "from": "captions.json#c-0042" }`。以後は独立したテロップ(`from` は来歴。元の行は `exclude`) **追記**: 「テロップに変換」は GUI の操作としては 2026-09-21 に撤去。`kind:"telop"` の器と `baked` の再生は後方互換で残す。
|
|
95
95
|
- 同時刻に 2 行あるときの表示(副行)は描画側の規則であってデータではない。編集ミスの重なりは lint warning
|
|
96
96
|
- **旧形 `tracks[].content: { from: "captions.json" }` は読める(tolerant reader)が deprecated**。読み込み層は袋グループと同じ内部表現に落とす。書き手(shell / スキル)は袋グループ形を出し、`akari migrate` が旧形を袋グループ形に正規化する。lint は旧形に warning `v2.captions-content-deprecated`
|
|
97
97
|
|
|
@@ -129,7 +129,7 @@ updated: 2026-08-30
|
|
|
129
129
|
- **1 トラック = 常に 1 行。** 葉のアイテム(子を持たないもの)は帯の中のチップであって、ヘッダ列の行ではない。ヘッダ列の行になるのは (a) 子を持つ純グループ (b) 展開中の純グループの子 だけ
|
|
130
130
|
- **袋の子へ届く経路は 2 つ**: (a) 帯のチップを直接クリックして選ぶ (b) ダブルクリックでフォーカスモードに入る(§7 の「中に入る」)。袋を段の上で展開する操作は**無い**
|
|
131
131
|
- 畳んだ帯に子の位置を刻みで示すのは従来どおり(どこに何があるかは帯で分かる)
|
|
132
|
-
- 「出す」(§3.1)・「テロップに変換」(§1.5)は**帯のチップに対する操作**として従来どおり使える(行が無くても届く)
|
|
132
|
+
- 「出す」(§3.1)・「テロップに変換」(§1.5)は**帯のチップに対する操作**として従来どおり使える(行が無くても届く) **追記**: 「テロップに変換」は GUI の操作としては 2026-09-21 に撤去。`kind:"telop"` の器と `baked` の再生は後方互換で残す。
|
|
133
133
|
|
|
134
134
|
**根拠**: 袋は「データがそうなっている入れ物」で、人間が作ったものでも、ばらせるものでもない。それを UI で「グループ」と呼ぶと「ではばらせるのか」「展開する必要があるのか」という**答えのない問い**が立つ。実案件(SFX 30・字幕 30 行)で葉まで行にした結果ヘッダ列が 71 行に膨らみ、この混同が破綻として顕在化した。
|
|
135
135
|
|
|
@@ -158,7 +158,7 @@ updated: 2026-08-30
|
|
|
158
158
|
|
|
159
159
|
## 3. 操作の意味論(データ変換として定義。UI のコマンド・キー割り当ては別契約)
|
|
160
160
|
|
|
161
|
-
操作は **出す / まとめる / ばらす** の 3 つ + 切り出し・テロップに変換。**「戻す」は無い**(⌘Z のみ。再グループ化は「まとめる」で足りる)。
|
|
161
|
+
操作は **出す / まとめる / ばらす** の 3 つ + 切り出し・テロップに変換。**「戻す」は無い**(⌘Z のみ。再グループ化は「まとめる」で足りる)。 **追記**: 「テロップに変換」は GUI の操作としては 2026-09-21 に撤去。`kind:"telop"` の器と `baked` の再生は後方互換で残す。
|
|
162
162
|
|
|
163
163
|
### 3.1 出す(detach)
|
|
164
164
|
|
|
@@ -181,6 +181,8 @@ updated: 2026-08-30
|
|
|
181
181
|
|
|
182
182
|
### 3.4 切り出し(§1.6)/ テロップに変換(§1.5)
|
|
183
183
|
|
|
184
|
+
> 追記: 「テロップに変換」は GUI の操作としては 2026-09-21 に撤去。`kind:"telop"` の器と `baked` の再生は後方互換で残す。以下は撤去前の意味論の記録。
|
|
185
|
+
|
|
184
186
|
- どちらも一方通行。元ファイルは不変・来歴(`derivedFrom` / `from`)を残す
|
|
185
187
|
|
|
186
188
|
## 4. 描画 — クローンマスク
|
|
@@ -309,7 +311,7 @@ await p.save(); // 正規直列化 → lint ゲート
|
|
|
309
311
|
| A3 | `object-tree-render` | クローンマスク(§4)を 3 出口(preview / osr / gpu)に・名札の走査・`style` / `text` | A1 |
|
|
310
312
|
| A4 | `object-tree-write-and-migrate` | shell / preview-server / スキルの書き込みを A2 の API へ・`content` → 袋グループの migrate・1 レコード 1 行での保存 | A2, A3 |
|
|
311
313
|
| D | タイムライン木行 | 折りたたみ / D&D 再親化 / ⌘G ⌘⇧G / 段の自動生成・消滅(UI 契約) | A2 |
|
|
312
|
-
| F | 字幕 = 袋グループ(UI) | 専用段の廃止・畳んだ帯の刻み表示・行を出す /
|
|
314
|
+
| F | 字幕 = 袋グループ(UI) | 専用段の廃止・畳んだ帯の刻み表示・行を出す / テロップに変換。**追記**: 「テロップに変換」は GUI の操作としては 2026-09-21 に撤去。`kind:"telop"` の器と `baked` の再生は後方互換で残す | D, A3 |
|
|
313
315
|
| H | フォーカスモード | 姉妹契約 §7 | D + 姉妹契約 |
|
|
314
316
|
| I | SKILL.md 読み方規約 | §5.2 を edit-plan / address-review / analyze-project へ | A2 |
|
|
315
317
|
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# contract — 素材の参照モデル v0(共有ライブラリ参照の台帳と解決規則)
|
|
2
2
|
|
|
3
|
+
ライブラリの置き場は既定で作業場の `library/`。作業場が無いときは従来の `~/.akari/assets/` を使う。
|
|
4
|
+
`akari-assets list`(または `akari assets list`)の先頭行で実際の置き場を確認する。
|
|
5
|
+
以下の `<ライブラリの置き場>` はその表示先を指し、音源はその下の `audio/` に入る。
|
|
6
|
+
|
|
3
7
|
- 状態: 実装済み(機械層のみ。シェル UI の採用は後続)
|
|
4
8
|
- 決定日: 2026-09-02
|
|
5
9
|
- 実装: `packages/asset-resolver`(記帳・実体化)/ `packages/render-cut`・`packages/edit-lint`(解決)
|
|
@@ -7,7 +11,7 @@
|
|
|
7
11
|
## 1. 目的
|
|
8
12
|
|
|
9
13
|
カタログ素材をプロジェクトごとに実体コピーすると、同じ素材が何度もダウンロード・複製されて
|
|
10
|
-
|
|
14
|
+
プロジェクトが肥大する。実体は**マシン単位の共有ライブラリ**(`<ライブラリの置き場>/<category>/<id>/`)に
|
|
11
15
|
1 部だけ置き、プロジェクトには**参照だけを記録**できるようにする。
|
|
12
16
|
|
|
13
17
|
## 2. 設計の要点
|
|
@@ -25,11 +29,11 @@
|
|
|
25
29
|
edit.json の version とは無関係。
|
|
26
30
|
- **解決規則**: 宣言されたプロジェクト相対パスが `assets/<category>/<id>/<rest>` の形で、
|
|
27
31
|
(1) プロジェクト実体が存在せず、(2) 台帳に `{category, id}` があるとき、
|
|
28
|
-
|
|
29
|
-
|
|
32
|
+
`resolveAssetLibraryRoots().read` の順(新しい置き場 → 従来の置き場)にフォールバックする。
|
|
33
|
+
解決先は各ルートで字句・realpath containment を満たす正規ファイルで
|
|
30
34
|
あること(`..` 等の脱出は fail-closed で拒否)。
|
|
31
35
|
- render-cut は解決した入力を render inputs 記録に `scope: "library"` として残す
|
|
32
|
-
(既存 `scope: "akari"` と同列の additive
|
|
36
|
+
(既存 `scope: "akari"` と同列の additive 記録)。採用した実ルートを `library_root` に保存して後段でも検査する。edit-lint は解決できる参照を欠落と報告せず、
|
|
33
37
|
台帳にあるが実体が無い参照は「共有ライブラリ参照(未取得)」として欠落報告する。
|
|
34
38
|
- render-cut / edit-lint は依存ゼロ CLI のため、解決ロジックは各パッケージ内に**同一実装を重複**して
|
|
35
39
|
持つ(`src/library-reference.mjs`)。挙動同一性は両テストの同一ケース表で担保する。
|
|
@@ -47,7 +51,53 @@ akari-assets bundle --project <dir> [--dry-run]
|
|
|
47
51
|
bundle は台帳の各参照をキャッシュから `assets/<category>/<id>/` へ実体化して台帳から除去する。
|
|
48
52
|
未取得の参照は resolve(取得)を試み、取得できないものは台帳に残して部分成功(exit 非 0)で報告する。冪等。
|
|
49
53
|
|
|
50
|
-
## 4.
|
|
54
|
+
## 4. 書き出しエンジンの配信
|
|
55
|
+
|
|
56
|
+
OSR / GPU の共通配信サーバーは、render-cut が解決した入力のうち `scope: "library"` の
|
|
57
|
+
全件を許可表として受け取る。映像だけでなく、音・静止画・オーバーレイ内の素材も対象。
|
|
58
|
+
キーは宣言パス `assets/<category>/<id>/<rest>`(区切りは `/`)、値は
|
|
59
|
+
`{ absolute: <実体の絶対パス>, library_root: <採用ルート> }`。
|
|
60
|
+
配信側は置き場の探索や台帳からの再解決を行わない。
|
|
61
|
+
|
|
62
|
+
ffmpeg の計画には、同じ render inputs の解決結果で素材パス欄だけを絶対パスへ置き換えた
|
|
63
|
+
edit の写しを渡す。BGM・SFX・ナレーション・分離音声・レイヤー音声の入力と尺の probe が対象。
|
|
64
|
+
映像ソースの cut 音声は既存の解決済み capabilities を使い、contact sheet は書き出した動画を読む。
|
|
65
|
+
元の edit.json、配信用の宣言パス、receipt の入力パスは書き換えない。
|
|
66
|
+
|
|
67
|
+
別プロセスへの受け渡しには
|
|
68
|
+
`<projectRoot>/.akari/render-tmp/media-references-<render-cut の PID>.json` を使う。
|
|
69
|
+
表の形式は `{ "token": "<合言葉>", "references": { "<宣言パス>": { "absolute": "<実体の絶対パス>", "library_root": "<採用ルート>" } } }`。
|
|
70
|
+
render-cut は実行ごとに `crypto.randomBytes(32)` の合言葉を hex 文字列として生成し、
|
|
71
|
+
同じ値を環境変数 `AKARI_RENDER_MEDIA_REFERENCES_TOKEN` に設定してから書き出しを起動する。
|
|
72
|
+
この変数は Electron 子プロセスへ継承される。終了時は `finally` で元の値へ戻し、元が未定義なら削除する。
|
|
73
|
+
合言葉はログ・エラー文・render.json に出さない。
|
|
74
|
+
render-cut は子プロセスの起動前に排他的に作成し、OSR / GPU(GPU から OSR への再試行を含む)の
|
|
75
|
+
終了時に `finally` で成功・失敗とも削除する。Electron は親 PID からパスを決め、サーバー生成時に
|
|
76
|
+
一度だけ読む。別 CLI の並行実行は表を共有しない。プロセス内の使用中パス集合で
|
|
77
|
+
同じプロジェクトの重複実行(ネスト呼び出しを含む)を拒否する。集合に無い自 PID の既存表は、
|
|
78
|
+
クラッシュや PID 再利用による残存表として削除してから排他的に作り直す。
|
|
79
|
+
使用中の記録は作成・書き出し・後片付けの失敗時にも解除する。他 PID の表は回収しない。
|
|
80
|
+
ファイル経由の表は、環境変数が無い・空、表の token が文字列でない、UTF-8 バイト長が異なる、
|
|
81
|
+
または `crypto.timingSafeEqual` で一致しない場合は一切使わない。token の無い旧形式や壊れた JSON も空の表として扱う。
|
|
82
|
+
これにより単体 CLI など render-cut を通らない起動では、プロジェクトに植え込まれた表から外部ファイルを配信しない。
|
|
83
|
+
配信 API の明示引数 `mediaReferences` がある場合は従来どおりそちらを優先し、
|
|
84
|
+
表が無い場合や認証できない場合はプロジェクト内だけを配信する。
|
|
85
|
+
|
|
86
|
+
`/media/<宣言パス>` は次の順で検査する。
|
|
87
|
+
|
|
88
|
+
1. デコード後に `..` セグメント(`/` と `\` の両区切り)を含む要求は 403。
|
|
89
|
+
2. プロジェクト内の実体があれば優先する。字句・realpath の両方でプロジェクト内に収まることを
|
|
90
|
+
検査し、symlink による脱出は 403、正規ファイルでなければ 404。
|
|
91
|
+
3. プロジェクトに実体が無い場合のみ、許可表の完全一致キーを調べる。表に無いファイルは
|
|
92
|
+
ライブラリ配下に存在しても 404。
|
|
93
|
+
4. 表の実体が採用ルート内にあることを字句で確認し、さらに実体と採用ルートを毎回 realpath で
|
|
94
|
+
解決して包含を再検査する。脱出は 403、欠落・非正規ファイルは 404。
|
|
95
|
+
5. 許可した実体は既存のファイル配信を使い、通常取得は 200、Range 取得は 206 とする。
|
|
96
|
+
|
|
97
|
+
台帳にあっても置き場に無い必須素材は、従来の render inputs / 計画段階のエラーで停止する。
|
|
98
|
+
配信ページの 404 を待ってから失敗させない。
|
|
99
|
+
|
|
100
|
+
## 5. スコープ外(後続)
|
|
51
101
|
|
|
52
102
|
- シェル UI の採用(取り込みフローの reference 既定化・プロジェクト面の「参照」バッジ・
|
|
53
103
|
プレビュー経路のフォールバック)
|
|
@@ -12,7 +12,10 @@
|
|
|
12
12
|
5. 絵コンテはタイムラインの印刷(9/6 §5)。生成の入力にしない
|
|
13
13
|
6. plan.json の仮枠役(`confidence` / `fill`)は退役。`plan-comments.json` の `pass: "scaffold"` の対象は `slot` から **clip id** へ
|
|
14
14
|
7. **空の枠**(2026-09-21): 仮枠ツール(F)で空いているところに描いた枠は、prompt 未記入の**文字カード png** を素材に持つ media item(絵のないクリップを文字カード png で表す規則の延長)。0.5 秒刻み・端に吸着・隣に食い込まない・0.5 秒未満にしない。専用トラックは作らない(どのトラックにも置ける)
|
|
15
|
+
実装: 選択 V / 分割 C / 仮枠 F(従来の A / B も有効)。仮枠はスナップ OFF でも近い可視端・再生ヘッドを 0.5 秒格子より優先し、`assets/generated/frame-<時刻>-<一意接尾辞>.png` と隣の `.meta.json` に保存する。
|
|
15
16
|
8. **すき間から作る枠**(2026-09-21): すき間をクリック →「あいだを生成」で、すき間の位置と長さの枠を置く。前のクリップの最後のコマ・次のクリップの最初のコマを抽出して両端(②③)に入れる。動画からの抽出は 1 コマを `assets/captures/` へ書き出す(§10)
|
|
17
|
+
実装: 同じ映像トラックで前後にクリップがある 0.5 秒以上の空きだけをすき間とする。前は `source.out − 1/output.fps`(in 以上)、次は `source.in` の合成前のコマを使い、静止画は元パスを使う。
|
|
18
|
+
抽出 PNG は `assets/captures/frame-<素材名>-<秒>-<素材・更新時刻等のハッシュ>.png` に保存し、同じ素材・同じ時刻は再利用する。
|
|
16
19
|
9. 枠は**生成前から尺と場所を持ち、生成物は同じ item に入る**(4 の延長)。メディアパネルは経由しない(タイムライン正本)
|
|
17
20
|
|
|
18
21
|
## 2. 9 スロット(生成入力の正規形)
|
|
@@ -96,8 +99,10 @@ mp4 がまだ無い「動画予定」は、**仮枠の素材の meta**(静止
|
|
|
96
99
|
1. **読み手の判定**: `next.kind === "video"` かつ `next.status === "planned"` = 「動画予定」。`next` が無い静止画 = 「画像のまま」= 完成品。文字カード(meta 自体が `planned`)で `next` が無いか prompt が空 = 「空の枠」
|
|
97
100
|
2. `next.inputs` は §2 の 9 スロットの下書き。`first_frame` は**そのクリップの絵とは限らない**(前のクリップの最後のコマ・キャプチャ・空 = プロンプトだけ)
|
|
98
101
|
3. **`inputs.frames_or_refs`** = `"frames"` / `"references"`(`next` の下書きだけが持つ欄。§2 ⑦ の `mode` = 元動画のモードとは別物)。最初 / 最後と参照が排他のとき(`frames_and_refs_exclusive: true` の行、または同じ family の i2v 行と ref 行の切替)、**下書きは両側を保持し、送るのは `frames_or_refs` の側だけ**。切り替えで中身を消さない。バリデータはこの欄を見て反対側を送信 body から外し、生成物 meta の `inputs` にはこの欄を書かない(送った側だけが残る)
|
|
102
|
+
右パネルは同じ family のフレーム行 / 参照行を「最初 / 最後|参照」で切り替え、model ID も相方に替える。参照は種類別の札・カウンタ付きグリッドで、素材パネルから複数選択する。
|
|
99
103
|
4. **送るとき**: CLI は `next`(または `--inputs`)を読み、従来どおり**生成物の隣**に video meta(`generating`)を書く。このとき **`placeholder: { path, sha256, item_id }`** = その item が今指している素材(静止画 / 文字カード)を必ず書く。item への逆引きは `placeholder` が正、`inputs.first_frame.path` は 9/13 時点の meta のための後方互換。`next` は消さない(「同じ入力でもう一度」の元)
|
|
100
104
|
5. **状態の優先**: `placeholder` で結線された生成物 meta が `generating` / stale / `failed` ならそれを描く。無ければ `next` の `planned` を描く。`done` で差し替わった後は mp4 の meta が直接当たる(§7)
|
|
105
|
+
done で差し替わった後の作り直し(本番の画質・同じ入力でもう一度)の下書きは、mp4 の meta の `next` に持つ。元の静止画の `next` は変えない。
|
|
101
106
|
6. `next` の更新は undo に入れない(§3 規則 3 と同じ)。右パネルの編集は即保存
|
|
102
107
|
7. 移行: `.akari/generation/<itemId>.inputs.json` があり `next` が無いときだけ読み、次の保存で `next` へ移す。新規の書き込みはしない
|
|
103
108
|
8. ビート表(`akari generate still --spec`)はビートごとに動画予定(最初だけ / 最初→最後)を指定でき、指定があれば CLI が `next` を書く。指定が無ければ「画像のまま」
|
|
@@ -129,6 +134,7 @@ mp4 がまだ無い「動画予定」は、**仮枠の素材の meta**(静止
|
|
|
129
134
|
}
|
|
130
135
|
```
|
|
131
136
|
|
|
137
|
+
- 参照の順序記法は行ごとの `tag`(接頭辞)+ `tag_joiner`(省略時は空文字)+ 1 始まりの番号。Seedance は `@Image` + 空文字 → `@Image1`、H3 は `Image` + 空白 → `Image 1`。動画・音声も同様。`tag` の末尾に空白は入れない
|
|
132
138
|
- `inputs.first_frame` / `last_frame` は `"required"` / `"optional"` / `"none"` の 3 値
|
|
133
139
|
- `duration.format` は `{type: "integer"}` / `{type: "string"}` / `{type: "string", suffix: "s"}` / `{type: "string", auto: true}`
|
|
134
140
|
- `audio_out` は `true`(切替可)/ `"always"`(欄なしで付く)/ `false`
|
|
@@ -148,6 +154,8 @@ mp4 がまだ無い「動画予定」は、**仮枠の素材の meta**(静止
|
|
|
148
154
|
|
|
149
155
|
Kling v3 standard i2v / Kling v3 pro i2v / Veo 3.1 first-last / Veo 3.1 reference / Seedance 2.0 i2v / Seedance 2.0 reference / Seedance 2.5 i2v / H3 i2v / H3 reference / Wan 2.7 i2v / Grok Imagine i2v / Vidu Q3 i2v。画像: codex-image / nano-banana-pro edit。Sora は OpenAI 直アダプタが出来るまで入れない。
|
|
150
156
|
|
|
157
|
+
動画の登録済みアダプタ(2026-09-22)は `fal:h3-i2v`・`fal:h3-ref`・`fal:kling-v3-standard-i2v`・`fal:kling-v3-pro-i2v`・`fal:seedance-2.0-i2v`・`fal:seedance-2.0-ref`・`fal:veo-3.1-flf` の 7 行。カタログ収載だけでは送信できない。H3 reference は OpenAPI に従い `Image 1` / `Video 1` / `Audio 1` で参照を名指しする。`first_frame` / `last_frame` は拒否する。
|
|
158
|
+
|
|
151
159
|
### 4-4. 鮮度とドリフト
|
|
152
160
|
|
|
153
161
|
- `as_of` 必須。UI の費用表示に日付を添える
|
|
@@ -160,6 +168,8 @@ Kling v3 standard i2v / Kling v3 pro i2v / Veo 3.1 first-last / Veo 3.1 referenc
|
|
|
160
168
|
|
|
161
169
|
各アダプタは 9 スロット × 出力ノブの**全セル**に「引数名 + 書式」か「拒否」を持つ。テストは全セルを網羅する。
|
|
162
170
|
|
|
171
|
+
対応一覧は §4-3 の 6 行。Seedance 2.0 reference は画像・動画・音声参照を写し、`first_frame` / `last_frame` / `seed` は拒否する。参照用の OpenAPI 根拠は `packages/generate/test/fixtures/openapi/`(2026-09-22 取得・URL と SHA-256 は同 README)に保存する。H3 reference は記法の不一致が解消するまで登録しない。
|
|
172
|
+
|
|
163
173
|
### 5-2. 尺の書式(スパイク実測)
|
|
164
174
|
|
|
165
175
|
| モデル | 送る形 |
|
|
@@ -171,9 +181,10 @@ Kling v3 standard i2v / Kling v3 pro i2v / Veo 3.1 first-last / Veo 3.1 referenc
|
|
|
171
181
|
|
|
172
182
|
### 5-3. 参照の渡し方
|
|
173
183
|
|
|
174
|
-
-
|
|
175
|
-
-
|
|
176
|
-
-
|
|
184
|
+
- Seedance 2.0 reference と H3 reference の画像・動画・音声は配列順のまま data URI で送る。**20 MB 超は送らず error**(fal storage へのアップロードは後日)。OpenAPI の上限は画像 9・動画 3・音声 3、全種合計 12 ファイル。Seedance の音声参照には画像か動画が 1 本以上必要。H3 は 2026-09-22 取得の OpenAPI に従い音声単独も可
|
|
185
|
+
- 引数名は Seedance が `image_urls` / `video_urls` / `audio_urls`、H3 が `reference_image_urls` / `reference_video_urls` / `reference_audio_urls`。OpenAPI の正本は `packages/schemas/fixtures/gen-models/openapi/`。generate のテストも相対 URL でこの正本を直接読む。`packages/generate/test/fixtures/openapi/` は取得記録の README のみ(取得日・出典・変換方法を記録)
|
|
186
|
+
- 順序タグはカタログ行の `tag` + `tag_joiner`(省略時は空文字)+ 配列順の番号(1 始まり)。prompt の `@画像N` / `@動画N` / `@音声N` を、Seedance では `@ImageN` / `@VideoN` / `@AudioN`、H3 では `Image N` / `Video N` / `Audio N` へ置換する。該当種別の本数を超える番号や 0 以下・非整数は送らず error。provider 記法の直書きは `@` 付きだけ番号を検査する。H3 の素の英語は検査・置換せず、通常文の `Image 1 of 3` や `Image 3` を誤って拒否しない。名指しが無ければ prompt に何も足さない。名前 + 役割(PixVerse)は要素の `name` / `role` から
|
|
187
|
+
- 参照音声は `range_s` があれば media-bin の ffmpeg で切り出してから送る(クリップ範囲だけ)。指定が無ければ元の音声をそのまま送る。切り出しの一時ファイルは成功・失敗ともに削除する
|
|
177
188
|
|
|
178
189
|
## 6. 状態と見え方
|
|
179
190
|
|
|
@@ -233,6 +244,7 @@ Kling v3 standard i2v / Kling v3 pro i2v / Veo 3.1 first-last / Veo 3.1 referenc
|
|
|
233
244
|
| 費用承認 | 有償生成の実行前ゲート |
|
|
234
245
|
| 判子 | 書き出しの 1 回(9/6) |
|
|
235
246
|
| 事実帯 | モデル選択の 1 行(価格・尺・入力・音声・較正)。レーダーの代わり |
|
|
247
|
+
| 下書き → 本番の画質 | `price.by_resolution` に異なる単価が 2 つ以上ある video 行だけ対応。下書きは最安解像度。チェック ON は `next.output.resolution` を最安にして解像度を固定、OFF は直前の選択(無ければカタログ順の既定)へ戻し、見積を再計算する。生成物の `output.resolution` が最安なら下書きと判定し、カタログ・meta に判定用の欄は追加しない。done の `placeholder` を辿った元静止画が存在し `next` を保持している場合だけ「本番の画質にする…」を表示。解像度の初期値は下書き前の選択かカタログの既定で、価格順の 2 番目は使わない。より高い画質を選択 → 見積 → 既存の費用承認 → 同じ `next.inputs`(対応モデルで meta に seed があれば再使用)で生成する。既存の `writeGenerationDraft` で現在の mp4 meta の既存 `next` 欄へ送信下書きを保存し、CLI の `--item` 経路を再利用する。元静止画の `next` は消さず、同じ item の素材だけを §7 に従って差し替え、映像・色の設定を保持する。placeholder が過去の mp4 を指す場合も元静止画まで辿る。表示文言は「同じ入力でもう一度、高い画質で生成します(絵は変わることがあります)」。 |
|
|
236
248
|
|
|
237
249
|
## 10. コマ保存(キャプチャ)(2026-09-21)
|
|
238
250
|
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# akari-launcher(`akari` コマンド)
|
|
2
2
|
|
|
3
|
+
ライブラリの置き場は既定で作業場の `library/`。作業場が無いときは従来の `~/.akari/assets/` を使う。
|
|
4
|
+
`akari-assets list`(または `akari assets list`)の先頭行で実際の置き場を確認する。
|
|
5
|
+
以下の `<ライブラリの置き場>` はその表示先を指し、音源はその下の `audio/` に入る。
|
|
6
|
+
|
|
3
7
|
「UI に依存したくない。opencode 単体でも、どんなディレクトリでも始められるように」を
|
|
4
8
|
実現する薄いラッパー CLI。npm パッケージ名は `akari-video`、提供するコマンド名は `akari`
|
|
5
9
|
(npm の `akari` は別プロダクトが取得済みのため。オーナー裁定 2026-07-21 §8-2)。
|
|
@@ -24,7 +28,7 @@ akari
|
|
|
24
28
|
├─ 4. 公式音源ライブラリ(AKARI Sounds)の初回セットアップ(src/sounds-setup.mjs):
|
|
25
29
|
│ 未導入かつ TTY のとき生涯 1 回だけ [Y/n](既定 Yes)を聞き、Yes なら
|
|
26
30
|
│ packages/audio-library-setup/bin/fetch-akari-sounds.mjs で一括ダウンロード。
|
|
27
|
-
│ n は marker
|
|
31
|
+
│ n は marker(<ライブラリの置き場>/audio/.akari-sounds-declined.json)を書いて以後
|
|
28
32
|
│ 聞かない。再入口は `akari sounds`。失敗しても起動は止めない
|
|
29
33
|
│
|
|
30
34
|
└─ 5. 最後に opencode を exec する
|
|
@@ -48,7 +52,7 @@ DL・sha256 検証・適用まで実行。それ以外(npm グローバル / g
|
|
|
48
52
|
`akari store <connect|status|install|download|disconnect>`(AKARI Store 連携。マイページで発行した
|
|
49
53
|
接続トークンを `~/.akari/store-credentials.json`(0600)に保存し、購入済み一覧の確認と
|
|
50
54
|
配布物の取得ができる。`install <productId> [--from <zip>]` は購入パックを展開し、`PACK.json` の
|
|
51
|
-
収載素材を
|
|
55
|
+
収載素材を `<ライブラリの置き場>/installed.json` へ登録する。`--from` は開発・オフライン導入時に手元の
|
|
52
56
|
zip を使う。`src/store-command.mjs`)/
|
|
53
57
|
`akari assets <list|fetch|sync|...>`(素材カタログの一覧・取得・同期。
|
|
54
58
|
`packages/asset-resolver` の CLI への薄い委譲で、カタログ合成・entitlements 判定・
|