akari-video 0.1.5 → 0.1.7
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 +18 -3
- package/bin/akari.mjs +52 -5
- package/package.json +1 -1
- package/src/assets-command.mjs +42 -0
- package/src/cli.mjs +48 -13
- package/src/internal-command.mjs +69 -0
- package/src/messages.mjs +51 -4
- package/{vendor/skills/generate-narration/bin/generate-narration.mjs → src/narration-command.mjs} +48 -31
- package/src/new-command.mjs +119 -0
- package/src/project-state.mjs +10 -1
- package/src/repo-assets.mjs +24 -4
- package/src/self-update.mjs +383 -0
- package/src/sounds-setup.mjs +22 -7
- package/src/status-command.mjs +18 -1
- package/src/status-core/display-name.mjs +22 -0
- package/src/status-core/status.mjs +9 -1
- package/src/status-core/workspace.mjs +123 -0
- package/src/update-check.mjs +130 -3
- package/vendor/.akari-capability-sources.json +4 -4
- package/vendor/docs/contract-2026-07-22-render-basics.md +16 -1
- package/vendor/docs/contract-2026-07-23-analysis-person-matte.md +1 -1
- package/vendor/docs/contract-2026-08-02-creator-root-v1.md +15 -2
- package/vendor/docs/contract-2026-08-02-preview-parity.md +216 -3
- package/vendor/docs/contract-2026-08-03-caption-display-encoding-qc-v1.md +21 -0
- package/vendor/docs/contract-2026-08-05-fx-v0.md +13 -0
- package/vendor/docs/contract-2026-08-11-analysis-vision-tracks-v0.md +177 -0
- package/vendor/docs/contract-2026-08-11-review-session-ui-events.md +89 -0
- package/vendor/packages/akari-launcher/README.md +18 -3
- package/vendor/packages/akari-launcher/bin/akari.mjs +52 -5
- package/vendor/packages/akari-launcher/package.json +1 -1
- package/vendor/packages/akari-tools/package.json +16 -0
- package/vendor/packages/asset-resolver/README.md +30 -2
- package/vendor/packages/asset-resolver/browse/app.js +124 -0
- package/vendor/packages/asset-resolver/browse/index.html +74 -0
- package/vendor/packages/asset-resolver/src/browse-server.mjs +151 -0
- package/vendor/packages/asset-resolver/src/catalog.mjs +58 -0
- package/vendor/packages/asset-resolver/src/entitlements.mjs +36 -0
- package/vendor/packages/asset-resolver/src/env.mjs +92 -0
- package/vendor/packages/asset-resolver/src/errors.mjs +10 -0
- package/vendor/packages/asset-resolver/src/fetch-file.mjs +60 -0
- package/vendor/packages/asset-resolver/src/hash.mjs +15 -0
- package/vendor/packages/asset-resolver/src/library.mjs +38 -0
- package/vendor/packages/asset-resolver/src/paid-zip.mjs +116 -0
- package/vendor/packages/asset-resolver/src/resolve.mjs +226 -0
- package/vendor/packages/asset-resolver/src/state.mjs +34 -0
- package/vendor/packages/asset-resolver/test/browse-server.test.mjs +42 -0
- package/vendor/packages/asset-resolver/test/catalog-and-state.test.mjs +37 -0
- package/vendor/packages/asset-resolver/test/entitlements.test.mjs +56 -0
- package/vendor/packages/asset-resolver/test/fixtures/build-fixture-library.mjs +106 -0
- package/vendor/packages/asset-resolver/test/helpers.mjs +28 -0
- package/vendor/packages/asset-resolver/test/resolve-integrity.test.mjs +32 -0
- package/vendor/packages/asset-resolver/test/resolve-locked.test.mjs +45 -0
- package/vendor/packages/asset-resolver/test/resolve-paid-zip.test.mjs +219 -0
- package/vendor/packages/asset-resolver/test/resolve-project-copy-darwin.test.mjs +84 -0
- package/vendor/packages/asset-resolver/test/resolve-success.test.mjs +55 -0
- package/vendor/packages/creator-root/src/index.mjs +238 -2
- package/vendor/packages/creator-root/test/create-creator-root.test.mjs +31 -1
- package/vendor/packages/creator-root/test/default-root-path.test.mjs +5 -5
- package/vendor/packages/overlay-runtime/README.md +140 -0
- package/vendor/packages/overlay-runtime/package.json +2 -2
- package/vendor/packages/preview-server/src/server.mjs +134 -17
- package/vendor/packages/project-scaffold/src/index.mjs +22 -7
- package/vendor/packages/project-scaffold/test/create-project.test.mjs +68 -2
- package/vendor/packages/render-cut/bin/akari-apply-textstyle.mjs +3 -3
- package/vendor/packages/schemas/analysis.schema.json +42 -0
- package/vendor/packages/schemas/bin/validate-captions.mjs +149 -5
- package/vendor/packages/schemas/bin/validate-edit.mjs +53 -11
- package/vendor/packages/schemas/bin/validate-intake.mjs +11 -1
- package/vendor/packages/schemas/captions.schema.json +148 -3
- package/vendor/packages/schemas/edit.schema.json +38 -21
- package/vendor/packages/schemas/examples/edit-cuts-fx-intensity-out-of-range-invalid/edit.json +1 -1
- package/vendor/packages/schemas/examples/edit-cuts-fx-unknown-key-invalid/edit.json +1 -1
- package/vendor/packages/schemas/examples/edit-cuts-fx-valid/edit.json +5 -5
- package/vendor/packages/schemas/examples/edit-layers-keyframes-valid/edit.json +38 -0
- package/vendor/packages/schemas/fixtures/intake/invalid-title-wrong-type/intake.json +9 -0
- package/vendor/packages/schemas/fixtures/intake/valid-with-title/intake.json +9 -0
- package/vendor/packages/schemas/intake.schema.json +8 -0
- package/vendor/packages/schemas/test/captions-animation-contract.test.mjs +38 -0
- package/vendor/packages/schemas/test/validate-captions.test.mjs +13 -0
- package/vendor/packages/schemas/test/validate-edit.test.mjs +137 -17
- package/vendor/packages/schemas/test/validate-intake.test.mjs +17 -0
- package/vendor/skills/analyze-footage/SKILL.md +2 -0
- package/vendor/skills/analyze-footage/analysis-json.md +2 -0
- package/vendor/skills/analyze-footage/bin/is-main-module.mjs +11 -0
- package/vendor/skills/analyze-footage/bin/person-matte/alpha-tag.mjs +4 -0
- package/vendor/skills/analyze-footage/bin/person-matte/person-matte.mjs +5 -2
- package/vendor/skills/analyze-footage/bin/transcribe-cloud.mjs +2 -3
- package/vendor/skills/analyze-footage/bin/vision-tracks/vision-tracks-helper.swift +399 -0
- package/vendor/skills/analyze-footage/bin/vision-tracks/vision-tracks.mjs +476 -0
- package/vendor/skills/analyze-footage/references/vision-tracks.schema.json +215 -0
- package/vendor/skills/analyze-footage/test/entrypoint-symlink.test.mjs +36 -0
- package/vendor/skills/analyze-footage/test/fixtures/vision-tracks/dummy-helper.mjs +91 -0
- package/vendor/skills/analyze-footage/test/fixtures/vision-tracks/example-face-landmarks.json +27 -0
- package/vendor/skills/analyze-footage/test/fixtures/vision-tracks/example-hand-pose.json +24 -0
- package/vendor/skills/analyze-footage/test/fixtures/vision-tracks/invalid-missing-required-landmark.json +25 -0
- package/vendor/skills/analyze-footage/test/fixtures/vision-tracks/invalid-out-of-range-coordinate.json +22 -0
- package/vendor/skills/analyze-footage/test/fixtures/vision-tracks/invalid-unknown-kind.json +8 -0
- package/vendor/skills/analyze-footage/test/person-matte-alpha-tag.test.mjs +21 -0
- package/vendor/skills/analyze-footage/test/vision-tracks-assembly.test.mjs +209 -0
- package/vendor/skills/analyze-footage/test/vision-tracks-check.test.mjs +77 -0
- package/vendor/skills/analyze-footage/test/vision-tracks-coords.test.mjs +106 -0
- package/vendor/skills/analyze-footage/test/vision-tracks-schema.test.mjs +89 -0
- package/vendor/skills/analyze-footage/vision-tracks.md +212 -0
- package/vendor/skills/beat-sync-edit/SKILL.md +3 -3
- package/vendor/skills/beat-sync-edit/generator.md +2 -2
- package/vendor/skills/beat-sync-edit/templates/gen-timeline.mjs +1 -1
- package/vendor/skills/beat-sync-edit/verify-loop.md +3 -2
- package/vendor/skills/compile-review-session/bin/compile-review-session.mjs +12 -1
- package/vendor/skills/compile-review-session/bin/core/compiler.mjs +7 -3
- package/vendor/skills/compile-review-session/bin/core/time-mapping.mjs +166 -8
- package/vendor/skills/compile-review-session/compilation-rules.md +46 -0
- package/vendor/skills/compile-review-session/dev-fixtures/README.md +1 -0
- package/vendor/skills/compile-review-session/dev-fixtures/fixture-project/review/sessions/s-0009/audio.wav +0 -0
- package/vendor/skills/compile-review-session/dev-fixtures/fixture-project/review/sessions/s-0009/edit.snapshot.json +12 -0
- package/vendor/skills/compile-review-session/dev-fixtures/fixture-project/review/sessions/s-0009/events.jsonl +5 -0
- package/vendor/skills/compile-review-session/dev-fixtures/fixture-project/review/sessions/s-0009/session.json +11 -0
- package/vendor/skills/compile-review-session/test/ui-events.test.mjs +331 -0
- package/vendor/skills/create-project/SKILL.md +2 -2
- package/vendor/skills/edit-plan/bin/generated/contract-validators.cjs +417 -72
- package/vendor/skills/edit-plan/expression-selection.md +4 -0
- package/vendor/skills/generate-narration/avatar-voice.md +3 -3
- package/vendor/skills/generate-narration/engines.md +2 -2
- package/vendor/skills/generate-narration/voice-profile-setup.md +2 -2
- package/vendor/skills/manage-connections/SKILL.md +9 -5
- package/vendor/skills/manage-connections/bin/doctor.mjs +114 -3
- package/vendor/skills/manage-connections/bin/resolve-connections.mjs +348 -0
- package/vendor/skills/manage-connections/test/resolve-connections.test.mjs +151 -0
- package/vendor/skills/overlay-authoring/3d.md +41 -0
- package/vendor/skills/overlay-authoring/motion.md +21 -0
- package/vendor/skills/overlay-authoring/telop.md +1 -0
- package/vendor/skills/setup-library/SKILL.md +12 -0
- package/vendor/templates/project-default/.akari/connections.json +1 -225
- package/vendor/templates/project-default/AGENTS.md +8 -0
- package/vendor/templates/project-default/CLAUDE.md +6 -0
- package/vendor/templates/project-default/akari.sh +119 -11
- package/vendor/docs/contract-2026-08-06-direction-recipes-v0.md +0 -234
- package/vendor/packages/direction/README.md +0 -52
- package/vendor/packages/direction/bin/expand-direction.mjs +0 -160
- package/vendor/packages/direction/package.json +0 -13
- package/vendor/packages/schemas/examples/edit-cuts-fx-color-overlay-missing-color-invalid/edit.json +0 -9
- package/vendor/skills/beat-sync-edit/bin/beatmap.mjs +0 -131
- package/vendor/skills/beat-sync-edit/bin/probe-frame.mjs +0 -96
- package/vendor/skills/beat-sync-edit/bin/render-when-idle.sh +0 -46
- package/vendor/skills/create-project/bin/create-project.mjs +0 -88
- /package/vendor/packages/schemas/examples/{edit-cuts-fx-invalid-id → edit-cuts-fx-unknown-id-valid}/edit.json +0 -0
package/README.md
CHANGED
|
@@ -31,11 +31,26 @@ akari
|
|
|
31
31
|
(PATH に opencode が無ければ、インストール案内を出して終了する)
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
install.sh 経由インストール(`~/.akari/app`)では、新版の検知・裏 staging DL・sha256 検証・
|
|
35
|
+
次回起動時の自動適用がすべて既定で走る(`AKARI_NO_AUTO_UPDATE=1` で無効化可)。起動を
|
|
36
|
+
ブロックすることは無く、適用は次回起動の頭でアトミックにスワップする(`src/update-check.mjs`
|
|
37
|
+
の `maybeStageInBackground` / `maybeApplyPendingUpdateOnLaunch`、実体は `src/self-update.mjs`
|
|
38
|
+
の `stageSelfUpdate` / `swapStagedApp`)。
|
|
39
|
+
|
|
40
|
+
サブコマンド: `akari update`(オンデマンドの確認・適用。install.sh 経由インストールなら
|
|
41
|
+
DL・sha256 検証・適用まで実行。それ以外(npm グローバル / git checkout)や旧フィードでは
|
|
42
|
+
更新案内のみ表示。`--rollback` で直前 1 世代へ戻す。`src/self-update.mjs`)/
|
|
43
|
+
`akari init`(作業場の作成・確認のみ)/
|
|
44
|
+
`akari new <target-dir> [--template <path>]`(新規プロジェクト作成)/
|
|
45
|
+
`akari narration generate ...`(VOICEVOX / fal-qwen3 ナレーション生成)/
|
|
46
|
+
`akari internal beat-sync-<beatmap|probe-frame|render-when-idle> ...`(beat-sync-edit 内部実行物)/
|
|
35
47
|
`akari sounds [--variant wav] [--force]`(公式音源の一括ダウンロード。プロンプトなし・headless 可)/
|
|
36
48
|
`akari store <connect|status|download|disconnect>`(AKARI Store 連携。マイページで発行した
|
|
37
49
|
接続トークンを `~/.akari/store-credentials.json`(0600)に保存し、購入済み一覧の確認と
|
|
38
|
-
配布物の取得ができる。`src/store-command.mjs
|
|
50
|
+
配布物の取得ができる。`src/store-command.mjs`)/
|
|
51
|
+
`akari assets <list|fetch|sync|...>`(素材カタログの一覧・取得・同期。
|
|
52
|
+
`packages/asset-resolver` の CLI への薄い委譲で、カタログ合成・entitlements 判定・
|
|
53
|
+
sha256 検証・fail-closed は resolver 側の責務のまま。`src/assets-command.mjs`)。
|
|
39
54
|
|
|
40
55
|
`akari` に渡した引数はそのまま `opencode` に転送する(例: `akari --continue` は
|
|
41
56
|
`opencode --continue` を起動する)。
|
|
@@ -67,7 +82,7 @@ AKARI Video は「同じファイル契約(`.akari/` 配下の JSON)に収
|
|
|
67
82
|
| アプリ | 接続ボタン(AKARI Video アプリ) | アプリの「はじめる」画面から接続 → はじめかた選択 |
|
|
68
83
|
|
|
69
84
|
3 つとも最終的に同じもの(`.akari/connections.json` / `.akari/intake.json` /
|
|
70
|
-
`
|
|
85
|
+
`akari new` が使う共通 project-scaffold)を読み書きするため、どの入口から始めても続きは他の入口から
|
|
71
86
|
再開できる。
|
|
72
87
|
|
|
73
88
|
## インストール
|
package/bin/akari.mjs
CHANGED
|
@@ -1,25 +1,72 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { run, runUpdateCommand } from '../src/cli.mjs';
|
|
3
3
|
import { runInitCommand } from '../src/init-command.mjs';
|
|
4
|
+
import { runNewCommand } from '../src/new-command.mjs';
|
|
5
|
+
import { runNarrationCommand } from '../src/narration-command.mjs';
|
|
6
|
+
import { runInternalCommand } from '../src/internal-command.mjs';
|
|
4
7
|
import { runSoundsCommand } from '../src/sounds-setup.mjs';
|
|
5
8
|
import { runStatusCommand } from '../src/status-command.mjs';
|
|
6
9
|
import { runAcceptCommand } from '../src/accept-command.mjs';
|
|
7
10
|
import { runCapabilityCommand } from '../src/capability-command.mjs';
|
|
8
11
|
import { runStoreCommand } from '../src/store-command.mjs';
|
|
12
|
+
import { runAssetsCommand } from '../src/assets-command.mjs';
|
|
13
|
+
import { maybeApplyPendingUpdateOnLaunch, readOwnVersion } from '../src/update-check.mjs';
|
|
14
|
+
import { describeCliHelp } from '../src/messages.mjs';
|
|
15
|
+
|
|
16
|
+
// `akari --version` / `-v`: インストール済みの版を表示するだけの最小コマンド
|
|
17
|
+
// (タスク契約 2026-08-11-update-u4-cli-self-update の受け入れ条件 —
|
|
18
|
+
// `akari update` / `--rollback` 後にインストール先の版を観測する手段として必要)。
|
|
19
|
+
async function printVersion() {
|
|
20
|
+
console.log(`v${readOwnVersion()}`);
|
|
21
|
+
return { exitCode: 0 };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// `akari --help` / `-h`: 引数なしのトップレベル一覧を表示するだけの最小コマンド
|
|
25
|
+
// (タスク契約 2026-08-11-onboarding-o3-firstrun-plain §4。それ以前はこの分岐が無く、
|
|
26
|
+
// `--help` は claude/opencode へそのまま転送されてしまっていた — AKARI Video 自身の
|
|
27
|
+
// コマンド一覧が一度も出ない行き止まりだったため新設した)。
|
|
28
|
+
async function printCliHelp() {
|
|
29
|
+
for (const line of describeCliHelp()) {
|
|
30
|
+
console.log(line);
|
|
31
|
+
}
|
|
32
|
+
return { exitCode: 0 };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// 起動の頭で保留中の自動適用があれば適用する(契約 §11・タスク契約
|
|
36
|
+
// 2026-08-11-update-u5-cli-auto-update)。すべてのサブコマンド分岐より前に置く —
|
|
37
|
+
// 「起動」= akari バイナリの実行そのものであり、`--version` や `akari update` の
|
|
38
|
+
// 入口でも既に新版へ切り替わっている必要がある(受け入れ条件: 2 回目の起動で
|
|
39
|
+
// `akari --version` が新版を返す。スワップは rename ベースで `~/.akari/app` の
|
|
40
|
+
// 実体を差し替えるだけなので、このプロセス自身がこの後 `readOwnVersion()` を
|
|
41
|
+
// 読み直せば新版の内容を観測できる — 同一 argv での re-exec はしない設計判断
|
|
42
|
+
// (理由は report.md 参照))。失敗は他の起動時副作用と同じく握りつぶし、
|
|
43
|
+
// claude/opencode 起動やサブコマンド実行を止めない。
|
|
44
|
+
try {
|
|
45
|
+
maybeApplyPendingUpdateOnLaunch({ env: process.env, log: (line) => console.log(line) });
|
|
46
|
+
} catch (error) {
|
|
47
|
+
console.error(`自動更新の適用確認でエラーが発生しました(続行します): ${error instanceof Error ? error.message : String(error)}`);
|
|
48
|
+
}
|
|
9
49
|
|
|
10
50
|
const argv = process.argv.slice(2);
|
|
11
|
-
// `akari update` / `akari init` / `akari
|
|
12
|
-
// `akari capability` / `akari store`
|
|
13
|
-
//
|
|
14
|
-
// 音源カタログ既定化のオーナー裁定 2026-08-03 /
|
|
51
|
+
// `akari update` / `akari init` / `akari new` / `akari narration` / `akari internal` /
|
|
52
|
+
// `akari sounds` / `akari status` / `akari accept` / `akari capability` / `akari store` /
|
|
53
|
+
// `akari assets` は claude へ転送せず、専用のサブコマンドとして扱う(契約 §4-1 /
|
|
54
|
+
// タスク契約 launcher-init(内部リポ)/ 音源カタログ既定化のオーナー裁定 2026-08-03 /
|
|
55
|
+
// AKARI Store 連携 / タスク契約 2026-08-09-agent-assets-discovery)。
|
|
15
56
|
// それ以外の引数はすべて従来どおり claude へ転送する。
|
|
16
|
-
const invoke = argv[0] === '
|
|
57
|
+
const invoke = (argv[0] === '--version' || argv[0] === '-v') ? printVersion()
|
|
58
|
+
: (argv[0] === '--help' || argv[0] === '-h') ? printCliHelp()
|
|
59
|
+
: argv[0] === 'update' ? runUpdateCommand(argv.slice(1))
|
|
17
60
|
: argv[0] === 'init' ? runInitCommand(argv.slice(1))
|
|
61
|
+
: argv[0] === 'new' ? runNewCommand(argv.slice(1))
|
|
62
|
+
: argv[0] === 'narration' ? runNarrationCommand(argv.slice(1))
|
|
63
|
+
: argv[0] === 'internal' ? runInternalCommand(argv.slice(1))
|
|
18
64
|
: argv[0] === 'sounds' ? runSoundsCommand(argv.slice(1))
|
|
19
65
|
: argv[0] === 'status' ? runStatusCommand(argv.slice(1))
|
|
20
66
|
: argv[0] === 'accept' ? runAcceptCommand(argv.slice(1))
|
|
21
67
|
: argv[0] === 'capability' ? runCapabilityCommand(argv.slice(1))
|
|
22
68
|
: argv[0] === 'store' ? runStoreCommand(argv.slice(1))
|
|
69
|
+
: argv[0] === 'assets' ? runAssetsCommand(argv.slice(1))
|
|
23
70
|
: run(argv);
|
|
24
71
|
|
|
25
72
|
const result = await invoke.catch((error) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "akari-video",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
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": {
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
|
|
3
|
+
import { resolveLauncherAssets } from './repo-assets.mjs';
|
|
4
|
+
import { assetsResolverUnavailableError } from './messages.mjs';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* `akari assets <list|fetch|sync|...>` — `packages/asset-resolver` の CLI
|
|
8
|
+
* (`bin/akari-assets.mjs`)への薄い委譲(タスク契約 2026-08-09-agent-assets-discovery)。
|
|
9
|
+
*
|
|
10
|
+
* カタログ合成・entitlements 判定・取得・sha256 検証・validate-asset・fail-closed の実ロジックは
|
|
11
|
+
* すべて resolver 側の責務のまま変更しない。認証(`~/.akari/store-credentials.json`)も
|
|
12
|
+
* resolver がそのまま読む。ここでは引数をそのまま子プロセスへ転送し、resolver 側の usage /
|
|
13
|
+
* エラー文言 / exit code をそのまま利用者に返すだけ。
|
|
14
|
+
*
|
|
15
|
+
* 規約は他の launcher 委譲コマンド(`akari sounds` = sounds-setup.mjs)と同じ:
|
|
16
|
+
* - 同梱の実体解決は `resolveLauncherAssets()`(モノレポ checkout → npm 配布時の vendor/)
|
|
17
|
+
* - 副作用(spawn)は options で注入可能・node --test で実プロセス不要
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
function defaultSpawnAssetsCli(cliPath, args, env) {
|
|
21
|
+
// stdio: inherit — list の一覧表示・fetch の進捗ログ・JSON 出力をそのまま利用者に見せる
|
|
22
|
+
// (sounds-setup.mjs の defaultSpawnFetch と同じ流儀)。env を明示的に渡すのは必須 —
|
|
23
|
+
// 注入された AKARI_HOME(テスト・隔離実行)が resolver 側の解決にも効くようにする。
|
|
24
|
+
return spawnSync(process.execPath, [cliPath, ...args], { stdio: 'inherit', env });
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function runAssetsCommand(args, options = {}) {
|
|
28
|
+
const logError = options.logError ?? ((line) => console.error(line));
|
|
29
|
+
const env = options.env ?? process.env;
|
|
30
|
+
const assets = options.assets ?? resolveLauncherAssets();
|
|
31
|
+
|
|
32
|
+
const cliPath = assets?.assetResolverCliPath;
|
|
33
|
+
if (!cliPath) {
|
|
34
|
+
logError(assetsResolverUnavailableError());
|
|
35
|
+
return { exitCode: 1 };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const spawnAssetsCli = options.spawnAssetsCli ?? defaultSpawnAssetsCli;
|
|
39
|
+
const result = spawnAssetsCli(cliPath, args, env);
|
|
40
|
+
const exitCode = typeof result.status === 'number' ? result.status : (result.error ? 1 : 0);
|
|
41
|
+
return { exitCode };
|
|
42
|
+
}
|
package/src/cli.mjs
CHANGED
|
@@ -11,12 +11,15 @@ import { resolveEffectiveProjectRoot } from './first-run.mjs';
|
|
|
11
11
|
import { maybeShowAssetIntroNotice } from './sounds-setup.mjs';
|
|
12
12
|
import {
|
|
13
13
|
checkForUpdateSync,
|
|
14
|
+
compareVersions,
|
|
15
|
+
isValidFeedShape,
|
|
14
16
|
readCacheSync,
|
|
15
17
|
readOwnVersion,
|
|
16
18
|
recordDismissalSync,
|
|
17
19
|
resolveCachePath,
|
|
18
20
|
triggerBackgroundRefresh
|
|
19
21
|
} from './update-check.mjs';
|
|
22
|
+
import { applySelfUpdate, isRunningFromAppDir, rollbackSelfUpdate } from './self-update.mjs';
|
|
20
23
|
|
|
21
24
|
/**
|
|
22
25
|
* `akari` ランチャーの本体。3 入口契約(ターミナル `akari` / セッション内 `/akari` /
|
|
@@ -173,11 +176,15 @@ function defaultSpawnOpencode(opencodePath, args, projectRoot) {
|
|
|
173
176
|
}
|
|
174
177
|
|
|
175
178
|
/**
|
|
176
|
-
* `akari update`:
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
179
|
+
* `akari update`: 新版があり、かつ自己更新の対象(app 経由実行 + フィードに
|
|
180
|
+
* `components.app` がある)なら DL → sha256 検証 → 適用まで実行する(契約 §11。
|
|
181
|
+
* 「update は明示操作」なので U2 の沈黙原則は適用せず、失敗は必ず表示する)。
|
|
182
|
+
* 対象外(npm グローバル / git checkout・旧フィード)のときは従来どおり
|
|
183
|
+
* **案内するだけ**(自動実行はしない — 契約 §4-1)に縮退する。`--dismiss` は
|
|
184
|
+
* 自己更新を試みず、キャッシュに載っている最新版の通知を今後出さないよう記録するだけ
|
|
185
|
+
* (既存挙動を維持)。`--rollback` は直前 1 世代(`~/.akari/app-previous/`)へ戻す。
|
|
186
|
+
* ネットワークに触れるのは自己更新の DL 区間のみ — フィード自体は既存キャッシュ由来
|
|
187
|
+
* (最新情報は `akari` 起動時のバックグラウンド fetch で更新される)。
|
|
181
188
|
*/
|
|
182
189
|
export async function runUpdateCommand(args, options = {}) {
|
|
183
190
|
const log = options.log ?? ((line) => console.log(line));
|
|
@@ -186,16 +193,44 @@ export async function runUpdateCommand(args, options = {}) {
|
|
|
186
193
|
const cachePath = resolveCachePath(env);
|
|
187
194
|
const cache = readCacheSync(cachePath);
|
|
188
195
|
const dismissRequested = args.includes('--dismiss');
|
|
196
|
+
const rollbackRequested = args.includes('--rollback');
|
|
189
197
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
recordDismissalSync({ version: cache.feed.product, env });
|
|
193
|
-
dismissed = true;
|
|
198
|
+
if (rollbackRequested) {
|
|
199
|
+
return (options.rollbackSelfUpdate ?? rollbackSelfUpdate)({ env, log });
|
|
194
200
|
}
|
|
195
201
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
202
|
+
if (dismissRequested) {
|
|
203
|
+
let dismissed = false;
|
|
204
|
+
if (typeof cache?.feed?.product === 'string') {
|
|
205
|
+
recordDismissalSync({ version: cache.feed.product, env });
|
|
206
|
+
dismissed = true;
|
|
207
|
+
}
|
|
208
|
+
const finalCache = dismissed ? readCacheSync(cachePath) : cache;
|
|
209
|
+
for (const line of describeUpdateCommand({ currentVersion, cache: finalCache, dismissed })) {
|
|
210
|
+
log(line);
|
|
211
|
+
}
|
|
212
|
+
return { exitCode: 0 };
|
|
199
213
|
}
|
|
200
|
-
|
|
214
|
+
|
|
215
|
+
const feed = cache?.feed;
|
|
216
|
+
const updateAvailable = isValidFeedShape(feed) && compareVersions(feed.product, currentVersion) > 0;
|
|
217
|
+
const selfUpdateEligible = updateAvailable
|
|
218
|
+
&& !!feed.components?.app?.url
|
|
219
|
+
&& !!feed.components?.app?.sha256
|
|
220
|
+
&& (options.isRunningFromAppDir ?? isRunningFromAppDir)({ env, launcherRoot: options.launcherRoot });
|
|
221
|
+
|
|
222
|
+
if (!selfUpdateEligible) {
|
|
223
|
+
for (const line of describeUpdateCommand({ currentVersion, cache, dismissed: false })) {
|
|
224
|
+
log(line);
|
|
225
|
+
}
|
|
226
|
+
return { exitCode: 0 };
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return (options.applySelfUpdate ?? applySelfUpdate)({
|
|
230
|
+
env,
|
|
231
|
+
feed,
|
|
232
|
+
log,
|
|
233
|
+
fetchImpl: options.fetchImpl,
|
|
234
|
+
runNpmInstall: options.runNpmInstall
|
|
235
|
+
});
|
|
201
236
|
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { spawnSync } from 'node:child_process';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
import { resolveLauncherAssets } from './repo-assets.mjs';
|
|
6
|
+
|
|
7
|
+
const commands = [
|
|
8
|
+
'beat-sync-beatmap',
|
|
9
|
+
'beat-sync-probe-frame',
|
|
10
|
+
'beat-sync-render-when-idle',
|
|
11
|
+
'vision-finger-frame',
|
|
12
|
+
'eye-bar'
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
const usage = [
|
|
16
|
+
'使い方: akari internal <subcommand> [args...]',
|
|
17
|
+
'',
|
|
18
|
+
'サブコマンド:',
|
|
19
|
+
...commands.map((command) => ` ${command}`)
|
|
20
|
+
].join('\n');
|
|
21
|
+
|
|
22
|
+
export async function runInternalCommand(args, options = {}) {
|
|
23
|
+
const log = options.log ?? ((line) => console.log(line));
|
|
24
|
+
const logError = options.logError ?? ((line) => console.error(line));
|
|
25
|
+
const assets = options.assets ?? resolveLauncherAssets();
|
|
26
|
+
const spawn = options.spawn ?? spawnSync;
|
|
27
|
+
const subcommand = args[0];
|
|
28
|
+
|
|
29
|
+
if (!subcommand || subcommand === '--help' || subcommand === '-h') {
|
|
30
|
+
log(usage);
|
|
31
|
+
return { exitCode: 0 };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// vision-finger-frame は task/2026-08-11-finger-frame-generator の境界規約により
|
|
35
|
+
// repo-assets.mjs(別タスク task/2026-08-11-eye-bar-generator と衝突しやすい共有ファイル)を
|
|
36
|
+
// 編集せず、他コマンドと違い assets.repoRoot から自己解決する(resolveRepoAssets() 側に
|
|
37
|
+
// フィールドを追加していない唯一の例外 -- 経緯は非公開の内部記録を参照)。
|
|
38
|
+
const fingerFrameScript = assets.repoRoot
|
|
39
|
+
? path.join(assets.repoRoot, 'packages', 'akari-tools', 'bin', 'finger-frame.mjs')
|
|
40
|
+
: null;
|
|
41
|
+
|
|
42
|
+
const definitions = {
|
|
43
|
+
'beat-sync-beatmap': { path: assets.beatmapScript, node: true },
|
|
44
|
+
'beat-sync-probe-frame': { path: assets.probeFrameScript, node: true },
|
|
45
|
+
'beat-sync-render-when-idle': { path: assets.renderWhenIdleScript, node: false },
|
|
46
|
+
'vision-finger-frame': {
|
|
47
|
+
path: fingerFrameScript && existsSync(fingerFrameScript) ? fingerFrameScript : null,
|
|
48
|
+
node: true
|
|
49
|
+
},
|
|
50
|
+
'eye-bar': { path: assets.eyeBarScript, node: true }
|
|
51
|
+
};
|
|
52
|
+
const definition = definitions[subcommand];
|
|
53
|
+
if (!definition) {
|
|
54
|
+
logError(`不明な internal サブコマンドです: ${subcommand}`);
|
|
55
|
+
log(usage);
|
|
56
|
+
return { exitCode: 1 };
|
|
57
|
+
}
|
|
58
|
+
if (!definition.path) {
|
|
59
|
+
logError(`内部コマンド ${subcommand} の実行スクリプトが見つかりません。AKARI Video の完全な checkout または配布物を確認してください。`);
|
|
60
|
+
return { exitCode: 1 };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const forwardedArgs = args.slice(1);
|
|
64
|
+
const result = definition.node
|
|
65
|
+
? spawn(process.execPath, [definition.path, ...forwardedArgs], { stdio: 'inherit' })
|
|
66
|
+
: spawn(definition.path, forwardedArgs, { stdio: 'inherit' });
|
|
67
|
+
const exitCode = typeof result?.status === 'number' ? result.status : 1;
|
|
68
|
+
return { exitCode };
|
|
69
|
+
}
|
package/src/messages.mjs
CHANGED
|
@@ -48,7 +48,7 @@ export function claudeMissingGuidance() {
|
|
|
48
48
|
export function opencodeMissingGuidance() {
|
|
49
49
|
return [
|
|
50
50
|
'opencode コマンドが見つかりませんでした。',
|
|
51
|
-
'opencode をインストールしてください: npm install -g opencode',
|
|
51
|
+
'opencode をインストールしてください: npm install -g opencode-ai',
|
|
52
52
|
'インストール後、このフォルダーで再度 `akari --opencode` を実行してください。'
|
|
53
53
|
].join('\n');
|
|
54
54
|
}
|
|
@@ -163,18 +163,25 @@ export function initFailedError(errorMessage) {
|
|
|
163
163
|
}
|
|
164
164
|
|
|
165
165
|
/**
|
|
166
|
-
* 素材の取得方式案内 +
|
|
167
|
-
*
|
|
166
|
+
* 素材の取得方式案内 + 無料スターターパック(`akari store connect`)+ 公式音源ライブラリ
|
|
167
|
+
* (AKARI Sounds)明示再入口(`akari sounds`)の文言群。1 行主義の既存流儀に従う。
|
|
168
168
|
*
|
|
169
169
|
* 2026-08-04 オーナー方針(正本: `planning/notes-2026-08-04-asset-reference-distribution.md`
|
|
170
170
|
* §8)により、初回起動での AKARI Sounds 一括ダウンロード [Y/n] 質問(2026-08-03 裁定)は
|
|
171
171
|
* 廃止した。素材は resolver がオンデマンド取得する設計に一本化されたため、質問文言
|
|
172
172
|
* (`soundsPromptText` / `soundsDeclinedNotice`)はもう使わない。
|
|
173
|
+
*
|
|
174
|
+
* 2026-08-11 オーナー裁定(正本: 内部リポ `planning/notes-2026-08-11-onboarding-firstrun.md`
|
|
175
|
+
* §3 R2)により、無料スターターパックの案内を同じ 1 回だけの通知に統合した(別画面を増やさない
|
|
176
|
+
* =「1 画面 1 問まで」の精神)。件数は明記しない(実際のパック内容は入れ替わりうるため
|
|
177
|
+
* 実数依存の表現にしない)。表示条件は `sounds-setup.mjs` の `maybeShowAssetIntroNotice` が
|
|
178
|
+
* 持つ — 既にアカウント連携済みなら、この文言ごと表示をスキップする(連携ずみの人には
|
|
179
|
+
* 「連携すると使える」という案内自体が的外れなため)。
|
|
173
180
|
*/
|
|
174
181
|
|
|
175
182
|
/** `akari` 起動時に生涯 1 回だけ出す素材案内(質問ではない・対話をブロックしない)。 */
|
|
176
183
|
export function assetIntroNotice() {
|
|
177
|
-
return '素材(B-roll
|
|
184
|
+
return '素材(B-roll・背景・音源)は使うときに必要な分だけ自動で取得されます。無料の素材パックもあります — `akari store connect` でアカウント連携すると使えるようになります。まとめて音源だけ欲しい場合は `akari sounds` で一括ダウンロードできます(この案内は次回以降表示しません)。';
|
|
178
185
|
}
|
|
179
186
|
|
|
180
187
|
/** ダウンロード成功後の完了 + 追加カタログ(外部補完)の案内。`akari sounds` の完了時に使う。 */
|
|
@@ -191,3 +198,43 @@ export function soundsFailedNotice() {
|
|
|
191
198
|
export function soundsUnavailableError() {
|
|
192
199
|
return '音源セットアップスクリプト(audio-library-setup)が見つかりませんでした。';
|
|
193
200
|
}
|
|
201
|
+
|
|
202
|
+
/** `akari assets`: 素材 resolver(asset-resolver)が同梱されていない場合のエラー(stderr 1 行)。 */
|
|
203
|
+
export function assetsResolverUnavailableError() {
|
|
204
|
+
return '素材 resolver(asset-resolver)が見つかりませんでした。`akari assets` は使えません。';
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* `akari --help` / `akari -h`(Node CLI 版。npm 配布 `akari-video` パッケージの `akari`
|
|
209
|
+
* コマンド)の出力(タスク契約 `2026-08-11-onboarding-o3-firstrun-plain` §4)。
|
|
210
|
+
* `akari.sh` の `-h|--help` 出力と同じ「作る → プレビュー → 連携/素材 → 更新」の初心者目線の
|
|
211
|
+
* 並びに揃え、開発者向けのフラグ・サブコマンドは末尾に降格する。プレビューサーバーは
|
|
212
|
+
* シェル版(`akari.sh --preview`)専用の機能で npm 版の `akari` 単体には同梱されないため、
|
|
213
|
+
* 案内が行き止まりにならないようその旨を明示する。
|
|
214
|
+
*/
|
|
215
|
+
export function describeCliHelp() {
|
|
216
|
+
return [
|
|
217
|
+
'AKARI Video — AI が主体で動画を編集するツール',
|
|
218
|
+
'',
|
|
219
|
+
'使い方: akari [command] [options...]',
|
|
220
|
+
'',
|
|
221
|
+
'よく使うコマンド:',
|
|
222
|
+
' (引数なし) プロジェクトを開いて AI エージェントを起動(未作成なら自動作成)',
|
|
223
|
+
' store connect アカウント連携(無料の素材パックと購入済み素材が使えるようになる)',
|
|
224
|
+
' sounds 公式音源ライブラリを一括ダウンロード(無料)',
|
|
225
|
+
' update 更新を確認する',
|
|
226
|
+
' status 接続状態を確認する',
|
|
227
|
+
'',
|
|
228
|
+
'開発者向け:',
|
|
229
|
+
' --opencode Claude Code の代わりに opencode を起動する',
|
|
230
|
+
' --claude, --claudecode Claude Code を明示的に起動する',
|
|
231
|
+
' -y, --yes 自動承認(確認をスキップ)',
|
|
232
|
+
' --version, -v インストール済みのバージョンを表示',
|
|
233
|
+
' new <dir> 雛形からプロジェクトを新規作成',
|
|
234
|
+
' init 保存フォルダ(作業場)だけを作成・確認',
|
|
235
|
+
' narration / assets / internal / capability 各機能の詳細は `akari <command> --help`',
|
|
236
|
+
' -h, --help このヘルプを表示',
|
|
237
|
+
'',
|
|
238
|
+
'プレビューサーバー(ブラウザで確認する画面)はシェル版のみ対応です: akari.sh --preview'
|
|
239
|
+
];
|
|
240
|
+
}
|
package/{vendor/skills/generate-narration/bin/generate-narration.mjs → src/narration-command.mjs}
RENAMED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
1
|
// 原稿テキストから VOICEVOX(ローカル)または fal Qwen3-TTS(自声クローン)でナレーション音声を
|
|
4
2
|
// 生成し、docs/contract-2026-07-20-edit-json-v1-narration.md 準拠のエントリを組み立てる。
|
|
5
3
|
|
|
@@ -17,12 +15,20 @@ const FAL_USD_PER_1000_CHARS = 0.09;
|
|
|
17
15
|
|
|
18
16
|
const usage = [
|
|
19
17
|
"使い方:",
|
|
20
|
-
"
|
|
18
|
+
" akari narration generate \\",
|
|
21
19
|
" --project <projectDir> --engine <voicevox|fal-qwen3> \\",
|
|
22
20
|
" --reading-file <読み原稿.txt> [--script-file <表示原稿.txt>] \\",
|
|
23
21
|
" --t <タイムライン秒> [--gain-db 0] [--id n-0001] \\",
|
|
24
22
|
" [--speaker 3] [--profile owner-ja] [--dry-run] [--yes] [--apply]",
|
|
25
23
|
].join("\n");
|
|
24
|
+
const commandUsage = [
|
|
25
|
+
"使い方: akari narration <subcommand> [options]",
|
|
26
|
+
"",
|
|
27
|
+
"サブコマンド:",
|
|
28
|
+
" generate 原稿からナレーション音声を生成する",
|
|
29
|
+
"",
|
|
30
|
+
usage,
|
|
31
|
+
].join("\n");
|
|
26
32
|
|
|
27
33
|
class PublicError extends Error {
|
|
28
34
|
constructor(message, exitCode = 1) {
|
|
@@ -31,8 +37,8 @@ class PublicError extends Error {
|
|
|
31
37
|
}
|
|
32
38
|
}
|
|
33
39
|
|
|
34
|
-
function printJson(value) {
|
|
35
|
-
|
|
40
|
+
function printJson(value, log = (line) => console.log(line)) {
|
|
41
|
+
log(JSON.stringify(value, null, 2));
|
|
36
42
|
}
|
|
37
43
|
|
|
38
44
|
function sleep(ms) {
|
|
@@ -390,10 +396,10 @@ async function synthesizeVoicevox(readingText, speakerId) {
|
|
|
390
396
|
// --- edit.json への --apply ---
|
|
391
397
|
|
|
392
398
|
function validateEditScriptPath() {
|
|
393
|
-
return fileURLToPath(new URL("
|
|
399
|
+
return fileURLToPath(new URL("../../schemas/bin/validate-edit.mjs", import.meta.url));
|
|
394
400
|
}
|
|
395
401
|
|
|
396
|
-
function applyToEditJson(projectDir, entry) {
|
|
402
|
+
function applyToEditJson(projectDir, entry, io) {
|
|
397
403
|
const editPath = path.join(projectDir, "edit.json");
|
|
398
404
|
let originalText;
|
|
399
405
|
try {
|
|
@@ -422,7 +428,7 @@ function applyToEditJson(projectDir, entry) {
|
|
|
422
428
|
`validate-edit が NG のため edit.json への書き込みをロールバックしました。\n${detail}`,
|
|
423
429
|
);
|
|
424
430
|
}
|
|
425
|
-
|
|
431
|
+
io.logError(`edit.json に ${entry.id} を追加しました(validate-edit: PASS)。`);
|
|
426
432
|
}
|
|
427
433
|
|
|
428
434
|
// --- dry-run ---
|
|
@@ -432,7 +438,7 @@ function maskKey(secret) {
|
|
|
432
438
|
return secret ? "***configured***" : "***unconfigured***";
|
|
433
439
|
}
|
|
434
440
|
|
|
435
|
-
async function runDryRun(options, readingText) {
|
|
441
|
+
async function runDryRun(options, readingText, io) {
|
|
436
442
|
const outputPath = relativeOutputPath(options.id ?? computeNextId(options.project), options.engine);
|
|
437
443
|
if (options.engine === "voicevox") {
|
|
438
444
|
printJson({
|
|
@@ -449,7 +455,7 @@ async function runDryRun(options, readingText) {
|
|
|
449
455
|
speaker: Number(options.speaker),
|
|
450
456
|
text: readingText,
|
|
451
457
|
},
|
|
452
|
-
});
|
|
458
|
+
}, io.log);
|
|
453
459
|
return;
|
|
454
460
|
}
|
|
455
461
|
|
|
@@ -467,18 +473,18 @@ async function runDryRun(options, readingText) {
|
|
|
467
473
|
headers: { Authorization: `Key ${maskKey(falKey)}` },
|
|
468
474
|
body: payload,
|
|
469
475
|
},
|
|
470
|
-
});
|
|
476
|
+
}, io.log);
|
|
471
477
|
}
|
|
472
478
|
|
|
473
479
|
// --- generate 本体 ---
|
|
474
480
|
|
|
475
|
-
async function runGenerate(options) {
|
|
481
|
+
async function runGenerate(options, io) {
|
|
476
482
|
const readingText = readTextFile(options.readingFile, "読み原稿");
|
|
477
483
|
const scriptText = options.scriptFile ? readTextFile(options.scriptFile, "表示原稿") : null;
|
|
478
484
|
|
|
479
485
|
if (options.dryRun) {
|
|
480
|
-
await runDryRun(options, readingText);
|
|
481
|
-
return;
|
|
486
|
+
await runDryRun(options, readingText, io);
|
|
487
|
+
return 0;
|
|
482
488
|
}
|
|
483
489
|
|
|
484
490
|
const id = options.id ?? computeNextId(options.project);
|
|
@@ -514,18 +520,15 @@ async function runGenerate(options) {
|
|
|
514
520
|
const falKey = resolveFalKey();
|
|
515
521
|
const meta = readProfileMeta(options.profile);
|
|
516
522
|
const estimatedCostUsd = estimateFalCostUsd(readingText);
|
|
517
|
-
|
|
518
|
-
`fal-qwen3 推定費用: 約 $${estimatedCostUsd}(${readingText.length} 文字 × $${FAL_USD_PER_1000_CHARS}/1000字)\n`,
|
|
519
|
-
);
|
|
523
|
+
io.logError(`fal-qwen3 推定費用: 約 $${estimatedCostUsd}(${readingText.length} 文字 × $${FAL_USD_PER_1000_CHARS}/1000字)`);
|
|
520
524
|
if (!options.yes) {
|
|
521
525
|
printJson({
|
|
522
526
|
sent: false,
|
|
523
527
|
engine: "fal-qwen3",
|
|
524
528
|
estimated_cost_usd: estimatedCostUsd,
|
|
525
529
|
reason: "費用承認(--yes)がありません。実リクエストは送信していません。",
|
|
526
|
-
});
|
|
527
|
-
|
|
528
|
-
return;
|
|
530
|
+
}, io.log);
|
|
531
|
+
return 2;
|
|
529
532
|
}
|
|
530
533
|
// --yes が明示された場合のみ、ここで初めて課金の発生する fal API を呼び出す。
|
|
531
534
|
audioBuffer = await synthesizeFal(readingText, meta, falKey);
|
|
@@ -550,23 +553,37 @@ async function runGenerate(options) {
|
|
|
550
553
|
provenance,
|
|
551
554
|
};
|
|
552
555
|
|
|
553
|
-
if (options.apply) applyToEditJson(options.project, entry);
|
|
556
|
+
if (options.apply) applyToEditJson(options.project, entry, io);
|
|
554
557
|
|
|
555
|
-
printJson(entry);
|
|
558
|
+
printJson(entry, io.log);
|
|
559
|
+
return 0;
|
|
556
560
|
}
|
|
557
561
|
|
|
558
|
-
async function
|
|
559
|
-
|
|
562
|
+
export async function runNarrationCommand(args, commandOptions = {}) {
|
|
563
|
+
const io = {
|
|
564
|
+
log: commandOptions.log ?? ((line) => console.log(line)),
|
|
565
|
+
logError: commandOptions.logError ?? ((line) => console.error(line)),
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
|
|
569
|
+
io.log(commandUsage);
|
|
570
|
+
return { exitCode: 0 };
|
|
571
|
+
}
|
|
572
|
+
if (args[0] === 'generate' && (args.includes('--help') || args.includes('-h'))) {
|
|
573
|
+
io.log(usage);
|
|
574
|
+
return { exitCode: 0 };
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
let parsedOptions;
|
|
560
578
|
try {
|
|
561
|
-
|
|
562
|
-
await runGenerate(
|
|
579
|
+
parsedOptions = parseArguments(args);
|
|
580
|
+
const exitCode = await runGenerate(parsedOptions, io);
|
|
581
|
+
return { exitCode };
|
|
563
582
|
} catch (error) {
|
|
564
583
|
const exitCode = error instanceof PublicError ? error.exitCode : 1;
|
|
565
584
|
const message = error instanceof PublicError ? error.message : `内部処理に失敗しました: ${error?.message ?? error}`;
|
|
566
|
-
|
|
567
|
-
printJson({ error: message });
|
|
568
|
-
|
|
585
|
+
io.logError(message);
|
|
586
|
+
printJson({ error: message }, io.log);
|
|
587
|
+
return { exitCode };
|
|
569
588
|
}
|
|
570
589
|
}
|
|
571
|
-
|
|
572
|
-
await main();
|