@proletariat/cli 0.3.57 → 0.3.59
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/dist/commands/{spec/view.d.ts → dashboard/index.d.ts} +4 -6
- package/dist/commands/dashboard/index.js +117 -0
- package/dist/commands/dashboard/index.js.map +1 -0
- package/dist/commands/execution/config.js +5 -4
- package/dist/commands/execution/config.js.map +1 -1
- package/dist/commands/execution/stop.js +4 -2
- package/dist/commands/execution/stop.js.map +1 -1
- package/dist/commands/execution/view.js +3 -0
- package/dist/commands/execution/view.js.map +1 -1
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.js +40 -3
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/mcp-server.js +1 -2
- package/dist/commands/mcp-server.js.map +1 -1
- package/dist/commands/media/add.d.ts +19 -0
- package/dist/commands/media/add.js +94 -0
- package/dist/commands/media/add.js.map +1 -0
- package/dist/commands/{spec → media}/index.d.ts +1 -1
- package/dist/commands/media/index.js +85 -0
- package/dist/commands/media/index.js.map +1 -0
- package/dist/commands/{spec/link/remove.d.ts → media/list.d.ts} +3 -6
- package/dist/commands/media/list.js +89 -0
- package/dist/commands/media/list.js.map +1 -0
- package/dist/commands/media/preprocess.d.ts +19 -0
- package/dist/commands/media/preprocess.js +91 -0
- package/dist/commands/media/preprocess.js.map +1 -0
- package/dist/commands/{spec/delete.d.ts → media/remove.d.ts} +2 -2
- package/dist/commands/media/remove.js +101 -0
- package/dist/commands/media/remove.js.map +1 -0
- package/dist/commands/{spec/link/index.d.ts → media/show.d.ts} +3 -3
- package/dist/commands/media/show.js +122 -0
- package/dist/commands/media/show.js.map +1 -0
- package/dist/commands/orchestrator/start.js +5 -0
- package/dist/commands/orchestrator/start.js.map +1 -1
- package/dist/commands/session/exec.d.ts +19 -0
- package/dist/commands/session/exec.js +205 -0
- package/dist/commands/session/exec.js.map +1 -0
- package/dist/commands/session/index.js +12 -0
- package/dist/commands/session/index.js.map +1 -1
- package/dist/commands/{spec/link/depends.d.ts → session/inspect.d.ts} +4 -4
- package/dist/commands/session/inspect.js +316 -0
- package/dist/commands/session/inspect.js.map +1 -0
- package/dist/commands/session/peek.d.ts +15 -0
- package/dist/commands/session/peek.js +141 -8
- package/dist/commands/session/peek.js.map +1 -1
- package/dist/commands/session/poke.d.ts +4 -1
- package/dist/commands/session/poke.js +175 -20
- package/dist/commands/session/poke.js.map +1 -1
- package/dist/commands/session/restart.d.ts +20 -0
- package/dist/commands/session/restart.js +320 -0
- package/dist/commands/session/restart.js.map +1 -0
- package/dist/commands/tools/add.d.ts +20 -0
- package/dist/commands/tools/add.js +129 -0
- package/dist/commands/tools/add.js.map +1 -0
- package/dist/commands/tools/check.d.ts +10 -0
- package/dist/commands/tools/check.js +75 -0
- package/dist/commands/tools/check.js.map +1 -0
- package/dist/commands/tools/detect.d.ts +11 -0
- package/dist/commands/tools/detect.js +107 -0
- package/dist/commands/tools/detect.js.map +1 -0
- package/dist/commands/tools/index.d.ts +11 -0
- package/dist/commands/tools/index.js +87 -0
- package/dist/commands/tools/index.js.map +1 -0
- package/dist/commands/tools/remove.d.ts +13 -0
- package/dist/commands/tools/remove.js +55 -0
- package/dist/commands/tools/remove.js.map +1 -0
- package/dist/commands/trello/configure.d.ts +16 -0
- package/dist/commands/trello/configure.js +259 -0
- package/dist/commands/trello/configure.js.map +1 -0
- package/dist/commands/{spec/plan.d.ts → trello/import.d.ts} +3 -5
- package/dist/commands/trello/import.js +241 -0
- package/dist/commands/trello/import.js.map +1 -0
- package/dist/commands/{spec/ticket.d.ts → trello/sync.d.ts} +5 -6
- package/dist/commands/trello/sync.js +190 -0
- package/dist/commands/trello/sync.js.map +1 -0
- package/dist/commands/work/start.d.ts +2 -0
- package/dist/commands/work/start.js +27 -41
- package/dist/commands/work/start.js.map +1 -1
- package/dist/lib/dashboard/data.d.ts +64 -0
- package/dist/lib/dashboard/data.js +259 -0
- package/dist/lib/dashboard/data.js.map +1 -0
- package/dist/lib/dashboard/html.d.ts +7 -0
- package/dist/lib/dashboard/html.js +682 -0
- package/dist/lib/dashboard/html.js.map +1 -0
- package/dist/lib/dashboard/server.d.ts +20 -0
- package/dist/lib/dashboard/server.js +114 -0
- package/dist/lib/dashboard/server.js.map +1 -0
- package/dist/lib/database/index.d.ts +49 -1
- package/dist/lib/database/index.js +127 -0
- package/dist/lib/database/index.js.map +1 -1
- package/dist/lib/execution/config.d.ts +8 -0
- package/dist/lib/execution/config.js +83 -4
- package/dist/lib/execution/config.js.map +1 -1
- package/dist/lib/execution/runners.d.ts +60 -4
- package/dist/lib/execution/runners.js +398 -79
- package/dist/lib/execution/runners.js.map +1 -1
- package/dist/lib/execution/spawner.d.ts +4 -2
- package/dist/lib/execution/spawner.js +54 -47
- package/dist/lib/execution/spawner.js.map +1 -1
- package/dist/lib/execution/types.d.ts +27 -5
- package/dist/lib/execution/types.js +24 -0
- package/dist/lib/execution/types.js.map +1 -1
- package/dist/lib/external-issues/adapters.d.ts +17 -0
- package/dist/lib/external-issues/adapters.js +88 -0
- package/dist/lib/external-issues/adapters.js.map +1 -1
- package/dist/lib/external-issues/mapping-store.js +1 -1
- package/dist/lib/external-issues/shortcut.js +2 -1
- package/dist/lib/external-issues/shortcut.js.map +1 -1
- package/dist/lib/external-issues/trello.d.ts +80 -0
- package/dist/lib/external-issues/trello.js +266 -0
- package/dist/lib/external-issues/trello.js.map +1 -0
- package/dist/lib/external-issues/types.d.ts +3 -3
- package/dist/lib/external-issues/types.js +1 -1
- package/dist/lib/external-issues/types.js.map +1 -1
- package/dist/lib/linear/client.d.ts +4 -3
- package/dist/lib/linear/client.js +185 -122
- package/dist/lib/linear/client.js.map +1 -1
- package/dist/lib/mcp/tools/cli-passthrough.js +77 -0
- package/dist/lib/mcp/tools/cli-passthrough.js.map +1 -1
- package/dist/lib/mcp/tools/index.d.ts +0 -1
- package/dist/lib/mcp/tools/index.js +0 -1
- package/dist/lib/mcp/tools/index.js.map +1 -1
- package/dist/lib/media/index.d.ts +91 -0
- package/dist/lib/media/index.js +475 -0
- package/dist/lib/media/index.js.map +1 -0
- package/dist/lib/onboarding/detect-tools.d.ts +15 -0
- package/dist/lib/onboarding/detect-tools.js +44 -0
- package/dist/lib/onboarding/detect-tools.js.map +1 -0
- package/dist/lib/onboarding/index.d.ts +2 -0
- package/dist/lib/onboarding/index.js +3 -0
- package/dist/lib/onboarding/index.js.map +1 -0
- package/dist/lib/onboarding/wizard.d.ts +25 -0
- package/dist/lib/onboarding/wizard.js +156 -0
- package/dist/lib/onboarding/wizard.js.map +1 -0
- package/dist/lib/pmo/schema.d.ts +2 -1
- package/dist/lib/pmo/schema.js +3 -1
- package/dist/lib/pmo/schema.js.map +1 -1
- package/dist/lib/runners/claude-code-runner.js +6 -0
- package/dist/lib/runners/claude-code-runner.js.map +1 -1
- package/dist/lib/tool-registry/detect.d.ts +20 -0
- package/dist/lib/tool-registry/detect.js +95 -0
- package/dist/lib/tool-registry/detect.js.map +1 -0
- package/dist/lib/tool-registry/index.d.ts +10 -0
- package/dist/lib/tool-registry/index.js +13 -0
- package/dist/lib/tool-registry/index.js.map +1 -0
- package/dist/lib/tool-registry/policy.d.ts +32 -0
- package/dist/lib/tool-registry/policy.js +97 -0
- package/dist/lib/tool-registry/policy.js.map +1 -0
- package/dist/lib/tool-registry/registry.d.ts +42 -0
- package/dist/lib/tool-registry/registry.js +120 -0
- package/dist/lib/tool-registry/registry.js.map +1 -0
- package/dist/lib/tool-registry/spawn.d.ts +50 -0
- package/dist/lib/tool-registry/spawn.js +103 -0
- package/dist/lib/tool-registry/spawn.js.map +1 -0
- package/dist/lib/tool-registry/types.d.ts +56 -0
- package/dist/lib/tool-registry/types.js +109 -0
- package/dist/lib/tool-registry/types.js.map +1 -0
- package/dist/lib/trello/client.d.ts +23 -0
- package/dist/lib/trello/client.js +114 -0
- package/dist/lib/trello/client.js.map +1 -0
- package/dist/lib/trello/config.d.ts +55 -0
- package/dist/lib/trello/config.js +127 -0
- package/dist/lib/trello/config.js.map +1 -0
- package/dist/lib/trello/index.d.ts +5 -0
- package/dist/lib/trello/index.js +5 -0
- package/dist/lib/trello/index.js.map +1 -0
- package/dist/lib/trello/mapper.d.ts +13 -0
- package/dist/lib/trello/mapper.js +71 -0
- package/dist/lib/trello/mapper.js.map +1 -0
- package/dist/lib/trello/sync.d.ts +13 -0
- package/dist/lib/trello/sync.js +38 -0
- package/dist/lib/trello/sync.js.map +1 -0
- package/dist/lib/trello/types.d.ts +53 -0
- package/dist/lib/trello/types.js +2 -0
- package/dist/lib/trello/types.js.map +1 -0
- package/dist/lib/work-source/client.js +17 -0
- package/dist/lib/work-source/client.js.map +1 -1
- package/dist/lib/work-source/config.d.ts +6 -1
- package/dist/lib/work-source/config.js +30 -1
- package/dist/lib/work-source/config.js.map +1 -1
- package/dist/lib/work-source/index.d.ts +1 -1
- package/dist/lib/work-source/index.js +1 -1
- package/dist/lib/work-source/index.js.map +1 -1
- package/oclif.manifest.json +6524 -6171
- package/package.json +6 -2
- package/dist/commands/spec/create.d.ts +0 -20
- package/dist/commands/spec/create.js +0 -171
- package/dist/commands/spec/create.js.map +0 -1
- package/dist/commands/spec/delete.js +0 -112
- package/dist/commands/spec/delete.js.map +0 -1
- package/dist/commands/spec/edit.d.ts +0 -23
- package/dist/commands/spec/edit.js +0 -262
- package/dist/commands/spec/edit.js.map +0 -1
- package/dist/commands/spec/index.js +0 -88
- package/dist/commands/spec/index.js.map +0 -1
- package/dist/commands/spec/link/depends.js +0 -87
- package/dist/commands/spec/link/depends.js.map +0 -1
- package/dist/commands/spec/link/index.js +0 -93
- package/dist/commands/spec/link/index.js.map +0 -1
- package/dist/commands/spec/link/remove.js +0 -91
- package/dist/commands/spec/link/remove.js.map +0 -1
- package/dist/commands/spec/list.d.ts +0 -14
- package/dist/commands/spec/list.js +0 -101
- package/dist/commands/spec/list.js.map +0 -1
- package/dist/commands/spec/plan.js +0 -102
- package/dist/commands/spec/plan.js.map +0 -1
- package/dist/commands/spec/ticket.js +0 -144
- package/dist/commands/spec/ticket.js.map +0 -1
- package/dist/commands/spec/view.js +0 -202
- package/dist/commands/spec/view.js.map +0 -1
- package/dist/lib/mcp/tools/spec.d.ts +0 -6
- package/dist/lib/mcp/tools/spec.js +0 -197
- package/dist/lib/mcp/tools/spec.js.map +0 -1
- package/dist/lib/pmo/spec-parser.d.ts +0 -25
- package/dist/lib/pmo/spec-parser.js +0 -206
- package/dist/lib/pmo/spec-parser.js.map +0 -1
- package/dist/lib/pmo/spec-types.d.ts +0 -43
- package/dist/lib/pmo/spec-types.js +0 -8
- package/dist/lib/pmo/spec-types.js.map +0 -1
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Media Library
|
|
3
|
+
*
|
|
4
|
+
* Manages media files (videos, audio) in HQ workspaces.
|
|
5
|
+
* Preprocesses media into frames + transcripts for agent consumption.
|
|
6
|
+
*/
|
|
7
|
+
import { type MediaItem } from '../database/index.js';
|
|
8
|
+
export type { MediaItem } from '../database/index.js';
|
|
9
|
+
/**
|
|
10
|
+
* Check if ffmpeg is installed
|
|
11
|
+
*/
|
|
12
|
+
export declare function isFfmpegInstalled(): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Check if whisper (or whisper.cpp) is available for transcription
|
|
15
|
+
*/
|
|
16
|
+
export declare function isWhisperInstalled(): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Detect if a file is video or audio based on extension
|
|
19
|
+
*/
|
|
20
|
+
export declare function detectMediaType(filePath: string): 'video' | 'audio' | null;
|
|
21
|
+
/**
|
|
22
|
+
* Get the media directory path within the HQ
|
|
23
|
+
*/
|
|
24
|
+
export declare function getMediaDir(hqPath: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* Add a media file to the HQ
|
|
27
|
+
*/
|
|
28
|
+
export declare function addMedia(hqPath: string, sourcePath: string, options?: {
|
|
29
|
+
interval?: number;
|
|
30
|
+
transcribe?: boolean;
|
|
31
|
+
}): Promise<{
|
|
32
|
+
success: boolean;
|
|
33
|
+
name: string;
|
|
34
|
+
error?: string;
|
|
35
|
+
}>;
|
|
36
|
+
/**
|
|
37
|
+
* Remove a media item from the HQ
|
|
38
|
+
*/
|
|
39
|
+
export declare function removeMedia(hqPath: string, name: string): {
|
|
40
|
+
success: boolean;
|
|
41
|
+
error?: string;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* List all media items in the workspace
|
|
45
|
+
*/
|
|
46
|
+
export declare function listMedia(hqPath: string): MediaItem[];
|
|
47
|
+
/**
|
|
48
|
+
* Get details for a specific media item
|
|
49
|
+
*/
|
|
50
|
+
export declare function showMedia(hqPath: string, name: string): MediaItem | null;
|
|
51
|
+
/**
|
|
52
|
+
* Preprocess a media file: extract frames and generate transcript
|
|
53
|
+
*/
|
|
54
|
+
export declare function preprocessMedia(hqPath: string, name: string, options?: {
|
|
55
|
+
interval?: number;
|
|
56
|
+
transcribe?: boolean;
|
|
57
|
+
}): Promise<{
|
|
58
|
+
success: boolean;
|
|
59
|
+
error?: string;
|
|
60
|
+
}>;
|
|
61
|
+
export interface MediaInfo {
|
|
62
|
+
name: string;
|
|
63
|
+
mediaType: 'video' | 'audio';
|
|
64
|
+
status: 'pending' | 'processing' | 'ready' | 'error';
|
|
65
|
+
frameCount: number;
|
|
66
|
+
hasTranscript: boolean;
|
|
67
|
+
durationSeconds: number | null;
|
|
68
|
+
resolution: string | null;
|
|
69
|
+
addedAt: string;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Get workspace media information
|
|
73
|
+
*/
|
|
74
|
+
export declare function getWorkspaceMediaInfo(): {
|
|
75
|
+
hqPath: string;
|
|
76
|
+
mediaPath: string;
|
|
77
|
+
media: MediaInfo[];
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Copy preprocessed media assets into an agent's workspace directory.
|
|
81
|
+
* Only copies lightweight preprocessed assets (frames/, transcript.md, manifest.json).
|
|
82
|
+
* Does NOT copy the raw source video (too large).
|
|
83
|
+
*
|
|
84
|
+
* @param hqPath - The HQ root path
|
|
85
|
+
* @param agentDir - The agent's working directory (e.g., agents/temp/thick-spiegel)
|
|
86
|
+
*/
|
|
87
|
+
export declare function copyMediaToAgentWorkspace(hqPath: string, agentDir: string): void;
|
|
88
|
+
/**
|
|
89
|
+
* Format duration in seconds to human-readable string
|
|
90
|
+
*/
|
|
91
|
+
export declare function formatDuration(seconds: number): string;
|
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Media Library
|
|
3
|
+
*
|
|
4
|
+
* Manages media files (videos, audio) in HQ workspaces.
|
|
5
|
+
* Preprocesses media into frames + transcripts for agent consumption.
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from 'node:fs';
|
|
8
|
+
import * as path from 'node:path';
|
|
9
|
+
import { execSync } from 'node:child_process';
|
|
10
|
+
import chalk from 'chalk';
|
|
11
|
+
import { styles } from '../styles.js';
|
|
12
|
+
import { findHQRoot } from '../workspace.js';
|
|
13
|
+
import { addMediaItemToDatabase, updateMediaItemStatus, getWorkspaceMediaItems, getMediaItem, removeMediaItemFromDatabase, } from '../database/index.js';
|
|
14
|
+
// =============================================================================
|
|
15
|
+
// Dependency Detection
|
|
16
|
+
// =============================================================================
|
|
17
|
+
/**
|
|
18
|
+
* Check if ffmpeg is installed
|
|
19
|
+
*/
|
|
20
|
+
export function isFfmpegInstalled() {
|
|
21
|
+
try {
|
|
22
|
+
execSync('ffmpeg -version', { stdio: 'pipe' });
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Check if whisper (or whisper.cpp) is available for transcription
|
|
31
|
+
*/
|
|
32
|
+
export function isWhisperInstalled() {
|
|
33
|
+
try {
|
|
34
|
+
execSync('whisper --help', { stdio: 'pipe' });
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
try {
|
|
39
|
+
execSync('whisper-cpp --help', { stdio: 'pipe' });
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Get the whisper command name (whisper or whisper-cpp)
|
|
49
|
+
*/
|
|
50
|
+
function getWhisperCommand() {
|
|
51
|
+
try {
|
|
52
|
+
execSync('whisper --help', { stdio: 'pipe' });
|
|
53
|
+
return 'whisper';
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
try {
|
|
57
|
+
execSync('whisper-cpp --help', { stdio: 'pipe' });
|
|
58
|
+
return 'whisper-cpp';
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Probe a media file to get its metadata using ffprobe
|
|
67
|
+
*/
|
|
68
|
+
function probeMedia(filePath) {
|
|
69
|
+
const result = {
|
|
70
|
+
duration: null,
|
|
71
|
+
width: null,
|
|
72
|
+
height: null,
|
|
73
|
+
hasAudio: false,
|
|
74
|
+
hasVideo: false,
|
|
75
|
+
};
|
|
76
|
+
try {
|
|
77
|
+
const output = execSync(`ffprobe -v quiet -print_format json -show_format -show_streams "${filePath}"`, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
|
|
78
|
+
const data = JSON.parse(output);
|
|
79
|
+
if (data.format?.duration) {
|
|
80
|
+
result.duration = parseFloat(data.format.duration);
|
|
81
|
+
}
|
|
82
|
+
for (const stream of data.streams || []) {
|
|
83
|
+
if (stream.codec_type === 'video') {
|
|
84
|
+
result.hasVideo = true;
|
|
85
|
+
result.width = stream.width;
|
|
86
|
+
result.height = stream.height;
|
|
87
|
+
}
|
|
88
|
+
if (stream.codec_type === 'audio') {
|
|
89
|
+
result.hasAudio = true;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// ffprobe failed - file might not be a valid media file
|
|
95
|
+
}
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
// =============================================================================
|
|
99
|
+
// Media CRUD Operations
|
|
100
|
+
// =============================================================================
|
|
101
|
+
/**
|
|
102
|
+
* Supported media file extensions
|
|
103
|
+
*/
|
|
104
|
+
const VIDEO_EXTENSIONS = new Set(['.mp4', '.mkv', '.avi', '.mov', '.webm', '.flv', '.wmv']);
|
|
105
|
+
const AUDIO_EXTENSIONS = new Set(['.mp3', '.wav', '.flac', '.aac', '.ogg', '.m4a', '.wma']);
|
|
106
|
+
/**
|
|
107
|
+
* Detect if a file is video or audio based on extension
|
|
108
|
+
*/
|
|
109
|
+
export function detectMediaType(filePath) {
|
|
110
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
111
|
+
if (VIDEO_EXTENSIONS.has(ext))
|
|
112
|
+
return 'video';
|
|
113
|
+
if (AUDIO_EXTENSIONS.has(ext))
|
|
114
|
+
return 'audio';
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Get the media directory path within the HQ
|
|
119
|
+
*/
|
|
120
|
+
export function getMediaDir(hqPath) {
|
|
121
|
+
return path.join(hqPath, 'media');
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Add a media file to the HQ
|
|
125
|
+
*/
|
|
126
|
+
export async function addMedia(hqPath, sourcePath, options = {}) {
|
|
127
|
+
const resolvedSource = path.resolve(sourcePath);
|
|
128
|
+
if (!fs.existsSync(resolvedSource)) {
|
|
129
|
+
return { success: false, name: '', error: `File not found: ${resolvedSource}` };
|
|
130
|
+
}
|
|
131
|
+
const mediaType = detectMediaType(resolvedSource);
|
|
132
|
+
if (!mediaType) {
|
|
133
|
+
return { success: false, name: '', error: `Unsupported file type: ${path.extname(resolvedSource)}` };
|
|
134
|
+
}
|
|
135
|
+
if (!isFfmpegInstalled()) {
|
|
136
|
+
return { success: false, name: '', error: 'ffmpeg is not installed. Install it with: brew install ffmpeg' };
|
|
137
|
+
}
|
|
138
|
+
const baseName = path.basename(resolvedSource, path.extname(resolvedSource));
|
|
139
|
+
// Sanitize name: lowercase, replace spaces/special chars with hyphens
|
|
140
|
+
const name = baseName.toLowerCase().replace(/[^a-z0-9-_]/g, '-').replace(/-+/g, '-');
|
|
141
|
+
const mediaDir = getMediaDir(hqPath);
|
|
142
|
+
const itemDir = path.join(mediaDir, name);
|
|
143
|
+
if (fs.existsSync(itemDir)) {
|
|
144
|
+
return { success: false, name, error: `Media "${name}" already exists. Remove it first or use a different name.` };
|
|
145
|
+
}
|
|
146
|
+
// Create directory structure
|
|
147
|
+
fs.mkdirSync(itemDir, { recursive: true });
|
|
148
|
+
fs.mkdirSync(path.join(itemDir, 'frames'), { recursive: true });
|
|
149
|
+
// Copy source file
|
|
150
|
+
const ext = path.extname(resolvedSource);
|
|
151
|
+
const destFile = path.join(itemDir, `source${ext}`);
|
|
152
|
+
console.log(styles.muted(`Copying ${resolvedSource} to media/${name}/...`));
|
|
153
|
+
fs.copyFileSync(resolvedSource, destFile);
|
|
154
|
+
// Add to database
|
|
155
|
+
addMediaItemToDatabase(hqPath, {
|
|
156
|
+
name,
|
|
157
|
+
path: `media/${name}`,
|
|
158
|
+
source_path: resolvedSource,
|
|
159
|
+
media_type: mediaType,
|
|
160
|
+
frame_interval: options.interval || 30,
|
|
161
|
+
});
|
|
162
|
+
// Run preprocessing
|
|
163
|
+
console.log(styles.muted('Starting preprocessing...'));
|
|
164
|
+
const preprocessResult = await preprocessMedia(hqPath, name, {
|
|
165
|
+
interval: options.interval || 30,
|
|
166
|
+
transcribe: options.transcribe ?? true,
|
|
167
|
+
});
|
|
168
|
+
if (!preprocessResult.success) {
|
|
169
|
+
console.log(chalk.yellow(`Warning: Preprocessing had issues: ${preprocessResult.error}`));
|
|
170
|
+
console.log(chalk.yellow('You can retry with: prlt media preprocess ' + name));
|
|
171
|
+
}
|
|
172
|
+
return { success: true, name };
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Remove a media item from the HQ
|
|
176
|
+
*/
|
|
177
|
+
export function removeMedia(hqPath, name) {
|
|
178
|
+
const itemDir = path.join(getMediaDir(hqPath), name);
|
|
179
|
+
// Remove from file system
|
|
180
|
+
if (fs.existsSync(itemDir)) {
|
|
181
|
+
fs.rmSync(itemDir, { recursive: true, force: true });
|
|
182
|
+
}
|
|
183
|
+
// Remove from database
|
|
184
|
+
removeMediaItemFromDatabase(hqPath, name);
|
|
185
|
+
return { success: true };
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* List all media items in the workspace
|
|
189
|
+
*/
|
|
190
|
+
export function listMedia(hqPath) {
|
|
191
|
+
return getWorkspaceMediaItems(hqPath);
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Get details for a specific media item
|
|
195
|
+
*/
|
|
196
|
+
export function showMedia(hqPath, name) {
|
|
197
|
+
return getMediaItem(hqPath, name);
|
|
198
|
+
}
|
|
199
|
+
// =============================================================================
|
|
200
|
+
// Preprocessing Pipeline
|
|
201
|
+
// =============================================================================
|
|
202
|
+
/**
|
|
203
|
+
* Format seconds into a timestamp string (e.g., "01m30s")
|
|
204
|
+
*/
|
|
205
|
+
function formatTimestamp(seconds) {
|
|
206
|
+
const m = Math.floor(seconds / 60);
|
|
207
|
+
const s = Math.floor(seconds % 60);
|
|
208
|
+
return `${String(m).padStart(2, '0')}m${String(s).padStart(2, '0')}s`;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Preprocess a media file: extract frames and generate transcript
|
|
212
|
+
*/
|
|
213
|
+
export async function preprocessMedia(hqPath, name, options = {}) {
|
|
214
|
+
const interval = options.interval || 30;
|
|
215
|
+
const transcribe = options.transcribe ?? true;
|
|
216
|
+
const item = getMediaItem(hqPath, name);
|
|
217
|
+
if (!item) {
|
|
218
|
+
return { success: false, error: `Media "${name}" not found` };
|
|
219
|
+
}
|
|
220
|
+
const itemDir = path.join(getMediaDir(hqPath), name);
|
|
221
|
+
if (!fs.existsSync(itemDir)) {
|
|
222
|
+
return { success: false, error: `Media directory not found: ${itemDir}` };
|
|
223
|
+
}
|
|
224
|
+
// Find source file
|
|
225
|
+
const sourceFile = findSourceFile(itemDir);
|
|
226
|
+
if (!sourceFile) {
|
|
227
|
+
return { success: false, error: 'Source media file not found in media directory' };
|
|
228
|
+
}
|
|
229
|
+
// Mark as processing
|
|
230
|
+
updateMediaItemStatus(hqPath, name, { status: 'processing' });
|
|
231
|
+
// Probe media info
|
|
232
|
+
const probe = probeMedia(sourceFile);
|
|
233
|
+
const resolution = probe.width && probe.height ? `${probe.width}x${probe.height}` : undefined;
|
|
234
|
+
// Clean previous frames
|
|
235
|
+
const framesDir = path.join(itemDir, 'frames');
|
|
236
|
+
if (fs.existsSync(framesDir)) {
|
|
237
|
+
fs.rmSync(framesDir, { recursive: true });
|
|
238
|
+
}
|
|
239
|
+
fs.mkdirSync(framesDir, { recursive: true });
|
|
240
|
+
let frameCount = 0;
|
|
241
|
+
let hasTranscript = false;
|
|
242
|
+
const errors = [];
|
|
243
|
+
// Extract frames (only for video)
|
|
244
|
+
if (probe.hasVideo) {
|
|
245
|
+
try {
|
|
246
|
+
console.log(styles.muted(`Extracting frames every ${interval}s...`));
|
|
247
|
+
// Use ffmpeg to extract frames at the specified interval
|
|
248
|
+
// Output as frame_NNNN_XXmYYs.jpg for easy reference
|
|
249
|
+
execSync(`ffmpeg -i "${sourceFile}" -vf "fps=1/${interval}" -q:v 2 "${path.join(framesDir, 'frame_%04d.jpg')}" -y`, { stdio: 'pipe' });
|
|
250
|
+
// Rename frames with timestamps
|
|
251
|
+
const frameFiles = fs.readdirSync(framesDir).filter(f => f.endsWith('.jpg')).sort();
|
|
252
|
+
for (let i = 0; i < frameFiles.length; i++) {
|
|
253
|
+
const oldPath = path.join(framesDir, frameFiles[i]);
|
|
254
|
+
const timestamp = formatTimestamp(i * interval);
|
|
255
|
+
const newName = `frame_${String(i).padStart(4, '0')}_${timestamp}.jpg`;
|
|
256
|
+
const newPath = path.join(framesDir, newName);
|
|
257
|
+
fs.renameSync(oldPath, newPath);
|
|
258
|
+
}
|
|
259
|
+
frameCount = frameFiles.length;
|
|
260
|
+
console.log(styles.muted(`Extracted ${frameCount} frames`));
|
|
261
|
+
}
|
|
262
|
+
catch (error) {
|
|
263
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
264
|
+
errors.push(`Frame extraction failed: ${msg}`);
|
|
265
|
+
console.log(chalk.yellow(`Warning: Frame extraction failed: ${msg}`));
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
// Generate transcript
|
|
269
|
+
if (transcribe && probe.hasAudio) {
|
|
270
|
+
const whisperCmd = getWhisperCommand();
|
|
271
|
+
if (whisperCmd) {
|
|
272
|
+
try {
|
|
273
|
+
console.log(styles.muted('Generating transcript...'));
|
|
274
|
+
// Extract audio to WAV for whisper compatibility
|
|
275
|
+
const wavPath = path.join(itemDir, 'audio.wav');
|
|
276
|
+
execSync(`ffmpeg -i "${sourceFile}" -ar 16000 -ac 1 -c:a pcm_s16le "${wavPath}" -y`, { stdio: 'pipe' });
|
|
277
|
+
// Run whisper
|
|
278
|
+
execSync(`${whisperCmd} "${wavPath}" --output_format txt,json --output_dir "${itemDir}"`, { stdio: 'pipe', timeout: 600000 } // 10 min timeout
|
|
279
|
+
);
|
|
280
|
+
// Clean up WAV
|
|
281
|
+
if (fs.existsSync(wavPath)) {
|
|
282
|
+
fs.unlinkSync(wavPath);
|
|
283
|
+
}
|
|
284
|
+
// Look for generated transcript files and rename them
|
|
285
|
+
const txtFiles = fs.readdirSync(itemDir).filter(f => f.endsWith('.txt') && f !== 'transcript.md');
|
|
286
|
+
const jsonFiles = fs.readdirSync(itemDir).filter(f => f.endsWith('.json') && f !== 'manifest.json');
|
|
287
|
+
if (txtFiles.length > 0) {
|
|
288
|
+
const txtContent = fs.readFileSync(path.join(itemDir, txtFiles[0]), 'utf-8');
|
|
289
|
+
fs.writeFileSync(path.join(itemDir, 'transcript.md'), `# Transcript: ${name}\n\n${txtContent}`);
|
|
290
|
+
// Clean up original
|
|
291
|
+
fs.unlinkSync(path.join(itemDir, txtFiles[0]));
|
|
292
|
+
hasTranscript = true;
|
|
293
|
+
}
|
|
294
|
+
if (jsonFiles.length > 0) {
|
|
295
|
+
fs.renameSync(path.join(itemDir, jsonFiles[0]), path.join(itemDir, 'transcript.json'));
|
|
296
|
+
}
|
|
297
|
+
console.log(styles.muted('Transcript generated'));
|
|
298
|
+
}
|
|
299
|
+
catch (error) {
|
|
300
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
301
|
+
errors.push(`Transcription failed: ${msg}`);
|
|
302
|
+
console.log(chalk.yellow(`Warning: Transcription failed: ${msg}`));
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
console.log(chalk.yellow('Whisper not installed. Skipping transcription.'));
|
|
307
|
+
console.log(chalk.yellow('Install with: pip install openai-whisper'));
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
else if (transcribe && !probe.hasAudio) {
|
|
311
|
+
console.log(styles.muted('No audio stream found. Skipping transcription.'));
|
|
312
|
+
}
|
|
313
|
+
// Generate manifest
|
|
314
|
+
const manifest = generateManifest(name, itemDir, probe, frameCount, hasTranscript, interval);
|
|
315
|
+
fs.writeFileSync(path.join(itemDir, 'manifest.json'), JSON.stringify(manifest, null, 2));
|
|
316
|
+
// Update database
|
|
317
|
+
const status = errors.length > 0 ? 'error' : 'ready';
|
|
318
|
+
updateMediaItemStatus(hqPath, name, {
|
|
319
|
+
status,
|
|
320
|
+
duration_seconds: probe.duration ?? undefined,
|
|
321
|
+
resolution,
|
|
322
|
+
frame_count: frameCount,
|
|
323
|
+
has_transcript: hasTranscript,
|
|
324
|
+
error_message: errors.length > 0 ? errors.join('; ') : undefined,
|
|
325
|
+
});
|
|
326
|
+
if (errors.length > 0) {
|
|
327
|
+
return { success: false, error: errors.join('; ') };
|
|
328
|
+
}
|
|
329
|
+
return { success: true };
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Generate a manifest.json with metadata about the preprocessed media
|
|
333
|
+
*/
|
|
334
|
+
function generateManifest(name, itemDir, probe, frameCount, hasTranscript, interval) {
|
|
335
|
+
const framesDir = path.join(itemDir, 'frames');
|
|
336
|
+
const frameFiles = fs.existsSync(framesDir)
|
|
337
|
+
? fs.readdirSync(framesDir).filter(f => f.endsWith('.jpg')).sort()
|
|
338
|
+
: [];
|
|
339
|
+
return {
|
|
340
|
+
name,
|
|
341
|
+
media_type: probe.hasVideo ? 'video' : 'audio',
|
|
342
|
+
duration_seconds: probe.duration,
|
|
343
|
+
resolution: probe.width && probe.height ? `${probe.width}x${probe.height}` : null,
|
|
344
|
+
frame_interval_seconds: interval,
|
|
345
|
+
frame_count: frameCount,
|
|
346
|
+
has_transcript: hasTranscript,
|
|
347
|
+
frames: frameFiles.map((filename, i) => ({
|
|
348
|
+
filename,
|
|
349
|
+
timestamp_seconds: i * interval,
|
|
350
|
+
timestamp_display: formatTimestamp(i * interval),
|
|
351
|
+
})),
|
|
352
|
+
transcript_file: hasTranscript ? 'transcript.md' : null,
|
|
353
|
+
transcript_json_file: fs.existsSync(path.join(itemDir, 'transcript.json')) ? 'transcript.json' : null,
|
|
354
|
+
processed_at: new Date().toISOString(),
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Get workspace media information
|
|
359
|
+
*/
|
|
360
|
+
export function getWorkspaceMediaInfo() {
|
|
361
|
+
const hqPath = findHQRoot();
|
|
362
|
+
if (!hqPath) {
|
|
363
|
+
throw new Error('Not in an HQ directory. Run "prlt new" first.');
|
|
364
|
+
}
|
|
365
|
+
const mediaPath = getMediaDir(hqPath);
|
|
366
|
+
const items = getWorkspaceMediaItems(hqPath);
|
|
367
|
+
const media = items.map(item => ({
|
|
368
|
+
name: item.name,
|
|
369
|
+
mediaType: item.media_type,
|
|
370
|
+
status: item.status,
|
|
371
|
+
frameCount: item.frame_count,
|
|
372
|
+
hasTranscript: item.has_transcript,
|
|
373
|
+
durationSeconds: item.duration_seconds,
|
|
374
|
+
resolution: item.resolution,
|
|
375
|
+
addedAt: item.added_at,
|
|
376
|
+
}));
|
|
377
|
+
return { hqPath, mediaPath, media };
|
|
378
|
+
}
|
|
379
|
+
// =============================================================================
|
|
380
|
+
// Agent Workspace Mounting (TKT-077)
|
|
381
|
+
// =============================================================================
|
|
382
|
+
/**
|
|
383
|
+
* Copy preprocessed media assets into an agent's workspace directory.
|
|
384
|
+
* Only copies lightweight preprocessed assets (frames/, transcript.md, manifest.json).
|
|
385
|
+
* Does NOT copy the raw source video (too large).
|
|
386
|
+
*
|
|
387
|
+
* @param hqPath - The HQ root path
|
|
388
|
+
* @param agentDir - The agent's working directory (e.g., agents/temp/thick-spiegel)
|
|
389
|
+
*/
|
|
390
|
+
export function copyMediaToAgentWorkspace(hqPath, agentDir) {
|
|
391
|
+
const mediaDir = getMediaDir(hqPath);
|
|
392
|
+
if (!fs.existsSync(mediaDir)) {
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
const items = getWorkspaceMediaItems(hqPath);
|
|
396
|
+
const readyItems = items.filter(item => item.status === 'ready');
|
|
397
|
+
if (readyItems.length === 0) {
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
const agentMediaDir = path.join(agentDir, 'media');
|
|
401
|
+
fs.mkdirSync(agentMediaDir, { recursive: true });
|
|
402
|
+
for (const item of readyItems) {
|
|
403
|
+
const sourceItemDir = path.join(hqPath, item.path);
|
|
404
|
+
const destItemDir = path.join(agentMediaDir, item.name);
|
|
405
|
+
if (!fs.existsSync(sourceItemDir)) {
|
|
406
|
+
continue;
|
|
407
|
+
}
|
|
408
|
+
fs.mkdirSync(destItemDir, { recursive: true });
|
|
409
|
+
// Copy manifest.json
|
|
410
|
+
const manifestSrc = path.join(sourceItemDir, 'manifest.json');
|
|
411
|
+
if (fs.existsSync(manifestSrc)) {
|
|
412
|
+
fs.copyFileSync(manifestSrc, path.join(destItemDir, 'manifest.json'));
|
|
413
|
+
}
|
|
414
|
+
// Copy transcript.md
|
|
415
|
+
const transcriptSrc = path.join(sourceItemDir, 'transcript.md');
|
|
416
|
+
if (fs.existsSync(transcriptSrc)) {
|
|
417
|
+
fs.copyFileSync(transcriptSrc, path.join(destItemDir, 'transcript.md'));
|
|
418
|
+
}
|
|
419
|
+
// Copy transcript.json
|
|
420
|
+
const transcriptJsonSrc = path.join(sourceItemDir, 'transcript.json');
|
|
421
|
+
if (fs.existsSync(transcriptJsonSrc)) {
|
|
422
|
+
fs.copyFileSync(transcriptJsonSrc, path.join(destItemDir, 'transcript.json'));
|
|
423
|
+
}
|
|
424
|
+
// Copy frames directory
|
|
425
|
+
const framesSrc = path.join(sourceItemDir, 'frames');
|
|
426
|
+
if (fs.existsSync(framesSrc)) {
|
|
427
|
+
const framesDest = path.join(destItemDir, 'frames');
|
|
428
|
+
fs.mkdirSync(framesDest, { recursive: true });
|
|
429
|
+
const frameFiles = fs.readdirSync(framesSrc);
|
|
430
|
+
for (const file of frameFiles) {
|
|
431
|
+
fs.copyFileSync(path.join(framesSrc, file), path.join(framesDest, file));
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
// =============================================================================
|
|
437
|
+
// Utility
|
|
438
|
+
// =============================================================================
|
|
439
|
+
/**
|
|
440
|
+
* Find the source media file in a media item directory
|
|
441
|
+
*/
|
|
442
|
+
function findSourceFile(itemDir) {
|
|
443
|
+
const allExtensions = [...VIDEO_EXTENSIONS, ...AUDIO_EXTENSIONS];
|
|
444
|
+
for (const ext of allExtensions) {
|
|
445
|
+
const sourceFile = path.join(itemDir, `source${ext}`);
|
|
446
|
+
if (fs.existsSync(sourceFile)) {
|
|
447
|
+
return sourceFile;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
// Also check for files with 'source' prefix or just any media file
|
|
451
|
+
const files = fs.readdirSync(itemDir);
|
|
452
|
+
for (const file of files) {
|
|
453
|
+
const ext = path.extname(file).toLowerCase();
|
|
454
|
+
if (allExtensions.includes(ext)) {
|
|
455
|
+
return path.join(itemDir, file);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return null;
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* Format duration in seconds to human-readable string
|
|
462
|
+
*/
|
|
463
|
+
export function formatDuration(seconds) {
|
|
464
|
+
const h = Math.floor(seconds / 3600);
|
|
465
|
+
const m = Math.floor((seconds % 3600) / 60);
|
|
466
|
+
const s = Math.floor(seconds % 60);
|
|
467
|
+
if (h > 0) {
|
|
468
|
+
return `${h}h ${m}m ${s}s`;
|
|
469
|
+
}
|
|
470
|
+
if (m > 0) {
|
|
471
|
+
return `${m}m ${s}s`;
|
|
472
|
+
}
|
|
473
|
+
return `${s}s`;
|
|
474
|
+
}
|
|
475
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/media/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface DetectedTool {
|
|
2
|
+
name: string;
|
|
3
|
+
command: string;
|
|
4
|
+
path: string;
|
|
5
|
+
displayName: string;
|
|
6
|
+
}
|
|
7
|
+
export interface ToolDetectionResult {
|
|
8
|
+
tools: DetectedTool[];
|
|
9
|
+
hasClaudeCode: boolean;
|
|
10
|
+
hasCodex: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Detect which AI tools are installed on the system.
|
|
14
|
+
*/
|
|
15
|
+
export declare function detectAITools(): ToolDetectionResult;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
const TOOLS_TO_DETECT = [
|
|
3
|
+
{ name: 'claude-code', command: 'claude', displayName: 'Claude Code' },
|
|
4
|
+
{ name: 'codex', command: 'codex', displayName: 'Codex' },
|
|
5
|
+
];
|
|
6
|
+
/**
|
|
7
|
+
* Check if a command is available on the system PATH.
|
|
8
|
+
* Returns the resolved path or null if not found.
|
|
9
|
+
*/
|
|
10
|
+
function whichCommand(command) {
|
|
11
|
+
try {
|
|
12
|
+
const result = execSync(`which ${command}`, {
|
|
13
|
+
encoding: 'utf-8',
|
|
14
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
15
|
+
}).trim();
|
|
16
|
+
return result || null;
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Detect which AI tools are installed on the system.
|
|
24
|
+
*/
|
|
25
|
+
export function detectAITools() {
|
|
26
|
+
const tools = [];
|
|
27
|
+
for (const tool of TOOLS_TO_DETECT) {
|
|
28
|
+
const toolPath = whichCommand(tool.command);
|
|
29
|
+
if (toolPath) {
|
|
30
|
+
tools.push({
|
|
31
|
+
name: tool.name,
|
|
32
|
+
command: tool.command,
|
|
33
|
+
path: toolPath,
|
|
34
|
+
displayName: tool.displayName,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
tools,
|
|
40
|
+
hasClaudeCode: tools.some(t => t.name === 'claude-code'),
|
|
41
|
+
hasCodex: tools.some(t => t.name === 'codex'),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=detect-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect-tools.js","sourceRoot":"","sources":["../../../src/lib/onboarding/detect-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAe9C,MAAM,eAAe,GAAG;IACtB,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,EAAE;IACtE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE;CACjD,CAAC;AAEX;;;GAGG;AACH,SAAS,YAAY,CAAC,OAAe;IACnC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,SAAS,OAAO,EAAE,EAAE;YAC1C,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;SAChC,CAAC,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,MAAM,IAAI,IAAI,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,KAAK,GAAmB,EAAE,CAAC;IAEjC,KAAK,MAAM,IAAI,IAAI,eAAe,EAAE,CAAC;QACnC,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC5C,IAAI,QAAQ,EAAE,CAAC;YACb,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,IAAI,CAAC,WAAW;aAC9B,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO;QACL,KAAK;QACL,aAAa,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,aAAa,CAAC;QACxD,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC;KAC9C,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/onboarding/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAA+C,MAAM,mBAAmB,CAAC;AAC/F,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,eAAe,GAEhB,MAAM,aAAa,CAAC"}
|