@filmwhisper/cli 0.1.0

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.
Files changed (50) hide show
  1. package/LICENSE +21 -0
  2. package/dist/__tests__/cli.test.d.ts +2 -0
  3. package/dist/__tests__/cli.test.d.ts.map +1 -0
  4. package/dist/__tests__/cli.test.js +38 -0
  5. package/dist/__tests__/cli.test.js.map +1 -0
  6. package/dist/__tests__/migrate.test.d.ts +2 -0
  7. package/dist/__tests__/migrate.test.d.ts.map +1 -0
  8. package/dist/__tests__/migrate.test.js +449 -0
  9. package/dist/__tests__/migrate.test.js.map +1 -0
  10. package/dist/commands/init.d.ts +4 -0
  11. package/dist/commands/init.d.ts.map +1 -0
  12. package/dist/commands/init.js +21 -0
  13. package/dist/commands/init.js.map +1 -0
  14. package/dist/commands/migrate.d.ts +19 -0
  15. package/dist/commands/migrate.d.ts.map +1 -0
  16. package/dist/commands/migrate.js +443 -0
  17. package/dist/commands/migrate.js.map +1 -0
  18. package/dist/commands/process.d.ts +4 -0
  19. package/dist/commands/process.d.ts.map +1 -0
  20. package/dist/commands/process.js +21 -0
  21. package/dist/commands/process.js.map +1 -0
  22. package/dist/commands/search.d.ts +4 -0
  23. package/dist/commands/search.d.ts.map +1 -0
  24. package/dist/commands/search.js +24 -0
  25. package/dist/commands/search.js.map +1 -0
  26. package/dist/commands/status.d.ts +2 -0
  27. package/dist/commands/status.d.ts.map +1 -0
  28. package/dist/commands/status.js +21 -0
  29. package/dist/commands/status.js.map +1 -0
  30. package/dist/index.d.ts +3 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +36 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/mcp-client.d.ts +11 -0
  35. package/dist/mcp-client.d.ts.map +1 -0
  36. package/dist/mcp-client.js +29 -0
  37. package/dist/mcp-client.js.map +1 -0
  38. package/package.json +29 -0
  39. package/src/__tests__/cli.test.ts +47 -0
  40. package/src/__tests__/migrate.test.ts +600 -0
  41. package/src/commands/init.ts +19 -0
  42. package/src/commands/migrate.ts +734 -0
  43. package/src/commands/process.ts +19 -0
  44. package/src/commands/search.ts +22 -0
  45. package/src/commands/status.ts +20 -0
  46. package/src/index.ts +44 -0
  47. package/src/mcp-client.ts +38 -0
  48. package/tsconfig.json +13 -0
  49. package/tsconfig.tsbuildinfo +1 -0
  50. package/vitest.config.ts +7 -0
@@ -0,0 +1,443 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import Database from "better-sqlite3";
4
+ import { randomUUID } from "node:crypto";
5
+ const FW_VERSION = "2.0.0";
6
+ function mapProcessingStatus(status) {
7
+ const valid = ["pending", "running", "complete", "failed"];
8
+ return valid.includes(status) ? status : "pending";
9
+ }
10
+ function mapReviewStatus(status) {
11
+ const valid = ["keep", "exclude", "needs_review"];
12
+ if (valid.includes(status))
13
+ return status;
14
+ // v1 may have different status values — map common ones
15
+ if (status === "approved" || status === "accepted")
16
+ return "keep";
17
+ if (status === "rejected" || status === "removed")
18
+ return "exclude";
19
+ return "needs_review";
20
+ }
21
+ /**
22
+ * Build asset_id → source_hash lookup from v1 DB.
23
+ */
24
+ function buildAssetIdToHash(v1) {
25
+ const rows = v1.prepare("SELECT id, source_hash FROM assets").all();
26
+ const map = new Map();
27
+ for (const row of rows) {
28
+ map.set(row.id, row.source_hash);
29
+ }
30
+ return map;
31
+ }
32
+ function analyzeV1(v1) {
33
+ const tables = v1.prepare("SELECT name FROM sqlite_master WHERE type='table'").all().map((r) => r.name);
34
+ const counts = {};
35
+ for (const name of tables) {
36
+ const row = v1.prepare(`SELECT COUNT(*) as count FROM "${name}"`).get();
37
+ counts[name] = row.count;
38
+ }
39
+ return { tables, counts };
40
+ }
41
+ function migrateProject(v1, projectId) {
42
+ const row = v1
43
+ .prepare("SELECT * FROM projects WHERE id = ?")
44
+ .get(projectId);
45
+ if (!row)
46
+ throw new Error(`v1 project id=${projectId} not found`);
47
+ const project = {
48
+ fw_version: FW_VERSION,
49
+ schema: "project",
50
+ name: row.name,
51
+ source_path: row.source_uri,
52
+ language: row.language,
53
+ created_at: row.created_at,
54
+ updated_at: row.updated_at,
55
+ };
56
+ if (row.proxy_spec_json && row.proxy_spec_json !== "{}") {
57
+ project.proxy_spec = row.proxy_spec_json;
58
+ }
59
+ if (row.target_duration_seconds != null) {
60
+ project.target_duration_seconds = row.target_duration_seconds;
61
+ }
62
+ return project;
63
+ }
64
+ function migrateAssets(v1, projectId) {
65
+ const assets = v1
66
+ .prepare("SELECT * FROM assets WHERE project_id = ?")
67
+ .all(projectId);
68
+ // Pre-fetch analyses and transcripts for all assets
69
+ const analyses = new Map();
70
+ const rows = v1
71
+ .prepare("SELECT * FROM asset_analysis WHERE asset_id IN (SELECT id FROM assets WHERE project_id = ?)")
72
+ .all(projectId);
73
+ for (const a of rows) {
74
+ analyses.set(a.asset_id, a);
75
+ }
76
+ const transcriptRows = v1
77
+ .prepare("SELECT * FROM transcripts WHERE asset_id IN (SELECT id FROM assets WHERE project_id = ?) ORDER BY asset_id, utterance_index")
78
+ .all(projectId);
79
+ const transcriptsByAsset = new Map();
80
+ for (const t of transcriptRows) {
81
+ const list = transcriptsByAsset.get(t.asset_id) ?? [];
82
+ list.push(t);
83
+ transcriptsByAsset.set(t.asset_id, list);
84
+ }
85
+ return assets.map((asset) => {
86
+ const fwAsset = {
87
+ fw_version: FW_VERSION,
88
+ schema: "asset",
89
+ asset_hash: asset.source_hash,
90
+ filename: path.basename(asset.source_path),
91
+ source_path: asset.source_path,
92
+ duration_seconds: (asset.duration_ms ?? 0) / 1000,
93
+ created_at: asset.created_at,
94
+ updated_at: asset.updated_at,
95
+ transcode_status: mapProcessingStatus(asset.transcode_status),
96
+ transcribe_status: mapProcessingStatus(asset.transcribe_status),
97
+ analyze_status: mapProcessingStatus(asset.analyze_status),
98
+ };
99
+ if (asset.proxy_path) {
100
+ fwAsset.proxy_path = asset.proxy_path;
101
+ }
102
+ // Merge analysis
103
+ const analysis = analyses.get(asset.id);
104
+ if (analysis) {
105
+ let segments;
106
+ try {
107
+ const rawSegments = JSON.parse(analysis.segments_json);
108
+ segments = rawSegments.map((s, i) => ({
109
+ segment_index: i,
110
+ start_ms: s.start_ms,
111
+ end_ms: s.end_ms,
112
+ editorial_role: analysis.editorial_role,
113
+ energy: analysis.energy,
114
+ story_value: analysis.story_value,
115
+ summary: s.summary,
116
+ }));
117
+ }
118
+ catch {
119
+ segments = undefined;
120
+ }
121
+ fwAsset.analysis = {
122
+ semantic: {
123
+ subject: analysis.subject,
124
+ editorial_role: analysis.editorial_role,
125
+ energy: analysis.energy,
126
+ shot_type: analysis.shot_type,
127
+ story_value: analysis.story_value,
128
+ summary: analysis.overall_description,
129
+ },
130
+ segments,
131
+ };
132
+ fwAsset.segments = segments;
133
+ }
134
+ // Merge transcripts
135
+ const transcripts = transcriptsByAsset.get(asset.id);
136
+ if (transcripts && transcripts.length > 0) {
137
+ const speakers = [...new Set(transcripts.map((t) => t.speaker_label))];
138
+ fwAsset.transcript = {
139
+ speakers,
140
+ utterances: transcripts.map((t) => ({
141
+ speaker_label: t.speaker_label,
142
+ text: t.text,
143
+ start_ms: t.start_ms,
144
+ end_ms: t.end_ms,
145
+ confidence: t.confidence ?? 0,
146
+ })),
147
+ };
148
+ }
149
+ return fwAsset;
150
+ });
151
+ }
152
+ function migrateSearchChunks(v1, v2State, projectId, assetIdToHash) {
153
+ const chunks = v1
154
+ .prepare("SELECT * FROM search_chunks WHERE project_id = ?")
155
+ .all(projectId);
156
+ if (chunks.length === 0)
157
+ return 0;
158
+ const insert = v2State.prepare(`INSERT OR IGNORE INTO segments_source (asset_hash, segment_index, transcript_text, analysis_summary, editorial_role, speaker_labels)
159
+ VALUES (?, ?, ?, ?, ?, ?)`);
160
+ let count = 0;
161
+ for (const chunk of chunks) {
162
+ const hash = assetIdToHash.get(chunk.asset_id);
163
+ if (!hash)
164
+ continue;
165
+ insert.run(hash, chunk.segment_index, chunk.transcript_text || null, chunk.chunk_text || null, chunk.editorial_role || null, chunk.speaker_labels || null);
166
+ count++;
167
+ }
168
+ return count;
169
+ }
170
+ function migrateSegmentReviews(v1, v2State, projectId, assetIdToHash) {
171
+ const reviews = v1
172
+ .prepare("SELECT * FROM segment_reviews WHERE project_id = ?")
173
+ .all(projectId);
174
+ if (reviews.length === 0)
175
+ return 0;
176
+ const insert = v2State.prepare(`INSERT OR IGNORE INTO segment_reviews (asset_hash, segment_index, status, updated_at)
177
+ VALUES (?, ?, ?, ?)`);
178
+ let count = 0;
179
+ for (const review of reviews) {
180
+ const hash = assetIdToHash.get(review.asset_id);
181
+ if (!hash)
182
+ continue;
183
+ insert.run(hash, review.segment_index, mapReviewStatus(review.status), review.updated_at);
184
+ count++;
185
+ }
186
+ return count;
187
+ }
188
+ function migrateEditPackages(v1, v2State, projectId, assetIdToHash) {
189
+ // Find the latest complete edit package
190
+ const pkg = v1
191
+ .prepare("SELECT * FROM edit_packages WHERE project_id = ? AND status = 'complete' ORDER BY version DESC LIMIT 1")
192
+ .get(projectId);
193
+ if (!pkg)
194
+ return 0;
195
+ // Try to read the EDL JSON file
196
+ let clips;
197
+ try {
198
+ const edlContent = fs.readFileSync(pkg.decision_list_path, "utf-8");
199
+ const edl = JSON.parse(edlContent);
200
+ clips = edl.clips ?? [];
201
+ }
202
+ catch {
203
+ // EDL file not readable — skip timeline migration
204
+ return 0;
205
+ }
206
+ if (clips.length === 0)
207
+ return 0;
208
+ const insert = v2State.prepare(`INSERT INTO timeline_clips (id, asset_hash, clip_index, in_point_ms, out_point_ms, editorial_rationale, created_at, updated_at)
209
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`);
210
+ const now = new Date().toISOString();
211
+ let count = 0;
212
+ for (let i = 0; i < clips.length; i++) {
213
+ const clip = clips[i];
214
+ const hash = assetIdToHash.get(clip.asset_id);
215
+ if (!hash)
216
+ continue;
217
+ insert.run(randomUUID(), hash, i, clip.source_in_ms, clip.source_out_ms, clip.selection_reason || null, now, now);
218
+ count++;
219
+ }
220
+ return count;
221
+ }
222
+ function initV2StateDb(dbPath) {
223
+ const dir = path.dirname(dbPath);
224
+ if (!fs.existsSync(dir))
225
+ fs.mkdirSync(dir, { recursive: true });
226
+ const db = new Database(dbPath);
227
+ db.pragma("journal_mode = WAL");
228
+ db.pragma("foreign_keys = ON");
229
+ db.exec(`
230
+ CREATE TABLE IF NOT EXISTS revisions (
231
+ scope TEXT PRIMARY KEY,
232
+ revision INTEGER NOT NULL DEFAULT 0
233
+ );
234
+ INSERT OR IGNORE INTO revisions (scope, revision) VALUES ('timeline', 0);
235
+ INSERT OR IGNORE INTO revisions (scope, revision) VALUES ('reviews', 0);
236
+ INSERT OR IGNORE INTO revisions (scope, revision) VALUES ('project', 0);
237
+ INSERT OR IGNORE INTO revisions (scope, revision) VALUES ('jobs', 0);
238
+ INSERT OR IGNORE INTO revisions (scope, revision) VALUES ('fts', 0);
239
+
240
+ CREATE TABLE IF NOT EXISTS timeline_clips (
241
+ id TEXT PRIMARY KEY,
242
+ asset_hash TEXT NOT NULL,
243
+ clip_index INTEGER NOT NULL,
244
+ in_point_ms INTEGER NOT NULL,
245
+ out_point_ms INTEGER NOT NULL,
246
+ editorial_rationale TEXT,
247
+ created_at TEXT NOT NULL,
248
+ updated_at TEXT NOT NULL
249
+ );
250
+
251
+ CREATE TABLE IF NOT EXISTS segment_reviews (
252
+ asset_hash TEXT NOT NULL,
253
+ segment_index INTEGER NOT NULL,
254
+ status TEXT NOT NULL CHECK(status IN ('keep', 'exclude', 'needs_review')),
255
+ reviewer TEXT,
256
+ updated_at TEXT NOT NULL,
257
+ PRIMARY KEY (asset_hash, segment_index)
258
+ );
259
+
260
+ CREATE TABLE IF NOT EXISTS undo_history (
261
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
262
+ scope TEXT NOT NULL,
263
+ operation TEXT NOT NULL,
264
+ created_at TEXT NOT NULL
265
+ );
266
+
267
+ CREATE TABLE IF NOT EXISTS jobs (
268
+ job_id TEXT PRIMARY KEY,
269
+ project_id TEXT NOT NULL,
270
+ type TEXT NOT NULL,
271
+ status TEXT NOT NULL DEFAULT 'pending',
272
+ progress REAL DEFAULT 0,
273
+ step TEXT,
274
+ params TEXT,
275
+ result TEXT,
276
+ error TEXT,
277
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
278
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
279
+ );
280
+
281
+ CREATE TABLE IF NOT EXISTS segments_source (
282
+ asset_hash TEXT NOT NULL,
283
+ segment_index INTEGER NOT NULL,
284
+ transcript_text TEXT,
285
+ analysis_summary TEXT,
286
+ editorial_role TEXT,
287
+ speaker_labels TEXT,
288
+ PRIMARY KEY (asset_hash, segment_index)
289
+ );
290
+
291
+ CREATE VIRTUAL TABLE IF NOT EXISTS segments_fts USING fts5(
292
+ transcript_text,
293
+ analysis_summary,
294
+ editorial_role,
295
+ speaker_labels,
296
+ content='segments_source',
297
+ content_rowid='rowid',
298
+ tokenize='unicode61'
299
+ );
300
+
301
+ CREATE TRIGGER IF NOT EXISTS segments_source_ai AFTER INSERT ON segments_source BEGIN
302
+ INSERT INTO segments_fts(rowid, transcript_text, analysis_summary, editorial_role, speaker_labels)
303
+ VALUES (new.rowid, new.transcript_text, new.analysis_summary, new.editorial_role, new.speaker_labels);
304
+ END;
305
+
306
+ CREATE TRIGGER IF NOT EXISTS segments_source_ad AFTER DELETE ON segments_source BEGIN
307
+ INSERT INTO segments_fts(segments_fts, rowid, transcript_text, analysis_summary, editorial_role, speaker_labels)
308
+ VALUES ('delete', old.rowid, old.transcript_text, old.analysis_summary, old.editorial_role, old.speaker_labels);
309
+ END;
310
+
311
+ CREATE TRIGGER IF NOT EXISTS segments_source_au AFTER UPDATE ON segments_source BEGIN
312
+ INSERT INTO segments_fts(segments_fts, rowid, transcript_text, analysis_summary, editorial_role, speaker_labels)
313
+ VALUES ('delete', old.rowid, old.transcript_text, old.analysis_summary, old.editorial_role, old.speaker_labels);
314
+ INSERT INTO segments_fts(rowid, transcript_text, analysis_summary, editorial_role, speaker_labels)
315
+ VALUES (new.rowid, new.transcript_text, new.analysis_summary, new.editorial_role, new.speaker_labels);
316
+ END;
317
+ `);
318
+ return db;
319
+ }
320
+ // ============================================================
321
+ // Public command
322
+ // ============================================================
323
+ export async function migrateCommand(options) {
324
+ const { source, dryRun } = options;
325
+ if (!source) {
326
+ console.error("Error: --source <path> is required");
327
+ process.exit(1);
328
+ }
329
+ if (!fs.existsSync(source)) {
330
+ console.error(`Error: Source database not found: ${source}`);
331
+ process.exit(1);
332
+ }
333
+ const v1 = new Database(source, { readonly: true });
334
+ try {
335
+ // Step 1: Analyze v1
336
+ const { tables, counts } = analyzeV1(v1);
337
+ console.log("v1 데이터베이스 분석:");
338
+ console.log("=====================");
339
+ for (const name of tables) {
340
+ console.log(` ${name}: ${counts[name]} 레코드`);
341
+ }
342
+ // Determine which project to migrate (first one)
343
+ const projects = v1.prepare("SELECT * FROM projects ORDER BY id").all();
344
+ if (projects.length === 0) {
345
+ console.error("Error: No projects found in v1 database");
346
+ process.exit(1);
347
+ }
348
+ // Migrate each project
349
+ for (const v1Project of projects) {
350
+ console.log(`\n프로젝트 마이그레이션: "${v1Project.name}" (id=${v1Project.id})`);
351
+ // Determine target path
352
+ const targetPath = options.target
353
+ ? projects.length > 1
354
+ ? path.join(options.target, v1Project.name)
355
+ : options.target
356
+ : v1Project.source_uri;
357
+ if (dryRun) {
358
+ console.log("\n[DRY RUN] 실제 변경 없음");
359
+ console.log(` 대상 경로: ${targetPath}`);
360
+ const assetCount = v1.prepare("SELECT COUNT(*) as count FROM assets WHERE project_id = ?").get(v1Project.id).count;
361
+ const analysisCount = v1
362
+ .prepare("SELECT COUNT(*) as count FROM asset_analysis WHERE asset_id IN (SELECT id FROM assets WHERE project_id = ?)")
363
+ .get(v1Project.id).count;
364
+ console.log(` 에셋: ${assetCount}개`);
365
+ console.log(` 분석: ${analysisCount}개`);
366
+ console.log(` → .fw/project.fw.json 생성 예정`);
367
+ console.log(` → .fw/assets/*.fw.json ${assetCount}개 생성 예정`);
368
+ console.log(` → .fw/state.sqlite 생성 예정`);
369
+ continue;
370
+ }
371
+ // Step 2: Backup source
372
+ const backupPath = `${source}.bak`;
373
+ if (!fs.existsSync(backupPath)) {
374
+ fs.copyFileSync(source, backupPath);
375
+ console.log(` 백업 생성: ${backupPath}`);
376
+ }
377
+ else {
378
+ console.log(` 백업 이미 존재: ${backupPath}`);
379
+ }
380
+ // Step 3: Create target directory
381
+ const fwDir = path.join(targetPath, ".fw");
382
+ const assetsDir = path.join(fwDir, "assets");
383
+ fs.mkdirSync(assetsDir, { recursive: true });
384
+ console.log(` 디렉토리 생성: ${fwDir}`);
385
+ // Step 4: Build asset ID → hash lookup
386
+ const assetIdToHash = buildAssetIdToHash(v1);
387
+ // Step 5: Migrate project JSON
388
+ const project = migrateProject(v1, v1Project.id);
389
+ const projectJsonPath = path.join(fwDir, "project.fw.json");
390
+ fs.writeFileSync(projectJsonPath, JSON.stringify(project, null, 2));
391
+ console.log(` project.fw.json 생성 완료`);
392
+ // Step 6: Migrate assets
393
+ const fwAssets = migrateAssets(v1, v1Project.id);
394
+ let analysisCount = 0;
395
+ let transcriptAssets = 0;
396
+ for (const asset of fwAssets) {
397
+ const assetPath = path.join(assetsDir, `${asset.asset_hash}.fw.json`);
398
+ fs.writeFileSync(assetPath, JSON.stringify(asset, null, 2));
399
+ if (asset.analysis)
400
+ analysisCount++;
401
+ if (asset.transcript)
402
+ transcriptAssets++;
403
+ }
404
+ console.log(` 에셋 ${fwAssets.length}개 마이그레이션 (분석: ${analysisCount}, 트랜스크립트: ${transcriptAssets})`);
405
+ // Step 7: Migrate state.sqlite data
406
+ const statePath = path.join(fwDir, "state.sqlite");
407
+ const v2State = initV2StateDb(statePath);
408
+ try {
409
+ const migrateSqlite = v2State.transaction(() => {
410
+ const chunks = migrateSearchChunks(v1, v2State, v1Project.id, assetIdToHash);
411
+ console.log(` 검색 청크 ${chunks}개 마이그레이션`);
412
+ const reviews = migrateSegmentReviews(v1, v2State, v1Project.id, assetIdToHash);
413
+ console.log(` 세그먼트 리뷰 ${reviews}개 마이그레이션`);
414
+ const clips = migrateEditPackages(v1, v2State, v1Project.id, assetIdToHash);
415
+ console.log(` 타임라인 클립 ${clips}개 마이그레이션`);
416
+ return { chunks, reviews, clips };
417
+ });
418
+ const { chunks, reviews, clips } = migrateSqlite();
419
+ console.log(`\n마이그레이션 완료: "${v1Project.name}"`);
420
+ console.log(` 경로: ${targetPath}/.fw/`);
421
+ return {
422
+ projectName: v1Project.name,
423
+ assetsCount: fwAssets.length,
424
+ analysisCount,
425
+ transcriptAssets,
426
+ searchChunks: chunks,
427
+ segmentReviews: reviews,
428
+ timelineClips: clips,
429
+ targetPath,
430
+ backupPath,
431
+ };
432
+ }
433
+ finally {
434
+ v2State.close();
435
+ }
436
+ }
437
+ }
438
+ finally {
439
+ v1.close();
440
+ }
441
+ return undefined;
442
+ }
443
+ //# sourceMappingURL=migrate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../src/commands/migrate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare function processCommand(projectId: string, options: {
2
+ steps?: string;
3
+ }): Promise<void>;
4
+ //# sourceMappingURL=process.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process.d.ts","sourceRoot":"","sources":["../../src/commands/process.ts"],"names":[],"mappings":"AAEA,wBAAsB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,iBAgBlF"}
@@ -0,0 +1,21 @@
1
+ import { createMcpClient } from "../mcp-client.js";
2
+ export async function processCommand(projectId, options) {
3
+ const client = await createMcpClient();
4
+ try {
5
+ const args = { project_id: projectId };
6
+ if (options.steps) {
7
+ args.steps = options.steps.split(",").map((s) => s.trim()).filter(Boolean);
8
+ }
9
+ const result = await client.callTool("fw_process", args);
10
+ console.log("Processing started:");
11
+ console.log(JSON.stringify(JSON.parse(result.content[0].text), null, 2));
12
+ }
13
+ catch (err) {
14
+ console.error("Error:", err instanceof Error ? err.message : err);
15
+ process.exit(1);
16
+ }
17
+ finally {
18
+ await client.close();
19
+ }
20
+ }
21
+ //# sourceMappingURL=process.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process.js","sourceRoot":"","sources":["../../src/commands/process.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,SAAiB,EAAE,OAA2B;IACjF,MAAM,MAAM,GAAG,MAAM,eAAe,EAAE,CAAC;IACvC,IAAI,CAAC;QACH,MAAM,IAAI,GAA4B,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;QAChE,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YAClB,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC7E,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;QACzD,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;QACnC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC3E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAClE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;AACH,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare function searchCommand(projectId: string, query: string, options: {
2
+ limit?: number;
3
+ }): Promise<void>;
4
+ //# sourceMappingURL=search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/commands/search.ts"],"names":[],"mappings":"AAEA,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,iBAmBhG"}
@@ -0,0 +1,24 @@
1
+ import { createMcpClient } from "../mcp-client.js";
2
+ export async function searchCommand(projectId, query, options) {
3
+ const client = await createMcpClient();
4
+ try {
5
+ const args = {
6
+ project_id: projectId,
7
+ query,
8
+ };
9
+ if (options.limit !== undefined) {
10
+ args.limit = Number(options.limit);
11
+ }
12
+ const result = await client.callTool("fw_search", args);
13
+ console.log("Search results:");
14
+ console.log(JSON.stringify(JSON.parse(result.content[0].text), null, 2));
15
+ }
16
+ catch (err) {
17
+ console.error("Error:", err instanceof Error ? err.message : err);
18
+ process.exit(1);
19
+ }
20
+ finally {
21
+ await client.close();
22
+ }
23
+ }
24
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/commands/search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,SAAiB,EAAE,KAAa,EAAE,OAA2B;IAC/F,MAAM,MAAM,GAAG,MAAM,eAAe,EAAE,CAAC;IACvC,IAAI,CAAC;QACH,MAAM,IAAI,GAA4B;YACpC,UAAU,EAAE,SAAS;YACrB,KAAK;SACN,CAAC;QACF,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YAChC,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACrC,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;QACxD,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;QAC/B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC3E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAClE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function statusCommand(projectId: string | undefined): Promise<void>;
2
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAEA,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,iBAiBhE"}
@@ -0,0 +1,21 @@
1
+ import { createMcpClient } from "../mcp-client.js";
2
+ export async function statusCommand(projectId) {
3
+ if (!projectId) {
4
+ console.error("Error: project_id is required");
5
+ process.exit(1);
6
+ }
7
+ const client = await createMcpClient();
8
+ try {
9
+ const result = await client.callTool("fw_project_status", { project_id: projectId });
10
+ console.log("Project status:");
11
+ console.log(JSON.stringify(JSON.parse(result.content[0].text), null, 2));
12
+ }
13
+ catch (err) {
14
+ console.error("Error:", err instanceof Error ? err.message : err);
15
+ process.exit(1);
16
+ }
17
+ finally {
18
+ await client.close();
19
+ }
20
+ }
21
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,SAA6B;IAC/D,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;QAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,eAAe,EAAE,CAAC;IACvC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,mBAAmB,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC;QACrF,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;QAC/B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC3E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAClE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * FilmWhisper CLI — thin wrapper around the MCP server
4
+ */
5
+ import { cac } from "cac";
6
+ import { initCommand } from "./commands/init.js";
7
+ import { statusCommand } from "./commands/status.js";
8
+ import { processCommand } from "./commands/process.js";
9
+ import { searchCommand } from "./commands/search.js";
10
+ import { migrateCommand } from "./commands/migrate.js";
11
+ const cli = cac("fw");
12
+ cli
13
+ .command("init <source_path>", "Initialize a FilmWhisper project")
14
+ .option("--name <name>", "Project name (defaults to directory name)")
15
+ .action(initCommand);
16
+ cli
17
+ .command("status [project_id]", "Show project status")
18
+ .action(statusCommand);
19
+ cli
20
+ .command("process <project_id>", "Process project assets")
21
+ .option("--steps <steps>", "Processing steps (comma-separated: transcode,transcribe,analyze)")
22
+ .action(processCommand);
23
+ cli
24
+ .command("search <project_id> <query>", "Search project assets")
25
+ .option("--limit <limit>", "Max results", { default: 20 })
26
+ .action(searchCommand);
27
+ cli
28
+ .command("migrate", "Migrate from v1 database")
29
+ .option("--source <source>", "Path to v1 SQLite database")
30
+ .option("--target <target>", "Target directory for v2 project")
31
+ .option("--dry-run", "Show migration plan without making changes")
32
+ .action(migrateCommand);
33
+ cli.help();
34
+ cli.version("0.1.0");
35
+ cli.parse();
36
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;GAEG;AACH,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC;AAEtB,GAAG;KACA,OAAO,CAAC,oBAAoB,EAAE,kCAAkC,CAAC;KACjE,MAAM,CAAC,eAAe,EAAE,2CAA2C,CAAC;KACpE,MAAM,CAAC,WAAW,CAAC,CAAC;AAEvB,GAAG;KACA,OAAO,CAAC,qBAAqB,EAAE,qBAAqB,CAAC;KACrD,MAAM,CAAC,aAAa,CAAC,CAAC;AAEzB,GAAG;KACA,OAAO,CAAC,sBAAsB,EAAE,wBAAwB,CAAC;KACzD,MAAM,CAAC,iBAAiB,EAAE,kEAAkE,CAAC;KAC7F,MAAM,CAAC,cAAc,CAAC,CAAC;AAE1B,GAAG;KACA,OAAO,CAAC,6BAA6B,EAAE,uBAAuB,CAAC;KAC/D,MAAM,CAAC,iBAAiB,EAAE,aAAa,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;KACzD,MAAM,CAAC,aAAa,CAAC,CAAC;AAEzB,GAAG;KACA,OAAO,CAAC,SAAS,EAAE,0BAA0B,CAAC;KAC9C,MAAM,CAAC,mBAAmB,EAAE,4BAA4B,CAAC;KACzD,MAAM,CAAC,mBAAmB,EAAE,iCAAiC,CAAC;KAC9D,MAAM,CAAC,WAAW,EAAE,4CAA4C,CAAC;KACjE,MAAM,CAAC,cAAc,CAAC,CAAC;AAE1B,GAAG,CAAC,IAAI,EAAE,CAAC;AACX,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;AAErB,GAAG,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,11 @@
1
+ export interface FwClient {
2
+ callTool(name: string, args: Record<string, unknown>): Promise<{
3
+ content: Array<{
4
+ type: string;
5
+ text: string;
6
+ }>;
7
+ }>;
8
+ close(): Promise<void>;
9
+ }
10
+ export declare function createMcpClient(): Promise<FwClient>;
11
+ //# sourceMappingURL=mcp-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-client.d.ts","sourceRoot":"","sources":["../src/mcp-client.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC,CAAC;IACnH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,QAAQ,CAAC,CAsBzD"}