@redaksjon/protokoll 0.0.10 → 0.0.12
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/.nvmrc +1 -2
- package/README.md +9 -9
- package/dist/agentic/tools/lookup-project.js +1 -1
- package/dist/agentic/tools/lookup-project.js.map +1 -1
- package/dist/constants.js +2 -2
- package/dist/constants.js.map +1 -1
- package/dist/context/discovery.js +1 -1
- package/dist/context/discovery.js.map +1 -1
- package/dist/context/storage.js +1 -1
- package/dist/context/storage.js.map +1 -1
- package/dist/output/manager.js +1 -1
- package/dist/output/manager.js.map +1 -1
- package/dist/phases/complete.js +1 -1
- package/dist/phases/complete.js.map +1 -1
- package/dist/phases/locate.js +1 -1
- package/dist/phases/locate.js.map +1 -1
- package/dist/pipeline/orchestrator.js +1 -1
- package/dist/pipeline/orchestrator.js.map +1 -1
- package/dist/routing/router.js +2 -2
- package/dist/routing/router.js.map +1 -1
- package/dist/util/media.js +1 -1
- package/dist/util/media.js.map +1 -1
- package/dist/util/storage.js +3 -3
- package/dist/util/storage.js.map +1 -1
- package/eslint.config.mjs +1 -1
- package/package.json +3 -5
- package/scripts/copy-assets.mjs +47 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/vite.config.ts +6 -13
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orchestrator.js","sources":["../../src/pipeline/orchestrator.ts"],"sourcesContent":["/**\n * Pipeline Orchestrator\n *\n * Orchestrates the intelligent transcription pipeline, coordinating\n * all the modules: context, routing, transcription, reasoning,\n * agentic tools, interactive mode, output management, and reflection.\n * \n * THIS IS THE MAIN PROCESSING FLOW - NOT DEAD CODE!\n */\n\nimport { PipelineConfig, PipelineInput, PipelineResult, PipelineState } from './types';\nimport * as Context from '../context';\nimport * as Routing from '../routing';\nimport * as Interactive from '../interactive';\nimport * as Output from '../output';\nimport * as Reflection from '../reflection';\nimport * as Transcription from '../transcription';\nimport * as Reasoning from '../reasoning';\nimport * as Agentic from '../agentic';\nimport * as CompletePhase from '../phases/complete';\nimport * as Logging from '../logging';\nimport * as Metadata from '../util/metadata';\n\nexport interface OrchestratorInstance {\n process(input: PipelineInput): Promise<PipelineResult>;\n}\n\nexport interface OrchestratorConfig extends PipelineConfig {\n outputDirectory: string;\n outputStructure: string;\n outputFilenameOptions: string[];\n maxAudioSize: number;\n tempDirectory: string;\n}\n\nexport const create = async (config: OrchestratorConfig): Promise<OrchestratorInstance> => {\n const logger = Logging.getLogger();\n const currentWorkingDir = globalThis.process.cwd();\n \n logger.debug('Initializing intelligent transcription pipeline...');\n \n // Initialize context system (async)\n const context = await Context.create({\n startingDir: config.contextDirectory || currentWorkingDir,\n });\n logger.debug('Context system initialized - ready to query entities via tools');\n \n // Initialize routing with config-based defaults\n const routingConfig: Routing.RoutingConfig = {\n default: {\n path: config.outputDirectory || '~/notes',\n structure: (config.outputStructure || 'month') as Routing.FilesystemStructure,\n filename_options: (config.outputFilenameOptions || ['date', 'time', 'subject']) as Routing.FilenameOption[],\n createDirectories: true,\n },\n projects: [],\n conflict_resolution: 'primary',\n };\n \n const routing = Routing.create(routingConfig, context);\n logger.debug('Routing system initialized');\n \n const interactive = Interactive.create(\n { enabled: config.interactive, defaultToSuggestion: true },\n context\n );\n \n const output = Output.create({\n intermediateDir: config.intermediateDir || './output/protokoll',\n keepIntermediates: config.keepIntermediates ?? true,\n timestampFormat: 'YYMMDD-HHmm',\n });\n logger.debug('Output manager initialized');\n \n const reflection = config.selfReflection \n ? Reflection.create({\n enabled: true,\n format: 'markdown',\n includeConversation: false,\n includeOutput: true,\n })\n : null;\n if (reflection) {\n logger.debug('Self-reflection system enabled');\n }\n \n // Initialize transcription service\n const transcription = Transcription.create({\n defaultModel: config.transcriptionModel as Transcription.TranscriptionModel,\n });\n logger.debug('Transcription service initialized with model: %s', config.transcriptionModel);\n \n // Initialize reasoning for agentic processing\n const reasoning = Reasoning.create({ model: config.model });\n logger.debug('Reasoning system initialized with model: %s', config.model);\n\n // Initialize complete phase for moving files to processed directory\n // Pass outputStructure so processed files use the same directory structure as output\n const complete = config.processedDirectory \n ? CompletePhase.create({\n processedDirectory: config.processedDirectory,\n outputStructure: config.outputStructure as CompletePhase.FilesystemStructure,\n dryRun: config.dryRun,\n })\n : null;\n if (complete) {\n logger.debug('Complete phase initialized with processed directory: %s', config.processedDirectory);\n }\n \n // Helper to extract a human-readable title from the output path\n const extractTitleFromPath = (outputPath: string): string | undefined => {\n const filename = outputPath.split('/').pop()?.replace('.md', '');\n if (!filename) return undefined;\n \n // Remove date prefix (e.g., \"27-0716-\" from \"27-0716-wagner-webhooks\")\n const withoutDate = filename.replace(/^\\d{2}-\\d{4}-/, '');\n if (!withoutDate) return undefined;\n \n // Convert kebab-case to Title Case\n return withoutDate\n .split('-')\n .map(word => word.charAt(0).toUpperCase() + word.slice(1))\n .join(' ');\n };\n\n const processInput = async (input: PipelineInput): Promise<PipelineResult> => {\n const startTime = Date.now();\n \n logger.info('Processing: %s (hash: %s)', input.audioFile, input.hash);\n \n // Initialize state\n const state: PipelineState = {\n input,\n startTime: new Date(),\n };\n \n // Start reflection collection if enabled\n if (reflection) {\n reflection.collector.start();\n }\n \n // Start interactive session if enabled\n if (config.interactive) {\n interactive.startSession();\n logger.debug('Interactive session started');\n }\n \n try {\n // Step 1: Check onboarding needs\n logger.debug('Checking onboarding state...');\n const onboardingState = interactive.checkNeedsOnboarding();\n if (onboardingState.needsOnboarding) {\n logger.debug('First-run detected - onboarding may be triggered');\n }\n \n // Step 2: Raw transcription using Transcription module\n logger.info('Transcribing audio...');\n const whisperStart = Date.now();\n \n const transcriptionResult = await transcription.transcribe(input.audioFile, {\n model: config.transcriptionModel as Transcription.TranscriptionModel,\n });\n state.rawTranscript = transcriptionResult.text;\n \n const whisperDuration = Date.now() - whisperStart;\n logger.info('Transcription: %d chars in %.1fs', \n state.rawTranscript.length, whisperDuration / 1000);\n \n if (reflection) {\n reflection.collector.recordWhisper(whisperDuration);\n }\n \n // Step 3: Route detection\n logger.debug('Determining routing destination...');\n const routingContext: Routing.RoutingContext = {\n transcriptText: state.rawTranscript || '',\n audioDate: input.creation,\n sourceFile: input.audioFile,\n hash: input.hash,\n };\n \n const routeResult = routing.route(routingContext);\n \n logger.debug('Routing decision: project=%s, confidence=%.2f', \n routeResult.projectId || 'default', routeResult.confidence);\n \n // Record routing decision in reflection\n if (reflection) {\n reflection.collector.recordRoutingDecision({\n projectId: routeResult.projectId,\n destination: routeResult.destination.path,\n confidence: routeResult.confidence,\n reasoning: routeResult.reasoning,\n signals: routeResult.signals.map(s => ({\n type: s.type,\n value: s.value,\n weight: s.weight,\n })),\n alternativesConsidered: routeResult.alternateMatches?.map(alt => ({\n projectId: alt.projectId,\n confidence: alt.confidence,\n whyNotChosen: `Lower confidence (${(alt.confidence * 100).toFixed(1)}%)`,\n })),\n });\n }\n \n // Build output path\n const outputPath = routing.buildOutputPath(routeResult, routingContext);\n logger.debug('Output path: %s', outputPath);\n \n // Step 4: Create output paths using Output module\n logger.debug('Setting up output directories...');\n const paths = output.createOutputPaths(\n input.audioFile,\n outputPath,\n input.hash,\n input.creation\n );\n \n await output.ensureDirectories(paths);\n \n // Write raw transcript to intermediate\n await output.writeIntermediate(paths, 'transcript', {\n text: state.rawTranscript,\n model: config.transcriptionModel,\n duration: whisperDuration,\n });\n \n // Step 5: Agentic enhancement using real executor\n logger.info('Enhancing with %s...', config.model);\n \n const agenticStart = Date.now();\n const toolContext: Agentic.ToolContext = {\n transcriptText: state.rawTranscript || '',\n audioDate: input.creation,\n sourceFile: input.audioFile,\n contextInstance: context,\n routingInstance: routing,\n interactiveMode: config.interactive,\n interactiveInstance: config.interactive ? interactive : undefined,\n };\n \n const executor = Agentic.create(reasoning, toolContext);\n const agenticResult = await executor.process(state.rawTranscript || '');\n \n state.enhancedText = agenticResult.enhancedText;\n const toolsUsed = agenticResult.toolsUsed;\n const agenticDuration = Date.now() - agenticStart;\n \n // Record tool calls in reflection\n if (reflection) {\n for (const tool of toolsUsed) {\n reflection.collector.recordToolCall(tool, agenticDuration / toolsUsed.length, true);\n }\n reflection.collector.recordCorrection(state.rawTranscript || '', state.enhancedText);\n // Record token usage from agentic result\n if (agenticResult.totalTokens) {\n reflection.collector.recordModelResponse(config.model, agenticResult.totalTokens);\n }\n // Record context changes (new projects, entities created)\n if (agenticResult.contextChanges) {\n for (const change of agenticResult.contextChanges) {\n reflection.collector.recordContextChange(change);\n }\n }\n }\n \n // Write agentic session to intermediate\n await output.writeIntermediate(paths, 'session', {\n iterations: agenticResult.iterations,\n toolsUsed: agenticResult.toolsUsed,\n state: agenticResult.state,\n });\n \n // Step 6: Write final output using Output module with metadata\n logger.debug('Writing final transcript...');\n if (state.enhancedText) {\n // Build metadata from routing decision and input\n const transcriptMetadata: Metadata.TranscriptMetadata = {\n title: extractTitleFromPath(paths.final),\n projectId: routeResult.projectId || undefined,\n project: routeResult.projectId || undefined,\n date: input.creation,\n routing: Metadata.createRoutingMetadata(routeResult),\n tags: Metadata.extractTagsFromSignals(routeResult.signals),\n confidence: routeResult.confidence,\n };\n \n await output.writeTranscript(paths, state.enhancedText, transcriptMetadata);\n }\n \n // Step 7: Generate reflection report\n logger.debug('Generating reflection report...');\n let reflectionReport: Reflection.ReflectionReport | undefined;\n if (reflection) {\n reflectionReport = reflection.generate(\n input.audioFile,\n paths.final,\n undefined,\n state.enhancedText\n );\n \n if (paths.intermediate.reflection) {\n await reflection.save(reflectionReport, paths.intermediate.reflection);\n }\n }\n \n // Step 8: End interactive session\n logger.debug('Finalizing session...');\n let session: Interactive.InteractiveSession | undefined;\n if (config.interactive) {\n session = interactive.endSession();\n logger.debug('Interactive session ended: %d clarifications', session.responses.length);\n \n // Save session if path available\n if (paths.intermediate.session) {\n await output.writeIntermediate(paths, 'session', session);\n }\n }\n \n // Step 9: Cleanup if needed\n if (!config.keepIntermediates && !config.debug) {\n await output.cleanIntermediates(paths);\n }\n\n // Step 10: Move audio file to processed directory\n let processedAudioPath: string | undefined;\n if (complete) {\n // Extract subject from output path for naming\n const subject = paths.final.split('/').pop()?.replace('.md', '') || undefined;\n processedAudioPath = await complete.complete(\n input.audioFile, \n input.hash, \n input.creation,\n subject\n );\n }\n \n const processingTime = Date.now() - startTime;\n \n // Compact summary output\n logger.info('Enhancement: %d iterations, %d tools, %.1fs', \n agenticResult.iterations, toolsUsed.length, agenticDuration / 1000);\n if (agenticResult.totalTokens) {\n logger.info('Tokens: %d total', agenticResult.totalTokens);\n }\n logger.info('Output: %s (%.1fs total)', paths.final, processingTime / 1000);\n \n return {\n outputPath: paths.final,\n enhancedText: state.enhancedText || '',\n rawTranscript: state.rawTranscript || '',\n routedProject: routeResult.projectId,\n routingConfidence: routeResult.confidence,\n processingTime,\n toolsUsed,\n correctionsApplied: agenticResult.state.resolvedEntities.size,\n processedAudioPath,\n reflection: reflectionReport,\n session,\n intermediatePaths: paths,\n };\n \n } catch (error) {\n logger.error('Pipeline error', { error });\n throw error;\n }\n };\n \n return { process: processInput };\n};\n"],"names":["create","config","logger","Logging","currentWorkingDir","globalThis","process","cwd","debug","context","Context","startingDir","contextDirectory","routingConfig","default","path","outputDirectory","structure","outputStructure","filename_options","outputFilenameOptions","createDirectories","projects","conflict_resolution","routing","Routing","interactive","Interactive","enabled","output","Output","intermediateDir","keepIntermediates","reflection","selfReflection","Reflection","transcription","Transcription","defaultModel","transcriptionModel","reasoning","Reasoning","model","complete","processedDirectory","CompletePhase","dryRun","extractTitleFromPath","outputPath","filename","split","pop","replace","undefined","withoutDate","map","word","charAt","toUpperCase","slice","join","processInput","input","startTime","Date","now","info","audioFile","hash","state","collector","start","startSession","onboardingState","checkNeedsOnboarding","needsOnboarding","whisperStart","transcriptionResult","transcribe","rawTranscript","text","whisperDuration","length","recordWhisper","routingContext","transcriptText","audioDate","creation","sourceFile","routeResult","route","projectId","confidence","recordRoutingDecision","destination","signals","s","type","value","weight","alternativesConsidered","alternateMatches","alt","whyNotChosen","toFixed","buildOutputPath","paths","createOutputPaths","ensureDirectories","writeIntermediate","duration","agenticStart","toolContext","contextInstance","routingInstance","interactiveMode","interactiveInstance","executor","Agentic","agenticResult","enhancedText","toolsUsed","agenticDuration","tool","recordToolCall","recordCorrection","totalTokens","recordModelResponse","contextChanges","change","recordContextChange","iterations","transcriptMetadata","title","final","project","date","Metadata","tags","writeTranscript","reflectionReport","generate","intermediate","save","session","endSession","responses","cleanIntermediates","processedAudioPath","subject","processingTime","routedProject","routingConfidence","correctionsApplied","resolvedEntities","size","intermediatePaths","error"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"orchestrator.js","sources":["../../src/pipeline/orchestrator.ts"],"sourcesContent":["/**\n * Pipeline Orchestrator\n *\n * Orchestrates the intelligent transcription pipeline, coordinating\n * all the modules: context, routing, transcription, reasoning,\n * agentic tools, interactive mode, output management, and reflection.\n * \n * THIS IS THE MAIN PROCESSING FLOW - NOT DEAD CODE!\n */\n\nimport { PipelineConfig, PipelineInput, PipelineResult, PipelineState } from './types';\nimport * as Context from '../context';\nimport * as Routing from '../routing';\nimport * as Interactive from '../interactive';\nimport * as Output from '../output';\nimport * as Reflection from '../reflection';\nimport * as Transcription from '../transcription';\nimport * as Reasoning from '../reasoning';\nimport * as Agentic from '../agentic';\nimport * as CompletePhase from '../phases/complete';\nimport * as Logging from '../logging';\nimport * as Metadata from '../util/metadata';\n\nexport interface OrchestratorInstance {\n process(input: PipelineInput): Promise<PipelineResult>;\n}\n\nexport interface OrchestratorConfig extends PipelineConfig {\n outputDirectory: string;\n outputStructure: string;\n outputFilenameOptions: string[];\n maxAudioSize: number;\n tempDirectory: string;\n}\n\nexport const create = async (config: OrchestratorConfig): Promise<OrchestratorInstance> => {\n const logger = Logging.getLogger();\n const currentWorkingDir = globalThis.process.cwd();\n \n logger.debug('Initializing intelligent transcription pipeline...');\n \n // Initialize context system (async)\n const context = await Context.create({\n startingDir: config.contextDirectory || currentWorkingDir,\n });\n logger.debug('Context system initialized - ready to query entities via tools');\n \n // Initialize routing with config-based defaults\n const routingConfig: Routing.RoutingConfig = {\n default: {\n path: config.outputDirectory || '~/notes',\n structure: (config.outputStructure || 'month') as Routing.FilesystemStructure,\n filename_options: (config.outputFilenameOptions || ['date', 'time', 'subject']) as Routing.FilenameOption[],\n createDirectories: true,\n },\n projects: [],\n conflict_resolution: 'primary',\n };\n \n const routing = Routing.create(routingConfig, context);\n logger.debug('Routing system initialized');\n \n const interactive = Interactive.create(\n { enabled: config.interactive, defaultToSuggestion: true },\n context\n );\n \n const output = Output.create({\n intermediateDir: config.intermediateDir || './output/protokoll',\n keepIntermediates: config.keepIntermediates ?? true,\n timestampFormat: 'YYMMDD-HHmm',\n });\n logger.debug('Output manager initialized');\n \n const reflection = config.selfReflection \n ? Reflection.create({\n enabled: true,\n format: 'markdown',\n includeConversation: false,\n includeOutput: true,\n })\n : null;\n if (reflection) {\n logger.debug('Self-reflection system enabled');\n }\n \n // Initialize transcription service\n const transcription = Transcription.create({\n defaultModel: config.transcriptionModel as Transcription.TranscriptionModel,\n });\n logger.debug('Transcription service initialized with model: %s', config.transcriptionModel);\n \n // Initialize reasoning for agentic processing\n const reasoning = Reasoning.create({ model: config.model });\n logger.debug('Reasoning system initialized with model: %s', config.model);\n\n // Initialize complete phase for moving files to processed directory\n // Pass outputStructure so processed files use the same directory structure as output\n const complete = config.processedDirectory \n ? CompletePhase.create({\n processedDirectory: config.processedDirectory,\n outputStructure: config.outputStructure as CompletePhase.FilesystemStructure,\n dryRun: config.dryRun,\n })\n : null;\n if (complete) {\n logger.debug('Complete phase initialized with processed directory: %s', config.processedDirectory);\n }\n \n // Helper to extract a human-readable title from the output path\n const extractTitleFromPath = (outputPath: string): string | undefined => {\n const filename = outputPath.split('/').pop()?.replace('.md', '');\n if (!filename) return undefined;\n \n // Remove date prefix (e.g., \"27-0716-\" from \"27-0716-meeting-notes\")\n const withoutDate = filename.replace(/^\\d{2}-\\d{4}-/, '');\n if (!withoutDate) return undefined;\n \n // Convert kebab-case to Title Case\n return withoutDate\n .split('-')\n .map(word => word.charAt(0).toUpperCase() + word.slice(1))\n .join(' ');\n };\n\n const processInput = async (input: PipelineInput): Promise<PipelineResult> => {\n const startTime = Date.now();\n \n logger.info('Processing: %s (hash: %s)', input.audioFile, input.hash);\n \n // Initialize state\n const state: PipelineState = {\n input,\n startTime: new Date(),\n };\n \n // Start reflection collection if enabled\n if (reflection) {\n reflection.collector.start();\n }\n \n // Start interactive session if enabled\n if (config.interactive) {\n interactive.startSession();\n logger.debug('Interactive session started');\n }\n \n try {\n // Step 1: Check onboarding needs\n logger.debug('Checking onboarding state...');\n const onboardingState = interactive.checkNeedsOnboarding();\n if (onboardingState.needsOnboarding) {\n logger.debug('First-run detected - onboarding may be triggered');\n }\n \n // Step 2: Raw transcription using Transcription module\n logger.info('Transcribing audio...');\n const whisperStart = Date.now();\n \n const transcriptionResult = await transcription.transcribe(input.audioFile, {\n model: config.transcriptionModel as Transcription.TranscriptionModel,\n });\n state.rawTranscript = transcriptionResult.text;\n \n const whisperDuration = Date.now() - whisperStart;\n logger.info('Transcription: %d chars in %.1fs', \n state.rawTranscript.length, whisperDuration / 1000);\n \n if (reflection) {\n reflection.collector.recordWhisper(whisperDuration);\n }\n \n // Step 3: Route detection\n logger.debug('Determining routing destination...');\n const routingContext: Routing.RoutingContext = {\n transcriptText: state.rawTranscript || '',\n audioDate: input.creation,\n sourceFile: input.audioFile,\n hash: input.hash,\n };\n \n const routeResult = routing.route(routingContext);\n \n logger.debug('Routing decision: project=%s, confidence=%.2f', \n routeResult.projectId || 'default', routeResult.confidence);\n \n // Record routing decision in reflection\n if (reflection) {\n reflection.collector.recordRoutingDecision({\n projectId: routeResult.projectId,\n destination: routeResult.destination.path,\n confidence: routeResult.confidence,\n reasoning: routeResult.reasoning,\n signals: routeResult.signals.map(s => ({\n type: s.type,\n value: s.value,\n weight: s.weight,\n })),\n alternativesConsidered: routeResult.alternateMatches?.map(alt => ({\n projectId: alt.projectId,\n confidence: alt.confidence,\n whyNotChosen: `Lower confidence (${(alt.confidence * 100).toFixed(1)}%)`,\n })),\n });\n }\n \n // Build output path\n const outputPath = routing.buildOutputPath(routeResult, routingContext);\n logger.debug('Output path: %s', outputPath);\n \n // Step 4: Create output paths using Output module\n logger.debug('Setting up output directories...');\n const paths = output.createOutputPaths(\n input.audioFile,\n outputPath,\n input.hash,\n input.creation\n );\n \n await output.ensureDirectories(paths);\n \n // Write raw transcript to intermediate\n await output.writeIntermediate(paths, 'transcript', {\n text: state.rawTranscript,\n model: config.transcriptionModel,\n duration: whisperDuration,\n });\n \n // Step 5: Agentic enhancement using real executor\n logger.info('Enhancing with %s...', config.model);\n \n const agenticStart = Date.now();\n const toolContext: Agentic.ToolContext = {\n transcriptText: state.rawTranscript || '',\n audioDate: input.creation,\n sourceFile: input.audioFile,\n contextInstance: context,\n routingInstance: routing,\n interactiveMode: config.interactive,\n interactiveInstance: config.interactive ? interactive : undefined,\n };\n \n const executor = Agentic.create(reasoning, toolContext);\n const agenticResult = await executor.process(state.rawTranscript || '');\n \n state.enhancedText = agenticResult.enhancedText;\n const toolsUsed = agenticResult.toolsUsed;\n const agenticDuration = Date.now() - agenticStart;\n \n // Record tool calls in reflection\n if (reflection) {\n for (const tool of toolsUsed) {\n reflection.collector.recordToolCall(tool, agenticDuration / toolsUsed.length, true);\n }\n reflection.collector.recordCorrection(state.rawTranscript || '', state.enhancedText);\n // Record token usage from agentic result\n if (agenticResult.totalTokens) {\n reflection.collector.recordModelResponse(config.model, agenticResult.totalTokens);\n }\n // Record context changes (new projects, entities created)\n if (agenticResult.contextChanges) {\n for (const change of agenticResult.contextChanges) {\n reflection.collector.recordContextChange(change);\n }\n }\n }\n \n // Write agentic session to intermediate\n await output.writeIntermediate(paths, 'session', {\n iterations: agenticResult.iterations,\n toolsUsed: agenticResult.toolsUsed,\n state: agenticResult.state,\n });\n \n // Step 6: Write final output using Output module with metadata\n logger.debug('Writing final transcript...');\n if (state.enhancedText) {\n // Build metadata from routing decision and input\n const transcriptMetadata: Metadata.TranscriptMetadata = {\n title: extractTitleFromPath(paths.final),\n projectId: routeResult.projectId || undefined,\n project: routeResult.projectId || undefined,\n date: input.creation,\n routing: Metadata.createRoutingMetadata(routeResult),\n tags: Metadata.extractTagsFromSignals(routeResult.signals),\n confidence: routeResult.confidence,\n };\n \n await output.writeTranscript(paths, state.enhancedText, transcriptMetadata);\n }\n \n // Step 7: Generate reflection report\n logger.debug('Generating reflection report...');\n let reflectionReport: Reflection.ReflectionReport | undefined;\n if (reflection) {\n reflectionReport = reflection.generate(\n input.audioFile,\n paths.final,\n undefined,\n state.enhancedText\n );\n \n if (paths.intermediate.reflection) {\n await reflection.save(reflectionReport, paths.intermediate.reflection);\n }\n }\n \n // Step 8: End interactive session\n logger.debug('Finalizing session...');\n let session: Interactive.InteractiveSession | undefined;\n if (config.interactive) {\n session = interactive.endSession();\n logger.debug('Interactive session ended: %d clarifications', session.responses.length);\n \n // Save session if path available\n if (paths.intermediate.session) {\n await output.writeIntermediate(paths, 'session', session);\n }\n }\n \n // Step 9: Cleanup if needed\n if (!config.keepIntermediates && !config.debug) {\n await output.cleanIntermediates(paths);\n }\n\n // Step 10: Move audio file to processed directory\n let processedAudioPath: string | undefined;\n if (complete) {\n // Extract subject from output path for naming\n const subject = paths.final.split('/').pop()?.replace('.md', '') || undefined;\n processedAudioPath = await complete.complete(\n input.audioFile, \n input.hash, \n input.creation,\n subject\n );\n }\n \n const processingTime = Date.now() - startTime;\n \n // Compact summary output\n logger.info('Enhancement: %d iterations, %d tools, %.1fs', \n agenticResult.iterations, toolsUsed.length, agenticDuration / 1000);\n if (agenticResult.totalTokens) {\n logger.info('Tokens: %d total', agenticResult.totalTokens);\n }\n logger.info('Output: %s (%.1fs total)', paths.final, processingTime / 1000);\n \n return {\n outputPath: paths.final,\n enhancedText: state.enhancedText || '',\n rawTranscript: state.rawTranscript || '',\n routedProject: routeResult.projectId,\n routingConfidence: routeResult.confidence,\n processingTime,\n toolsUsed,\n correctionsApplied: agenticResult.state.resolvedEntities.size,\n processedAudioPath,\n reflection: reflectionReport,\n session,\n intermediatePaths: paths,\n };\n \n } catch (error) {\n logger.error('Pipeline error', { error });\n throw error;\n }\n };\n \n return { process: processInput };\n};\n"],"names":["create","config","logger","Logging","currentWorkingDir","globalThis","process","cwd","debug","context","Context","startingDir","contextDirectory","routingConfig","default","path","outputDirectory","structure","outputStructure","filename_options","outputFilenameOptions","createDirectories","projects","conflict_resolution","routing","Routing","interactive","Interactive","enabled","output","Output","intermediateDir","keepIntermediates","reflection","selfReflection","Reflection","transcription","Transcription","defaultModel","transcriptionModel","reasoning","Reasoning","model","complete","processedDirectory","CompletePhase","dryRun","extractTitleFromPath","outputPath","filename","split","pop","replace","undefined","withoutDate","map","word","charAt","toUpperCase","slice","join","processInput","input","startTime","Date","now","info","audioFile","hash","state","collector","start","startSession","onboardingState","checkNeedsOnboarding","needsOnboarding","whisperStart","transcriptionResult","transcribe","rawTranscript","text","whisperDuration","length","recordWhisper","routingContext","transcriptText","audioDate","creation","sourceFile","routeResult","route","projectId","confidence","recordRoutingDecision","destination","signals","s","type","value","weight","alternativesConsidered","alternateMatches","alt","whyNotChosen","toFixed","buildOutputPath","paths","createOutputPaths","ensureDirectories","writeIntermediate","duration","agenticStart","toolContext","contextInstance","routingInstance","interactiveMode","interactiveInstance","executor","Agentic","agenticResult","enhancedText","toolsUsed","agenticDuration","tool","recordToolCall","recordCorrection","totalTokens","recordModelResponse","contextChanges","change","recordContextChange","iterations","transcriptMetadata","title","final","project","date","Metadata","tags","writeTranscript","reflectionReport","generate","intermediate","save","session","endSession","responses","cleanIntermediates","processedAudioPath","subject","processingTime","routedProject","routingConfidence","correctionsApplied","resolvedEntities","size","intermediatePaths","error"],"mappings":";;;;;;;;;;;;AAmCO,MAAMA,SAAS,OAAOC,MAAAA,GAAAA;AAkCFA,IAAAA,IAAAA,yBAAAA;IAjCvB,MAAMC,MAAAA,GAASC,SAAiB,EAAA;AAChC,IAAA,MAAMC,iBAAAA,GAAoBC,UAAAA,CAAWC,OAAO,CAACC,GAAG,EAAA;AAEhDL,IAAAA,MAAAA,CAAOM,KAAK,CAAC,oDAAA,CAAA;;AAGb,IAAA,MAAMC,OAAAA,GAAU,MAAMC,QAAc,CAAC;QACjCC,WAAAA,EAAaV,MAAAA,CAAOW,gBAAgB,IAAIR;AAC5C,KAAA,CAAA;AACAF,IAAAA,MAAAA,CAAOM,KAAK,CAAC,gEAAA,CAAA;;AAGb,IAAA,MAAMK,aAAAA,GAAuC;QACzCC,OAAAA,EAAS;YACLC,IAAAA,EAAMd,MAAAA,CAAOe,eAAe,IAAI,SAAA;YAChCC,SAAAA,EAAYhB,MAAAA,CAAOiB,eAAe,IAAI,OAAA;YACtCC,gBAAAA,EAAmBlB,MAAAA,CAAOmB,qBAAqB,IAAI;AAAC,gBAAA,MAAA;AAAQ,gBAAA,MAAA;AAAQ,gBAAA;AAAU,aAAA;YAC9EC,iBAAAA,EAAmB;AACvB,SAAA;AACAC,QAAAA,QAAAA,EAAU,EAAE;QACZC,mBAAAA,EAAqB;AACzB,KAAA;AAEA,IAAA,MAAMC,OAAAA,GAAUC,QAAc,CAACZ,aAAAA,EAAeJ,OAAAA,CAAAA;AAC9CP,IAAAA,MAAAA,CAAOM,KAAK,CAAC,4BAAA,CAAA;IAEb,MAAMkB,WAAAA,GAAcC,QAAkB,CAClC;AAAEC,QAAAA,OAAAA,EAAS3B,OAAOyB,WAAuC,CAAA,EACzDjB,OAAAA,CAAAA;IAGJ,MAAMoB,MAAAA,GAASC,QAAa,CAAC;QACzBC,eAAAA,EAAiB9B,MAAAA,CAAO8B,eAAe,IAAI,oBAAA;AAC3CC,QAAAA,iBAAiB,GAAE/B,yBAAAA,GAAAA,MAAAA,CAAO+B,iBAAiB,MAAA,IAAA,IAAxB/B,uCAAAA,yBAAAA,GAA4B,IAEnD,CAAA,CAAA;AACAC,IAAAA,MAAAA,CAAOM,KAAK,CAAC,4BAAA,CAAA;AAEb,IAAA,MAAMyB,aAAahC,MAAAA,CAAOiC,cAAc,GAClCC,QAAiB,CAKnB,CAAA,GACE,IAAA;AACN,IAAA,IAAIF,UAAAA,EAAY;AACZ/B,QAAAA,MAAAA,CAAOM,KAAK,CAAC,gCAAA,CAAA;AACjB,IAAA;;IAGA,MAAM4B,aAAAA,GAAgBC,QAAoB,CAAC;AACvCC,QAAAA,YAAAA,EAAcrC,OAAOsC;AACzB,KAAA,CAAA;AACArC,IAAAA,MAAAA,CAAOM,KAAK,CAAC,kDAAA,EAAoDP,MAAAA,CAAOsC,kBAAkB,CAAA;;IAG1F,MAAMC,SAAAA,GAAYC,QAAgB,CAAC;AAAEC,QAAAA,KAAAA,EAAOzC,OAAOyC;AAAM,KAAA,CAAA;AACzDxC,IAAAA,MAAAA,CAAOM,KAAK,CAAC,6CAAA,EAA+CP,MAAAA,CAAOyC,KAAK,CAAA;;;AAIxE,IAAA,MAAMC,WAAW1C,MAAAA,CAAO2C,kBAAkB,GACpCC,QAAoB,CAAC;AACnBD,QAAAA,kBAAAA,EAAoB3C,OAAO2C,kBAAkB;AAC7C1B,QAAAA,eAAAA,EAAiBjB,OAAOiB,eAAe;AACvC4B,QAAAA,MAAAA,EAAQ7C,OAAO6C;KACnB,CAAA,GACE,IAAA;AACN,IAAA,IAAIH,QAAAA,EAAU;AACVzC,QAAAA,MAAAA,CAAOM,KAAK,CAAC,yDAAA,EAA2DP,MAAAA,CAAO2C,kBAAkB,CAAA;AACrG,IAAA;;AAGA,IAAA,MAAMG,uBAAuB,CAACC,UAAAA,GAAAA;AACTA,QAAAA,IAAAA,qBAAAA;AAAjB,QAAA,MAAMC,QAAAA,GAAAA,CAAWD,qBAAAA,GAAAA,UAAAA,CAAWE,KAAK,CAAC,GAAA,CAAA,CAAKC,GAAG,EAAA,MAAA,IAAA,IAAzBH,qBAAAA,KAAAA,MAAAA,GAAAA,MAAAA,GAAAA,qBAAAA,CAA6BI,OAAO,CAAC,KAAA,EAAO,EAAA,CAAA;QAC7D,IAAI,CAACH,UAAU,OAAOI,SAAAA;;AAGtB,QAAA,MAAMC,WAAAA,GAAcL,QAAAA,CAASG,OAAO,CAAC,eAAA,EAAiB,EAAA,CAAA;QACtD,IAAI,CAACE,aAAa,OAAOD,SAAAA;;AAGzB,QAAA,OAAOC,YACFJ,KAAK,CAAC,KACNK,GAAG,CAACC,CAAAA,IAAAA,GAAQA,IAAAA,CAAKC,MAAM,CAAC,CAAA,CAAA,CAAGC,WAAW,EAAA,GAAKF,IAAAA,CAAKG,KAAK,CAAC,CAAA,CAAA,CAAA,CACtDC,IAAI,CAAC,GAAA,CAAA;AACd,IAAA,CAAA;AAEA,IAAA,MAAMC,eAAe,OAAOC,KAAAA,GAAAA;QACxB,MAAMC,SAAAA,GAAYC,KAAKC,GAAG,EAAA;AAE1B/D,QAAAA,MAAAA,CAAOgE,IAAI,CAAC,2BAAA,EAA6BJ,MAAMK,SAAS,EAAEL,MAAMM,IAAI,CAAA;;AAGpE,QAAA,MAAMC,KAAAA,GAAuB;AACzBP,YAAAA,KAAAA;AACAC,YAAAA,SAAAA,EAAW,IAAIC,IAAAA;AACnB,SAAA;;AAGA,QAAA,IAAI/B,UAAAA,EAAY;YACZA,UAAAA,CAAWqC,SAAS,CAACC,KAAK,EAAA;AAC9B,QAAA;;QAGA,IAAItE,MAAAA,CAAOyB,WAAW,EAAE;AACpBA,YAAAA,WAAAA,CAAY8C,YAAY,EAAA;AACxBtE,YAAAA,MAAAA,CAAOM,KAAK,CAAC,6BAAA,CAAA;AACjB,QAAA;QAEA,IAAI;;AAEAN,YAAAA,MAAAA,CAAOM,KAAK,CAAC,8BAAA,CAAA;YACb,MAAMiE,eAAAA,GAAkB/C,YAAYgD,oBAAoB,EAAA;YACxD,IAAID,eAAAA,CAAgBE,eAAe,EAAE;AACjCzE,gBAAAA,MAAAA,CAAOM,KAAK,CAAC,kDAAA,CAAA;AACjB,YAAA;;AAGAN,YAAAA,MAAAA,CAAOgE,IAAI,CAAC,uBAAA,CAAA;YACZ,MAAMU,YAAAA,GAAeZ,KAAKC,GAAG,EAAA;AAE7B,YAAA,MAAMY,sBAAsB,MAAMzC,aAAAA,CAAc0C,UAAU,CAAChB,KAAAA,CAAMK,SAAS,EAAE;AACxEzB,gBAAAA,KAAAA,EAAOzC,OAAOsC;AAClB,aAAA,CAAA;YACA8B,KAAAA,CAAMU,aAAa,GAAGF,mBAAAA,CAAoBG,IAAI;YAE9C,MAAMC,eAAAA,GAAkBjB,IAAAA,CAAKC,GAAG,EAAA,GAAKW,YAAAA;YACrC1E,MAAAA,CAAOgE,IAAI,CAAC,kCAAA,EACRG,KAAAA,CAAMU,aAAa,CAACG,MAAM,EAAED,eAAAA,GAAkB,IAAA,CAAA;AAElD,YAAA,IAAIhD,UAAAA,EAAY;gBACZA,UAAAA,CAAWqC,SAAS,CAACa,aAAa,CAACF,eAAAA,CAAAA;AACvC,YAAA;;AAGA/E,YAAAA,MAAAA,CAAOM,KAAK,CAAC,oCAAA,CAAA;AACb,YAAA,MAAM4E,cAAAA,GAAyC;gBAC3CC,cAAAA,EAAgBhB,KAAAA,CAAMU,aAAa,IAAI,EAAA;AACvCO,gBAAAA,SAAAA,EAAWxB,MAAMyB,QAAQ;AACzBC,gBAAAA,UAAAA,EAAY1B,MAAMK,SAAS;AAC3BC,gBAAAA,IAAAA,EAAMN,MAAMM;AAChB,aAAA;YAEA,MAAMqB,WAAAA,GAAcjE,OAAAA,CAAQkE,KAAK,CAACN,cAAAA,CAAAA;YAElClF,MAAAA,CAAOM,KAAK,CAAC,+CAAA,EACTiF,WAAAA,CAAYE,SAAS,IAAI,SAAA,EAAWF,YAAYG,UAAU,CAAA;;AAG9D,YAAA,IAAI3D,UAAAA,EAAY;AAWgBwD,gBAAAA,IAAAA,6BAAAA;gBAV5BxD,UAAAA,CAAWqC,SAAS,CAACuB,qBAAqB,CAAC;AACvCF,oBAAAA,SAAAA,EAAWF,YAAYE,SAAS;oBAChCG,WAAAA,EAAaL,WAAAA,CAAYK,WAAW,CAAC/E,IAAI;AACzC6E,oBAAAA,UAAAA,EAAYH,YAAYG,UAAU;AAClCpD,oBAAAA,SAAAA,EAAWiD,YAAYjD,SAAS;AAChCuD,oBAAAA,OAAAA,EAASN,YAAYM,OAAO,CAACxC,GAAG,CAACyC,CAAAA,KAAM;AACnCC,4BAAAA,IAAAA,EAAMD,EAAEC,IAAI;AACZC,4BAAAA,KAAAA,EAAOF,EAAEE,KAAK;AACdC,4BAAAA,MAAAA,EAAQH,EAAEG;yBACd,CAAA,CAAA;oBACAC,sBAAsB,EAAA,CAAEX,6BAAAA,GAAAA,WAAAA,CAAYY,gBAAgB,MAAA,IAAA,IAA5BZ,6BAAAA,KAAAA,KAAAA,CAAAA,GAAAA,KAAAA,CAAAA,GAAAA,6BAAAA,CAA8BlC,GAAG,CAAC+C,CAAAA,GAAAA,IAAQ;AAC9DX,4BAAAA,SAAAA,EAAWW,IAAIX,SAAS;AACxBC,4BAAAA,UAAAA,EAAYU,IAAIV,UAAU;AAC1BW,4BAAAA,YAAAA,EAAc,CAAC,kBAAkB,EAAGD,CAAAA,GAAAA,CAAIV,UAAU,GAAG,GAAE,EAAGY,OAAO,CAAC,CAAA,CAAA,CAAG,EAAE;yBAC3E,CAAA;AACJ,iBAAA,CAAA;AACJ,YAAA;;AAGA,YAAA,MAAMxD,UAAAA,GAAaxB,OAAAA,CAAQiF,eAAe,CAAChB,WAAAA,EAAaL,cAAAA,CAAAA;YACxDlF,MAAAA,CAAOM,KAAK,CAAC,iBAAA,EAAmBwC,UAAAA,CAAAA;;AAGhC9C,YAAAA,MAAAA,CAAOM,KAAK,CAAC,kCAAA,CAAA;AACb,YAAA,MAAMkG,KAAAA,GAAQ7E,MAAAA,CAAO8E,iBAAiB,CAClC7C,KAAAA,CAAMK,SAAS,EACfnB,UAAAA,EACAc,KAAAA,CAAMM,IAAI,EACVN,KAAAA,CAAMyB,QAAQ,CAAA;YAGlB,MAAM1D,MAAAA,CAAO+E,iBAAiB,CAACF,KAAAA,CAAAA;;AAG/B,YAAA,MAAM7E,MAAAA,CAAOgF,iBAAiB,CAACH,KAAAA,EAAO,YAAA,EAAc;AAChD1B,gBAAAA,IAAAA,EAAMX,MAAMU,aAAa;AACzBrC,gBAAAA,KAAAA,EAAOzC,OAAOsC,kBAAkB;gBAChCuE,QAAAA,EAAU7B;AACd,aAAA,CAAA;;AAGA/E,YAAAA,MAAAA,CAAOgE,IAAI,CAAC,sBAAA,EAAwBjE,MAAAA,CAAOyC,KAAK,CAAA;YAEhD,MAAMqE,YAAAA,GAAe/C,KAAKC,GAAG,EAAA;AAC7B,YAAA,MAAM+C,WAAAA,GAAmC;gBACrC3B,cAAAA,EAAgBhB,KAAAA,CAAMU,aAAa,IAAI,EAAA;AACvCO,gBAAAA,SAAAA,EAAWxB,MAAMyB,QAAQ;AACzBC,gBAAAA,UAAAA,EAAY1B,MAAMK,SAAS;gBAC3B8C,eAAAA,EAAiBxG,OAAAA;gBACjByG,eAAAA,EAAiB1F,OAAAA;AACjB2F,gBAAAA,eAAAA,EAAiBlH,OAAOyB,WAAW;gBACnC0F,mBAAAA,EAAqBnH,MAAAA,CAAOyB,WAAW,GAAGA,WAAAA,GAAc2B;AAC5D,aAAA;AAEA,YAAA,MAAMgE,QAAAA,GAAWC,QAAc,CAAC9E,SAAAA,EAAWwE,WAAAA,CAAAA;AAC3C,YAAA,MAAMO,gBAAgB,MAAMF,QAAAA,CAAS/G,OAAO,CAAC+D,KAAAA,CAAMU,aAAa,IAAI,EAAA,CAAA;YAEpEV,KAAAA,CAAMmD,YAAY,GAAGD,aAAAA,CAAcC,YAAY;YAC/C,MAAMC,SAAAA,GAAYF,cAAcE,SAAS;YACzC,MAAMC,eAAAA,GAAkB1D,IAAAA,CAAKC,GAAG,EAAA,GAAK8C,YAAAA;;AAGrC,YAAA,IAAI9E,UAAAA,EAAY;gBACZ,KAAK,MAAM0F,QAAQF,SAAAA,CAAW;oBAC1BxF,UAAAA,CAAWqC,SAAS,CAACsD,cAAc,CAACD,MAAMD,eAAAA,GAAkBD,SAAAA,CAAUvC,MAAM,EAAE,IAAA,CAAA;AAClF,gBAAA;gBACAjD,UAAAA,CAAWqC,SAAS,CAACuD,gBAAgB,CAACxD,MAAMU,aAAa,IAAI,EAAA,EAAIV,KAAAA,CAAMmD,YAAY,CAAA;;gBAEnF,IAAID,aAAAA,CAAcO,WAAW,EAAE;oBAC3B7F,UAAAA,CAAWqC,SAAS,CAACyD,mBAAmB,CAAC9H,OAAOyC,KAAK,EAAE6E,cAAcO,WAAW,CAAA;AACpF,gBAAA;;gBAEA,IAAIP,aAAAA,CAAcS,cAAc,EAAE;AAC9B,oBAAA,KAAK,MAAMC,MAAAA,IAAUV,aAAAA,CAAcS,cAAc,CAAE;wBAC/C/F,UAAAA,CAAWqC,SAAS,CAAC4D,mBAAmB,CAACD,MAAAA,CAAAA;AAC7C,oBAAA;AACJ,gBAAA;AACJ,YAAA;;AAGA,YAAA,MAAMpG,MAAAA,CAAOgF,iBAAiB,CAACH,KAAAA,EAAO,SAAA,EAAW;AAC7CyB,gBAAAA,UAAAA,EAAYZ,cAAcY,UAAU;AACpCV,gBAAAA,SAAAA,EAAWF,cAAcE,SAAS;AAClCpD,gBAAAA,KAAAA,EAAOkD,cAAclD;AACzB,aAAA,CAAA;;AAGAnE,YAAAA,MAAAA,CAAOM,KAAK,CAAC,6BAAA,CAAA;YACb,IAAI6D,KAAAA,CAAMmD,YAAY,EAAE;;AAEpB,gBAAA,MAAMY,kBAAAA,GAAkD;oBACpDC,KAAAA,EAAOtF,oBAAAA,CAAqB2D,MAAM4B,KAAK,CAAA;oBACvC3C,SAAAA,EAAWF,WAAAA,CAAYE,SAAS,IAAItC,SAAAA;oBACpCkF,OAAAA,EAAS9C,WAAAA,CAAYE,SAAS,IAAItC,SAAAA;AAClCmF,oBAAAA,IAAAA,EAAM1E,MAAMyB,QAAQ;oBACpB/D,OAAAA,EAASiH,qBAA8B,CAAChD,WAAAA,CAAAA;AACxCiD,oBAAAA,IAAAA,EAAMD,sBAA+B,CAAChD,WAAAA,CAAYM,OAAO,CAAA;AACzDH,oBAAAA,UAAAA,EAAYH,YAAYG;AAC5B,iBAAA;AAEA,gBAAA,MAAM/D,OAAO8G,eAAe,CAACjC,KAAAA,EAAOrC,KAAAA,CAAMmD,YAAY,EAAEY,kBAAAA,CAAAA;AAC5D,YAAA;;AAGAlI,YAAAA,MAAAA,CAAOM,KAAK,CAAC,iCAAA,CAAA;YACb,IAAIoI,gBAAAA;AACJ,YAAA,IAAI3G,UAAAA,EAAY;gBACZ2G,gBAAAA,GAAmB3G,UAAAA,CAAW4G,QAAQ,CAClC/E,KAAAA,CAAMK,SAAS,EACfuC,KAAAA,CAAM4B,KAAK,EACXjF,SAAAA,EACAgB,KAAAA,CAAMmD,YAAY,CAAA;AAGtB,gBAAA,IAAId,KAAAA,CAAMoC,YAAY,CAAC7G,UAAU,EAAE;AAC/B,oBAAA,MAAMA,WAAW8G,IAAI,CAACH,kBAAkBlC,KAAAA,CAAMoC,YAAY,CAAC7G,UAAU,CAAA;AACzE,gBAAA;AACJ,YAAA;;AAGA/B,YAAAA,MAAAA,CAAOM,KAAK,CAAC,uBAAA,CAAA;YACb,IAAIwI,OAAAA;YACJ,IAAI/I,MAAAA,CAAOyB,WAAW,EAAE;AACpBsH,gBAAAA,OAAAA,GAAUtH,YAAYuH,UAAU,EAAA;AAChC/I,gBAAAA,MAAAA,CAAOM,KAAK,CAAC,8CAAA,EAAgDwI,OAAAA,CAAQE,SAAS,CAAChE,MAAM,CAAA;;AAGrF,gBAAA,IAAIwB,KAAAA,CAAMoC,YAAY,CAACE,OAAO,EAAE;AAC5B,oBAAA,MAAMnH,MAAAA,CAAOgF,iBAAiB,CAACH,KAAAA,EAAO,SAAA,EAAWsC,OAAAA,CAAAA;AACrD,gBAAA;AACJ,YAAA;;AAGA,YAAA,IAAI,CAAC/I,MAAAA,CAAO+B,iBAAiB,IAAI,CAAC/B,MAAAA,CAAOO,KAAK,EAAE;gBAC5C,MAAMqB,MAAAA,CAAOsH,kBAAkB,CAACzC,KAAAA,CAAAA;AACpC,YAAA;;YAGA,IAAI0C,kBAAAA;AACJ,YAAA,IAAIzG,QAAAA,EAAU;AAEM+D,gBAAAA,IAAAA,sBAAAA;;AAAhB,gBAAA,MAAM2C,UAAU3C,CAAAA,CAAAA,sBAAAA,GAAAA,KAAAA,CAAM4B,KAAK,CAACpF,KAAK,CAAC,GAAA,CAAA,CAAKC,GAAG,gBAA1BuD,sBAAAA,KAAAA,KAAAA,CAAAA,GAAAA,KAAAA,CAAAA,GAAAA,sBAAAA,CAA8BtD,OAAO,CAAC,OAAO,EAAA,CAAA,KAAOC,SAAAA;AACpE+F,gBAAAA,kBAAAA,GAAqB,MAAMzG,QAAAA,CAASA,QAAQ,CACxCmB,KAAAA,CAAMK,SAAS,EACfL,KAAAA,CAAMM,IAAI,EACVN,KAAAA,CAAMyB,QAAQ,EACd8D,OAAAA,CAAAA;AAER,YAAA;YAEA,MAAMC,cAAAA,GAAiBtF,IAAAA,CAAKC,GAAG,EAAA,GAAKF,SAAAA;;YAGpC7D,MAAAA,CAAOgE,IAAI,CAAC,6CAAA,EACRqD,aAAAA,CAAcY,UAAU,EAAEV,SAAAA,CAAUvC,MAAM,EAAEwC,eAAAA,GAAkB,IAAA,CAAA;YAClE,IAAIH,aAAAA,CAAcO,WAAW,EAAE;AAC3B5H,gBAAAA,MAAAA,CAAOgE,IAAI,CAAC,kBAAA,EAAoBqD,aAAAA,CAAcO,WAAW,CAAA;AAC7D,YAAA;AACA5H,YAAAA,MAAAA,CAAOgE,IAAI,CAAC,0BAAA,EAA4BwC,KAAAA,CAAM4B,KAAK,EAAEgB,cAAAA,GAAiB,IAAA,CAAA;YAEtE,OAAO;AACHtG,gBAAAA,UAAAA,EAAY0D,MAAM4B,KAAK;gBACvBd,YAAAA,EAAcnD,KAAAA,CAAMmD,YAAY,IAAI,EAAA;gBACpCzC,aAAAA,EAAeV,KAAAA,CAAMU,aAAa,IAAI,EAAA;AACtCwE,gBAAAA,aAAAA,EAAe9D,YAAYE,SAAS;AACpC6D,gBAAAA,iBAAAA,EAAmB/D,YAAYG,UAAU;AACzC0D,gBAAAA,cAAAA;AACA7B,gBAAAA,SAAAA;AACAgC,gBAAAA,kBAAAA,EAAoBlC,aAAAA,CAAclD,KAAK,CAACqF,gBAAgB,CAACC,IAAI;AAC7DP,gBAAAA,kBAAAA;gBACAnH,UAAAA,EAAY2G,gBAAAA;AACZI,gBAAAA,OAAAA;gBACAY,iBAAAA,EAAmBlD;AACvB,aAAA;AAEJ,QAAA,CAAA,CAAE,OAAOmD,KAAAA,EAAO;YACZ3J,MAAAA,CAAO2J,KAAK,CAAC,gBAAA,EAAkB;AAAEA,gBAAAA;AAAM,aAAA,CAAA;YACvC,MAAMA,KAAAA;AACV,QAAA;AACJ,IAAA,CAAA;IAEA,OAAO;QAAEvJ,OAAAA,EAASuD;AAAa,KAAA;AACnC;;;;"}
|
package/dist/routing/router.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.js","sources":["../../src/routing/router.ts"],"sourcesContent":["/**\n * Router\n * \n * Handles routing decisions and path building using Dreadcabinet patterns.\n * Takes classification results and builds output paths with appropriate\n * directory structure and filenames.\n * \n * Design Note: This module is designed to be self-contained and may be\n * extracted for use in other tools (kronologi, observasjon) in the future.\n */\n\nimport * as path from 'path';\nimport * as os from 'os';\nimport { \n RoutingContext, \n RouteDecision,\n RoutingConfig,\n FilesystemStructure\n} from './types';\nimport * as Classifier from './classifier';\n\nexport interface RouterInstance {\n route(context: RoutingContext): RouteDecision;\n buildOutputPath(decision: RouteDecision, context: RoutingContext): string;\n}\n\nexport const create = (\n config: RoutingConfig,\n classifier: Classifier.ClassifierInstance\n): RouterInstance => {\n \n const route = (context: RoutingContext): RouteDecision => {\n const results = classifier.classify(context, config.projects);\n \n if (results.length === 0) {\n return {\n projectId: null,\n destination: config.default,\n confidence: 1.0,\n signals: [],\n reasoning: 'No project matches found, using default routing',\n };\n }\n \n const bestMatch = results[0];\n const matchedProject = config.projects.find(p => p.projectId === bestMatch.projectId)!;\n \n // Handle conflict resolution if multiple high-confidence matches\n const highConfidenceMatches = results.filter(r => r.confidence > 0.5);\n \n if (highConfidenceMatches.length > 1 && config.conflict_resolution !== 'primary') {\n // Return best with alternates noted\n return {\n projectId: bestMatch.projectId,\n destination: matchedProject.destination,\n confidence: bestMatch.confidence,\n signals: bestMatch.signals,\n reasoning: bestMatch.reasoning,\n auto_tags: matchedProject.auto_tags,\n alternateMatches: highConfidenceMatches.slice(1),\n };\n }\n \n return {\n projectId: bestMatch.projectId,\n destination: matchedProject.destination,\n confidence: bestMatch.confidence,\n signals: bestMatch.signals,\n reasoning: bestMatch.reasoning,\n auto_tags: matchedProject.auto_tags,\n };\n };\n \n const buildOutputPath = (decision: RouteDecision, context: RoutingContext): string => {\n const { destination } = decision;\n \n // Expand ~ to home directory\n const basePath = expandPath(destination.path);\n \n // Build directory structure using Dreadcabinet patterns\n const directoryPath = buildDirectoryPath(basePath, destination.structure, context.audioDate);\n \n // Build filename using Dreadcabinet patterns\n // Pass structure so filename doesn't repeat info already in path\n const filename = buildFilename(destination.filename_options, context, destination.structure);\n \n return path.join(directoryPath, filename + '.md');\n };\n \n return { route, buildOutputPath };\n};\n\n// Dreadcabinet-style directory building\nfunction buildDirectoryPath(\n basePath: string, \n structure: FilesystemStructure, \n date: Date\n): string {\n const year = date.getFullYear().toString();\n const month = (date.getMonth() + 1).toString();\n const day = date.getDate().toString();\n \n switch (structure) {\n case 'none':\n return basePath;\n case 'year':\n return path.join(basePath, year);\n case 'month':\n return path.join(basePath, year, month);\n case 'day':\n return path.join(basePath, year, month, day);\n }\n}\n\n// Dreadcabinet-style filename building\n// The date portion is adjusted based on what's already in the directory path\nfunction buildFilename(\n options: Array<'date' | 'time' | 'subject'>,\n context: RoutingContext,\n structure: FilesystemStructure\n): string {\n const parts: string[] = [];\n const date = context.audioDate;\n const pad = (n: number) => n.toString().padStart(2, '0');\n \n for (const option of options) {\n switch (option) {\n case 'date': {\n // Adjust date format based on directory structure\n // Don't repeat info already in the path\n const day = pad(date.getDate());\n const month = pad(date.getMonth() + 1);\n const year = date.getFullYear().toString().slice(2);\n \n switch (structure) {\n case 'day':\n // Path has year/month/day - no date needed in filename\n break;\n case 'month':\n // Path has year/month - only day in filename\n parts.push(day);\n break;\n case 'year':\n // Path has year - month+day in filename\n parts.push(`${month}-${day}`);\n break;\n case 'none':\n // No date in path - full date in filename (YYMMDD)\n parts.push(`${year}${month}${day}`);\n break;\n }\n break;\n }\n case 'time': {\n const hours = pad(date.getHours());\n const minutes = pad(date.getMinutes());\n parts.push(`${hours}${minutes}`);\n break;\n }\n case 'subject': {\n const subject = extractSubject(context.transcriptText, context.sourceFile);\n if (subject) {\n parts.push(subject);\n }\n break;\n }\n }\n }\n \n // Join and clean up any double dashes\n return parts.join('-').replace(/--+/g, '-');\n}\n\nfunction extractSubject(text: string, sourceFile: string): string {\n // Try to extract from first sentence\n const firstSentence = text.split(/[.!?]/)[0]?.trim() ?? '';\n \n // Remove common prefixes\n const cleaned = firstSentence\n .replace(/^(this is a note about|note about|regarding|re:|meeting notes?:?)/i, '')\n .trim();\n \n if (cleaned.length > 3 && cleaned.length < 50) {\n return slugify(cleaned);\n }\n \n // Fall back to source filename\n return path.basename(sourceFile, path.extname(sourceFile))\n .replace(/[^a-zA-Z0-9-]/g, '-')\n .toLowerCase();\n}\n\nfunction slugify(text: string): string {\n return text\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-') // Replace non-alphanumeric with dash\n .replace(/--+/g, '-') // Collapse multiple dashes\n .replace(/^-|-$/g, '') // Remove leading/trailing dashes\n .slice(0, 40);\n}\n\nfunction expandPath(p: string): string {\n if (p.startsWith('~')) {\n return path.join(os.homedir(), p.slice(1));\n }\n return p;\n}\n\n"],"names":["create","config","classifier","route","context","results","classify","projects","length","projectId","destination","default","confidence","signals","reasoning","bestMatch","matchedProject","find","p","highConfidenceMatches","filter","r","conflict_resolution","auto_tags","alternateMatches","slice","buildOutputPath","decision","basePath","expandPath","path","directoryPath","buildDirectoryPath","structure","audioDate","filename","buildFilename","filename_options","join","date","year","getFullYear","toString","month","getMonth","day","getDate","options","parts","pad","n","padStart","option","push","hours","getHours","minutes","getMinutes","subject","extractSubject","transcriptText","sourceFile","replace","text","firstSentence","split","trim","cleaned","slugify","basename","extname","toLowerCase","startsWith","os","homedir"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"router.js","sources":["../../src/routing/router.ts"],"sourcesContent":["/**\n * Router\n * \n * Handles routing decisions and path building using Dreadcabinet patterns.\n * Takes classification results and builds output paths with appropriate\n * directory structure and filenames.\n * \n * Design Note: This module is designed to be self-contained and may be\n * extracted for use in other tools (kronologi, observasjon) in the future.\n */\n\nimport * as path from 'node:path';\nimport * as os from 'node:os';\nimport { \n RoutingContext, \n RouteDecision,\n RoutingConfig,\n FilesystemStructure\n} from './types';\nimport * as Classifier from './classifier';\n\nexport interface RouterInstance {\n route(context: RoutingContext): RouteDecision;\n buildOutputPath(decision: RouteDecision, context: RoutingContext): string;\n}\n\nexport const create = (\n config: RoutingConfig,\n classifier: Classifier.ClassifierInstance\n): RouterInstance => {\n \n const route = (context: RoutingContext): RouteDecision => {\n const results = classifier.classify(context, config.projects);\n \n if (results.length === 0) {\n return {\n projectId: null,\n destination: config.default,\n confidence: 1.0,\n signals: [],\n reasoning: 'No project matches found, using default routing',\n };\n }\n \n const bestMatch = results[0];\n const matchedProject = config.projects.find(p => p.projectId === bestMatch.projectId)!;\n \n // Handle conflict resolution if multiple high-confidence matches\n const highConfidenceMatches = results.filter(r => r.confidence > 0.5);\n \n if (highConfidenceMatches.length > 1 && config.conflict_resolution !== 'primary') {\n // Return best with alternates noted\n return {\n projectId: bestMatch.projectId,\n destination: matchedProject.destination,\n confidence: bestMatch.confidence,\n signals: bestMatch.signals,\n reasoning: bestMatch.reasoning,\n auto_tags: matchedProject.auto_tags,\n alternateMatches: highConfidenceMatches.slice(1),\n };\n }\n \n return {\n projectId: bestMatch.projectId,\n destination: matchedProject.destination,\n confidence: bestMatch.confidence,\n signals: bestMatch.signals,\n reasoning: bestMatch.reasoning,\n auto_tags: matchedProject.auto_tags,\n };\n };\n \n const buildOutputPath = (decision: RouteDecision, context: RoutingContext): string => {\n const { destination } = decision;\n \n // Expand ~ to home directory\n const basePath = expandPath(destination.path);\n \n // Build directory structure using Dreadcabinet patterns\n const directoryPath = buildDirectoryPath(basePath, destination.structure, context.audioDate);\n \n // Build filename using Dreadcabinet patterns\n // Pass structure so filename doesn't repeat info already in path\n const filename = buildFilename(destination.filename_options, context, destination.structure);\n \n return path.join(directoryPath, filename + '.md');\n };\n \n return { route, buildOutputPath };\n};\n\n// Dreadcabinet-style directory building\nfunction buildDirectoryPath(\n basePath: string, \n structure: FilesystemStructure, \n date: Date\n): string {\n const year = date.getFullYear().toString();\n const month = (date.getMonth() + 1).toString();\n const day = date.getDate().toString();\n \n switch (structure) {\n case 'none':\n return basePath;\n case 'year':\n return path.join(basePath, year);\n case 'month':\n return path.join(basePath, year, month);\n case 'day':\n return path.join(basePath, year, month, day);\n }\n}\n\n// Dreadcabinet-style filename building\n// The date portion is adjusted based on what's already in the directory path\nfunction buildFilename(\n options: Array<'date' | 'time' | 'subject'>,\n context: RoutingContext,\n structure: FilesystemStructure\n): string {\n const parts: string[] = [];\n const date = context.audioDate;\n const pad = (n: number) => n.toString().padStart(2, '0');\n \n for (const option of options) {\n switch (option) {\n case 'date': {\n // Adjust date format based on directory structure\n // Don't repeat info already in the path\n const day = pad(date.getDate());\n const month = pad(date.getMonth() + 1);\n const year = date.getFullYear().toString().slice(2);\n \n switch (structure) {\n case 'day':\n // Path has year/month/day - no date needed in filename\n break;\n case 'month':\n // Path has year/month - only day in filename\n parts.push(day);\n break;\n case 'year':\n // Path has year - month+day in filename\n parts.push(`${month}-${day}`);\n break;\n case 'none':\n // No date in path - full date in filename (YYMMDD)\n parts.push(`${year}${month}${day}`);\n break;\n }\n break;\n }\n case 'time': {\n const hours = pad(date.getHours());\n const minutes = pad(date.getMinutes());\n parts.push(`${hours}${minutes}`);\n break;\n }\n case 'subject': {\n const subject = extractSubject(context.transcriptText, context.sourceFile);\n if (subject) {\n parts.push(subject);\n }\n break;\n }\n }\n }\n \n // Join and clean up any double dashes\n return parts.join('-').replace(/--+/g, '-');\n}\n\nfunction extractSubject(text: string, sourceFile: string): string {\n // Try to extract from first sentence\n const firstSentence = text.split(/[.!?]/)[0]?.trim() ?? '';\n \n // Remove common prefixes\n const cleaned = firstSentence\n .replace(/^(this is a note about|note about|regarding|re:|meeting notes?:?)/i, '')\n .trim();\n \n if (cleaned.length > 3 && cleaned.length < 50) {\n return slugify(cleaned);\n }\n \n // Fall back to source filename\n return path.basename(sourceFile, path.extname(sourceFile))\n .replace(/[^a-zA-Z0-9-]/g, '-')\n .toLowerCase();\n}\n\nfunction slugify(text: string): string {\n return text\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-') // Replace non-alphanumeric with dash\n .replace(/--+/g, '-') // Collapse multiple dashes\n .replace(/^-|-$/g, '') // Remove leading/trailing dashes\n .slice(0, 40);\n}\n\nfunction expandPath(p: string): string {\n if (p.startsWith('~')) {\n return path.join(os.homedir(), p.slice(1));\n }\n return p;\n}\n\n"],"names":["create","config","classifier","route","context","results","classify","projects","length","projectId","destination","default","confidence","signals","reasoning","bestMatch","matchedProject","find","p","highConfidenceMatches","filter","r","conflict_resolution","auto_tags","alternateMatches","slice","buildOutputPath","decision","basePath","expandPath","path","directoryPath","buildDirectoryPath","structure","audioDate","filename","buildFilename","filename_options","join","date","year","getFullYear","toString","month","getMonth","day","getDate","options","parts","pad","n","padStart","option","push","hours","getHours","minutes","getMinutes","subject","extractSubject","transcriptText","sourceFile","replace","text","firstSentence","split","trim","cleaned","slugify","basename","extname","toLowerCase","startsWith","os","homedir"],"mappings":";;;AA0BO,MAAMA,MAAAA,GAAS,CAClBC,MAAAA,EACAC,UAAAA,GAAAA;AAGA,IAAA,MAAMC,QAAQ,CAACC,OAAAA,GAAAA;AACX,QAAA,MAAMC,UAAUH,UAAAA,CAAWI,QAAQ,CAACF,OAAAA,EAASH,OAAOM,QAAQ,CAAA;QAE5D,IAAIF,OAAAA,CAAQG,MAAM,KAAK,CAAA,EAAG;YACtB,OAAO;gBACHC,SAAAA,EAAW,IAAA;AACXC,gBAAAA,WAAAA,EAAaT,OAAOU,OAAO;gBAC3BC,UAAAA,EAAY,GAAA;AACZC,gBAAAA,OAAAA,EAAS,EAAE;gBACXC,SAAAA,EAAW;AACf,aAAA;AACJ,QAAA;QAEA,MAAMC,SAAAA,GAAYV,OAAO,CAAC,CAAA,CAAE;AAC5B,QAAA,MAAMW,cAAAA,GAAiBf,MAAAA,CAAOM,QAAQ,CAACU,IAAI,CAACC,CAAAA,CAAAA,GAAKA,CAAAA,CAAET,SAAS,KAAKM,SAAAA,CAAUN,SAAS,CAAA;;QAGpF,MAAMU,qBAAAA,GAAwBd,QAAQe,MAAM,CAACC,CAAAA,CAAAA,GAAKA,CAAAA,CAAET,UAAU,GAAG,GAAA,CAAA;AAEjE,QAAA,IAAIO,sBAAsBX,MAAM,GAAG,KAAKP,MAAAA,CAAOqB,mBAAmB,KAAK,SAAA,EAAW;;YAE9E,OAAO;AACHb,gBAAAA,SAAAA,EAAWM,UAAUN,SAAS;AAC9BC,gBAAAA,WAAAA,EAAaM,eAAeN,WAAW;AACvCE,gBAAAA,UAAAA,EAAYG,UAAUH,UAAU;AAChCC,gBAAAA,OAAAA,EAASE,UAAUF,OAAO;AAC1BC,gBAAAA,SAAAA,EAAWC,UAAUD,SAAS;AAC9BS,gBAAAA,SAAAA,EAAWP,eAAeO,SAAS;gBACnCC,gBAAAA,EAAkBL,qBAAAA,CAAsBM,KAAK,CAAC,CAAA;AAClD,aAAA;AACJ,QAAA;QAEA,OAAO;AACHhB,YAAAA,SAAAA,EAAWM,UAAUN,SAAS;AAC9BC,YAAAA,WAAAA,EAAaM,eAAeN,WAAW;AACvCE,YAAAA,UAAAA,EAAYG,UAAUH,UAAU;AAChCC,YAAAA,OAAAA,EAASE,UAAUF,OAAO;AAC1BC,YAAAA,SAAAA,EAAWC,UAAUD,SAAS;AAC9BS,YAAAA,SAAAA,EAAWP,eAAeO;AAC9B,SAAA;AACJ,IAAA,CAAA;IAEA,MAAMG,eAAAA,GAAkB,CAACC,QAAAA,EAAyBvB,OAAAA,GAAAA;QAC9C,MAAM,EAAEM,WAAW,EAAE,GAAGiB,QAAAA;;QAGxB,MAAMC,QAAAA,GAAWC,UAAAA,CAAWnB,WAAAA,CAAYoB,IAAI,CAAA;;AAG5C,QAAA,MAAMC,gBAAgBC,kBAAAA,CAAmBJ,QAAAA,EAAUlB,YAAYuB,SAAS,EAAE7B,QAAQ8B,SAAS,CAAA;;;AAI3F,QAAA,MAAMC,WAAWC,aAAAA,CAAc1B,WAAAA,CAAY2B,gBAAgB,EAAEjC,OAAAA,EAASM,YAAYuB,SAAS,CAAA;AAE3F,QAAA,OAAOH,IAAAA,CAAKQ,IAAI,CAACP,aAAAA,EAAeI,QAAAA,GAAW,KAAA,CAAA;AAC/C,IAAA,CAAA;IAEA,OAAO;AAAEhC,QAAAA,KAAAA;AAAOuB,QAAAA;AAAgB,KAAA;AACpC;AAEA;AACA,SAASM,kBAAAA,CACLJ,QAAgB,EAChBK,SAA8B,EAC9BM,IAAU,EAAA;AAEV,IAAA,MAAMC,IAAAA,GAAOD,IAAAA,CAAKE,WAAW,EAAA,CAAGC,QAAQ,EAAA;IACxC,MAAMC,KAAAA,GAAQ,CAACJ,IAAAA,CAAKK,QAAQ,EAAA,GAAK,CAAA,EAAGF,QAAQ,EAAA;AAC5C,IAAA,MAAMG,GAAAA,GAAMN,IAAAA,CAAKO,OAAO,EAAA,CAAGJ,QAAQ,EAAA;IAEnC,OAAQT,SAAAA;QACJ,KAAK,MAAA;YACD,OAAOL,QAAAA;QACX,KAAK,MAAA;YACD,OAAOE,IAAAA,CAAKQ,IAAI,CAACV,QAAAA,EAAUY,IAAAA,CAAAA;QAC/B,KAAK,OAAA;AACD,YAAA,OAAOV,IAAAA,CAAKQ,IAAI,CAACV,QAAAA,EAAUY,IAAAA,EAAMG,KAAAA,CAAAA;QACrC,KAAK,KAAA;AACD,YAAA,OAAOb,IAAAA,CAAKQ,IAAI,CAACV,QAAAA,EAAUY,MAAMG,KAAAA,EAAOE,GAAAA,CAAAA;AAChD;AACJ;AAEA;AACA;AACA,SAAST,aAAAA,CACLW,OAA2C,EAC3C3C,OAAuB,EACvB6B,SAA8B,EAAA;AAE9B,IAAA,MAAMe,QAAkB,EAAE;IAC1B,MAAMT,IAAAA,GAAOnC,QAAQ8B,SAAS;IAC9B,MAAMe,GAAAA,GAAM,CAACC,CAAAA,GAAcA,CAAAA,CAAER,QAAQ,EAAA,CAAGS,QAAQ,CAAC,CAAA,EAAG,GAAA,CAAA;IAEpD,KAAK,MAAMC,UAAUL,OAAAA,CAAS;QAC1B,OAAQK,MAAAA;YACJ,KAAK,MAAA;AAAQ,gBAAA;;;oBAGT,MAAMP,GAAAA,GAAMI,GAAAA,CAAIV,IAAAA,CAAKO,OAAO,EAAA,CAAA;AAC5B,oBAAA,MAAMH,KAAAA,GAAQM,GAAAA,CAAIV,IAAAA,CAAKK,QAAQ,EAAA,GAAK,CAAA,CAAA;AACpC,oBAAA,MAAMJ,OAAOD,IAAAA,CAAKE,WAAW,GAAGC,QAAQ,EAAA,CAAGjB,KAAK,CAAC,CAAA,CAAA;oBAEjD,OAAQQ,SAAAA;wBACJ,KAAK,KAAA;AAED,4BAAA;wBACJ,KAAK,OAAA;;AAEDe,4BAAAA,KAAAA,CAAMK,IAAI,CAACR,GAAAA,CAAAA;AACX,4BAAA;wBACJ,KAAK,MAAA;;AAEDG,4BAAAA,KAAAA,CAAMK,IAAI,CAAC,CAAA,EAAGV,KAAAA,CAAM,CAAC,EAAEE,GAAAA,CAAAA,CAAK,CAAA;AAC5B,4BAAA;wBACJ,KAAK,MAAA;;AAEDG,4BAAAA,KAAAA,CAAMK,IAAI,CAAC,CAAA,EAAGb,IAAAA,CAAAA,EAAOG,QAAQE,GAAAA,CAAAA,CAAK,CAAA;AAClC,4BAAA;AACR;AACA,oBAAA;AACJ,gBAAA;YACA,KAAK,MAAA;AAAQ,gBAAA;oBACT,MAAMS,KAAAA,GAAQL,GAAAA,CAAIV,IAAAA,CAAKgB,QAAQ,EAAA,CAAA;oBAC/B,MAAMC,OAAAA,GAAUP,GAAAA,CAAIV,IAAAA,CAAKkB,UAAU,EAAA,CAAA;AACnCT,oBAAAA,KAAAA,CAAMK,IAAI,CAAC,CAAA,EAAGC,KAAAA,CAAAA,EAAQE,OAAAA,CAAAA,CAAS,CAAA;AAC/B,oBAAA;AACJ,gBAAA;YACA,KAAK,SAAA;AAAW,gBAAA;AACZ,oBAAA,MAAME,UAAUC,cAAAA,CAAevD,OAAAA,CAAQwD,cAAc,EAAExD,QAAQyD,UAAU,CAAA;AACzE,oBAAA,IAAIH,OAAAA,EAAS;AACTV,wBAAAA,KAAAA,CAAMK,IAAI,CAACK,OAAAA,CAAAA;AACf,oBAAA;AACA,oBAAA;AACJ,gBAAA;AACJ;AACJ,IAAA;;AAGA,IAAA,OAAOV,MAAMV,IAAI,CAAC,GAAA,CAAA,CAAKwB,OAAO,CAAC,MAAA,EAAQ,GAAA,CAAA;AAC3C;AAEA,SAASH,cAAAA,CAAeI,IAAY,EAAEF,UAAkB,EAAA;;AAE9BE,IAAAA,IAAAA,YAAAA;;AAAtB,IAAA,MAAMC,aAAAA,GAAAA,CAAAA,IAAAA,GAAAA,CAAgBD,YAAAA,GAAAA,IAAAA,CAAKE,KAAK,CAAC,OAAA,CAAQ,CAAC,CAAA,CAAE,MAAA,IAAA,IAAtBF,YAAAA,KAAAA,MAAAA,GAAAA,MAAAA,GAAAA,YAAAA,CAAwBG,IAAI,EAAA,MAAA,IAAA,IAAA,IAAA,KAAA,MAAA,GAAA,IAAA,GAAM,EAAA;;AAGxD,IAAA,MAAMC,UAAUH,aAAAA,CACXF,OAAO,CAAC,oEAAA,EAAsE,IAC9EI,IAAI,EAAA;AAET,IAAA,IAAIC,QAAQ3D,MAAM,GAAG,KAAK2D,OAAAA,CAAQ3D,MAAM,GAAG,EAAA,EAAI;AAC3C,QAAA,OAAO4D,OAAAA,CAAQD,OAAAA,CAAAA;AACnB,IAAA;;AAGA,IAAA,OAAOrC,IAAAA,CAAKuC,QAAQ,CAACR,UAAAA,EAAY/B,IAAAA,CAAKwC,OAAO,CAACT,UAAAA,CAAAA,CAAAA,CACzCC,OAAO,CAAC,gBAAA,EAAkB,GAAA,CAAA,CAC1BS,WAAW,EAAA;AACpB;AAEA,SAASH,QAAQL,IAAY,EAAA;AACzB,IAAA,OAAOA,KACFQ,WAAW,EAAA,CACXT,OAAO,CAAC,aAAA,EAAe;KACvBA,OAAO,CAAC,MAAA,EAAQ,GAAA,CAAA;KAChBA,OAAO,CAAC,QAAA,EAAU,EAAA,CAAA;AAClBrC,KAAAA,KAAK,CAAC,CAAA,EAAG,EAAA,CAAA;AAClB;AAEA,SAASI,WAAWX,CAAS,EAAA;IACzB,IAAIA,CAAAA,CAAEsD,UAAU,CAAC,GAAA,CAAA,EAAM;QACnB,OAAO1C,IAAAA,CAAKQ,IAAI,CAACmC,EAAAA,CAAGC,OAAO,EAAA,EAAIxD,CAAAA,CAAEO,KAAK,CAAC,CAAA,CAAA,CAAA;AAC3C,IAAA;IACA,OAAOP,CAAAA;AACX;;;;"}
|
package/dist/util/media.js
CHANGED
package/dist/util/media.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media.js","sources":["../../src/util/media.ts"],"sourcesContent":["import ffmpeg from 'fluent-ffmpeg';\nimport { Logger } from 'winston';\nimport path from 'path';\nimport * as Storage from '@/util/storage';\n\nexport interface Media {\n getAudioCreationTime: (filePath: string) => Promise<Date | null>;\n getFileSize: (filePath: string) => Promise<number>;\n splitAudioFile: (filePath: string, outputDir: string, maxSizeBytes: number) => Promise<string[]>;\n}\n\nconst ffprobeAsync = (filePath: string): Promise<any> => {\n return new Promise((resolve, reject) => {\n ffmpeg.ffprobe(filePath, (err, metadata) => {\n if (err) return reject(err);\n resolve(metadata);\n });\n });\n};\n\n\nexport const create = (logger: Logger): Media => {\n const storage = Storage.create({ log: logger.debug });\n\n // Extract creation time from audio file using ffmpeg\n const getAudioCreationTime = async (filePath: string): Promise<Date | null> => {\n try {\n const metadata = await ffprobeAsync(filePath);\n\n // Look for creation_time in format tags\n const formatTags = metadata?.format?.tags;\n if (formatTags?.creation_time) {\n logger.debug('Found creation_time in format tags: %s', formatTags.creation_time);\n return new Date(formatTags.creation_time);\n }\n\n // Check for creation_time in stream tags as fallback\n if (metadata?.streams?.length > 0) {\n for (const stream of metadata.streams) {\n if (stream.tags?.creation_time) {\n logger.debug('Found creation_time in stream tags: %s', stream.tags.creation_time);\n return new Date(stream.tags.creation_time);\n }\n }\n }\n\n logger.debug('No creation_time found in audio file metadata');\n return null;\n } catch (error) {\n logger.error('Error extracting creation time from audio file: %s', error);\n return null;\n }\n };\n\n // Get file size in bytes\n const getFileSize = async (filePath: string): Promise<number> => {\n try {\n return await storage.getFileSize(filePath);\n } catch (error) {\n logger.error('Error getting file size: %s', error);\n throw new Error(`Failed to get file size for ${filePath}: ${error}`);\n }\n };\n\n // Split large audio file into smaller chunks\n const splitAudioFile = async (filePath: string, outputDir: string, maxSizeBytes: number): Promise<string[]> => {\n try {\n const metadata = await ffprobeAsync(filePath);\n const duration = parseFloat(metadata.format.duration);\n\n // Calculate how many segments we need based on file size and max size\n const fileSize = await getFileSize(filePath);\n const segmentCount = Math.ceil(fileSize / maxSizeBytes);\n\n // Calculate segment duration\n const segmentDuration = duration / segmentCount;\n logger.debug(`Splitting ${filePath} (${fileSize} bytes) into ${segmentCount} segments of ~${segmentDuration} seconds each`);\n\n // Create output directory if it doesn't exist\n await storage.createDirectory(outputDir);\n\n const outputFiles: string[] = [];\n const fileExt = path.extname(filePath);\n const fileName = path.basename(filePath, fileExt);\n\n // Create a promise for each segment\n const promises = [];\n\n for (let i = 0; i < segmentCount; i++) {\n const startTime = i * segmentDuration;\n const outputPath = path.join(outputDir, `${fileName}_part${i + 1}${fileExt}`);\n outputFiles.push(outputPath);\n\n const promise = new Promise<void>((resolve, reject) => {\n ffmpeg(filePath)\n .setStartTime(startTime)\n .setDuration(segmentDuration)\n .output(outputPath)\n .on('end', () => {\n logger.debug(`Created segment ${i + 1}/${segmentCount}: ${outputPath}`);\n resolve();\n })\n .on('error', (err) => {\n logger.error(`Error creating segment ${i + 1}/${segmentCount}: ${err}`);\n reject(err);\n })\n .run();\n });\n\n promises.push(promise);\n }\n\n // Wait for all segments to be created\n await Promise.all(promises);\n return outputFiles;\n } catch (error) {\n logger.error('Error splitting audio file: %s', error);\n throw new Error(`Failed to split audio file ${filePath}: ${error}`);\n }\n };\n\n return {\n getAudioCreationTime,\n getFileSize,\n splitAudioFile,\n }\n}\n"],"names":["ffprobeAsync","filePath","Promise","resolve","reject","ffmpeg","ffprobe","err","metadata","create","logger","storage","Storage","log","debug","getAudioCreationTime","formatTags","format","tags","creation_time","Date","streams","length","stream","error","getFileSize","Error","splitAudioFile","outputDir","maxSizeBytes","duration","parseFloat","fileSize","segmentCount","Math","ceil","segmentDuration","createDirectory","outputFiles","fileExt","path","extname","fileName","basename","promises","i","startTime","outputPath","join","push","promise","setStartTime","setDuration","output","on","run","all"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"media.js","sources":["../../src/util/media.ts"],"sourcesContent":["import ffmpeg from 'fluent-ffmpeg';\nimport { Logger } from 'winston';\nimport path from 'node:path';\nimport * as Storage from '@/util/storage';\n\nexport interface Media {\n getAudioCreationTime: (filePath: string) => Promise<Date | null>;\n getFileSize: (filePath: string) => Promise<number>;\n splitAudioFile: (filePath: string, outputDir: string, maxSizeBytes: number) => Promise<string[]>;\n}\n\nconst ffprobeAsync = (filePath: string): Promise<any> => {\n return new Promise((resolve, reject) => {\n ffmpeg.ffprobe(filePath, (err, metadata) => {\n if (err) return reject(err);\n resolve(metadata);\n });\n });\n};\n\n\nexport const create = (logger: Logger): Media => {\n const storage = Storage.create({ log: logger.debug });\n\n // Extract creation time from audio file using ffmpeg\n const getAudioCreationTime = async (filePath: string): Promise<Date | null> => {\n try {\n const metadata = await ffprobeAsync(filePath);\n\n // Look for creation_time in format tags\n const formatTags = metadata?.format?.tags;\n if (formatTags?.creation_time) {\n logger.debug('Found creation_time in format tags: %s', formatTags.creation_time);\n return new Date(formatTags.creation_time);\n }\n\n // Check for creation_time in stream tags as fallback\n if (metadata?.streams?.length > 0) {\n for (const stream of metadata.streams) {\n if (stream.tags?.creation_time) {\n logger.debug('Found creation_time in stream tags: %s', stream.tags.creation_time);\n return new Date(stream.tags.creation_time);\n }\n }\n }\n\n logger.debug('No creation_time found in audio file metadata');\n return null;\n } catch (error) {\n logger.error('Error extracting creation time from audio file: %s', error);\n return null;\n }\n };\n\n // Get file size in bytes\n const getFileSize = async (filePath: string): Promise<number> => {\n try {\n return await storage.getFileSize(filePath);\n } catch (error) {\n logger.error('Error getting file size: %s', error);\n throw new Error(`Failed to get file size for ${filePath}: ${error}`);\n }\n };\n\n // Split large audio file into smaller chunks\n const splitAudioFile = async (filePath: string, outputDir: string, maxSizeBytes: number): Promise<string[]> => {\n try {\n const metadata = await ffprobeAsync(filePath);\n const duration = parseFloat(metadata.format.duration);\n\n // Calculate how many segments we need based on file size and max size\n const fileSize = await getFileSize(filePath);\n const segmentCount = Math.ceil(fileSize / maxSizeBytes);\n\n // Calculate segment duration\n const segmentDuration = duration / segmentCount;\n logger.debug(`Splitting ${filePath} (${fileSize} bytes) into ${segmentCount} segments of ~${segmentDuration} seconds each`);\n\n // Create output directory if it doesn't exist\n await storage.createDirectory(outputDir);\n\n const outputFiles: string[] = [];\n const fileExt = path.extname(filePath);\n const fileName = path.basename(filePath, fileExt);\n\n // Create a promise for each segment\n const promises = [];\n\n for (let i = 0; i < segmentCount; i++) {\n const startTime = i * segmentDuration;\n const outputPath = path.join(outputDir, `${fileName}_part${i + 1}${fileExt}`);\n outputFiles.push(outputPath);\n\n const promise = new Promise<void>((resolve, reject) => {\n ffmpeg(filePath)\n .setStartTime(startTime)\n .setDuration(segmentDuration)\n .output(outputPath)\n .on('end', () => {\n logger.debug(`Created segment ${i + 1}/${segmentCount}: ${outputPath}`);\n resolve();\n })\n .on('error', (err) => {\n logger.error(`Error creating segment ${i + 1}/${segmentCount}: ${err}`);\n reject(err);\n })\n .run();\n });\n\n promises.push(promise);\n }\n\n // Wait for all segments to be created\n await Promise.all(promises);\n return outputFiles;\n } catch (error) {\n logger.error('Error splitting audio file: %s', error);\n throw new Error(`Failed to split audio file ${filePath}: ${error}`);\n }\n };\n\n return {\n getAudioCreationTime,\n getFileSize,\n splitAudioFile,\n }\n}\n"],"names":["ffprobeAsync","filePath","Promise","resolve","reject","ffmpeg","ffprobe","err","metadata","create","logger","storage","Storage","log","debug","getAudioCreationTime","formatTags","format","tags","creation_time","Date","streams","length","stream","error","getFileSize","Error","splitAudioFile","outputDir","maxSizeBytes","duration","parseFloat","fileSize","segmentCount","Math","ceil","segmentDuration","createDirectory","outputFiles","fileExt","path","extname","fileName","basename","promises","i","startTime","outputPath","join","push","promise","setStartTime","setDuration","output","on","run","all"],"mappings":"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"}
|
package/dist/util/storage.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
2
|
import { glob } from 'glob';
|
|
3
|
-
import path__default from 'path';
|
|
4
|
-
import crypto from 'crypto';
|
|
3
|
+
import path__default from 'node:path';
|
|
4
|
+
import crypto from 'node:crypto';
|
|
5
5
|
|
|
6
6
|
// eslint-disable-next-line no-restricted-imports
|
|
7
7
|
const create = (params)=>{
|
package/dist/util/storage.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.js","sources":["../../src/util/storage.ts"],"sourcesContent":["// eslint-disable-next-line no-restricted-imports\nimport * as fs from 'fs';\nimport { glob } from 'glob';\nimport path from 'path';\nimport crypto from 'crypto';\n/**\n * This module exists to isolate filesystem operations from the rest of the codebase.\n * This makes testing easier by avoiding direct fs mocking in jest configuration.\n * \n * Additionally, abstracting storage operations allows for future flexibility - \n * this export utility may need to work with storage systems other than the local filesystem\n * (e.g. S3, Google Cloud Storage, etc).\n */\n\nexport interface Utility {\n exists: (path: string) => Promise<boolean>;\n isDirectory: (path: string) => Promise<boolean>;\n isFile: (path: string) => Promise<boolean>;\n isReadable: (path: string) => Promise<boolean>;\n isWritable: (path: string) => Promise<boolean>;\n isFileReadable: (path: string) => Promise<boolean>;\n isDirectoryWritable: (path: string) => Promise<boolean>;\n isDirectoryReadable: (path: string) => Promise<boolean>;\n createDirectory: (path: string) => Promise<void>;\n readFile: (path: string, encoding: string) => Promise<string>;\n readStream: (path: string) => Promise<fs.ReadStream>;\n writeFile: (path: string, data: string | Buffer, encoding: string) => Promise<void>;\n forEachFileIn: (directory: string, callback: (path: string) => Promise<void>, options?: { pattern: string }) => Promise<void>;\n hashFile: (path: string, length: number) => Promise<string>;\n listFiles: (directory: string) => Promise<string[]>;\n deleteFile: (path: string) => Promise<void>;\n getFileSize: (path: string) => Promise<number>;\n}\n\nexport const create = (params: { log?: (message: string, ...args: any[]) => void }): Utility => {\n\n // eslint-disable-next-line no-console\n const log = params.log || console.log;\n\n const exists = async (path: string): Promise<boolean> => {\n try {\n await fs.promises.stat(path);\n return true;\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n } catch (error: any) {\n return false;\n }\n }\n\n const isDirectory = async (path: string): Promise<boolean> => {\n const stats = await fs.promises.stat(path);\n if (!stats.isDirectory()) {\n log(`${path} is not a directory`);\n return false;\n }\n return true;\n }\n\n const isFile = async (path: string): Promise<boolean> => {\n const stats = await fs.promises.stat(path);\n if (!stats.isFile()) {\n log(`${path} is not a file`);\n return false;\n }\n return true;\n }\n\n const isReadable = async (path: string): Promise<boolean> => {\n try {\n await fs.promises.access(path, fs.constants.R_OK);\n } catch (error: any) {\n log(`${path} is not readable: %s %s`, error.message, error.stack);\n return false;\n }\n return true;\n }\n\n const isWritable = async (path: string): Promise<boolean> => {\n try {\n await fs.promises.access(path, fs.constants.W_OK);\n } catch (error: any) {\n log(`${path} is not writable: %s %s`, error.message, error.stack);\n return false;\n }\n return true;\n }\n\n const isFileReadable = async (path: string): Promise<boolean> => {\n return await exists(path) && await isFile(path) && await isReadable(path);\n }\n\n const isDirectoryWritable = async (path: string): Promise<boolean> => {\n return await exists(path) && await isDirectory(path) && await isWritable(path);\n }\n\n const isDirectoryReadable = async (path: string): Promise<boolean> => {\n return await exists(path) && await isDirectory(path) && await isReadable(path);\n }\n\n const createDirectory = async (path: string): Promise<void> => {\n try {\n await fs.promises.mkdir(path, { recursive: true });\n } catch (mkdirError: any) {\n throw new Error(`Failed to create output directory ${path}: ${mkdirError.message} ${mkdirError.stack}`);\n }\n }\n\n const readFile = async (path: string, encoding: string): Promise<string> => {\n return await fs.promises.readFile(path, { encoding: encoding as BufferEncoding });\n }\n\n const writeFile = async (path: string, data: string | Buffer, encoding: string): Promise<void> => {\n await fs.promises.writeFile(path, data, { encoding: encoding as BufferEncoding });\n }\n\n const forEachFileIn = async (directory: string, callback: (file: string) => Promise<void>, options: { pattern: string | string[] } = { pattern: '*.*' }): Promise<void> => {\n try {\n const files = await glob(options.pattern, { cwd: directory, nodir: true });\n for (const file of files) {\n await callback(path.join(directory, file));\n }\n } catch (err: any) {\n throw new Error(`Failed to glob pattern ${options.pattern} in ${directory}: ${err.message}`);\n }\n }\n\n const readStream = async (path: string): Promise<fs.ReadStream> => {\n return fs.createReadStream(path);\n }\n\n const hashFile = async (path: string, length: number): Promise<string> => {\n const file = await readFile(path, 'utf8');\n return crypto.createHash('sha256').update(file).digest('hex').slice(0, length);\n }\n\n const listFiles = async (directory: string): Promise<string[]> => {\n return await fs.promises.readdir(directory);\n }\n\n const deleteFile = async (path: string): Promise<void> => {\n await fs.promises.unlink(path);\n }\n\n const getFileSize = async (path: string): Promise<number> => {\n const stats = await fs.promises.stat(path);\n return stats.size;\n }\n\n return {\n exists,\n isDirectory,\n isFile,\n isReadable,\n isWritable,\n isFileReadable,\n isDirectoryWritable,\n isDirectoryReadable,\n createDirectory,\n readFile,\n readStream,\n writeFile,\n forEachFileIn,\n hashFile,\n listFiles,\n deleteFile,\n getFileSize,\n };\n}"],"names":["create","params","log","console","exists","path","fs","promises","stat","error","isDirectory","stats","isFile","isReadable","access","constants","R_OK","message","stack","isWritable","W_OK","isFileReadable","isDirectoryWritable","isDirectoryReadable","createDirectory","mkdir","recursive","mkdirError","Error","readFile","encoding","writeFile","data","forEachFileIn","directory","callback","options","pattern","files","glob","cwd","nodir","file","join","err","readStream","createReadStream","hashFile","length","crypto","createHash","update","digest","slice","listFiles","readdir","deleteFile","unlink","getFileSize","size"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"storage.js","sources":["../../src/util/storage.ts"],"sourcesContent":["// eslint-disable-next-line no-restricted-imports\nimport * as fs from 'node:fs';\nimport { glob } from 'glob';\nimport path from 'node:path';\nimport crypto from 'node:crypto';\n/**\n * This module exists to isolate filesystem operations from the rest of the codebase.\n * This makes testing easier by avoiding direct fs mocking in jest configuration.\n * \n * Additionally, abstracting storage operations allows for future flexibility - \n * this export utility may need to work with storage systems other than the local filesystem\n * (e.g. S3, Google Cloud Storage, etc).\n */\n\nexport interface Utility {\n exists: (path: string) => Promise<boolean>;\n isDirectory: (path: string) => Promise<boolean>;\n isFile: (path: string) => Promise<boolean>;\n isReadable: (path: string) => Promise<boolean>;\n isWritable: (path: string) => Promise<boolean>;\n isFileReadable: (path: string) => Promise<boolean>;\n isDirectoryWritable: (path: string) => Promise<boolean>;\n isDirectoryReadable: (path: string) => Promise<boolean>;\n createDirectory: (path: string) => Promise<void>;\n readFile: (path: string, encoding: string) => Promise<string>;\n readStream: (path: string) => Promise<fs.ReadStream>;\n writeFile: (path: string, data: string | Buffer, encoding: string) => Promise<void>;\n forEachFileIn: (directory: string, callback: (path: string) => Promise<void>, options?: { pattern: string }) => Promise<void>;\n hashFile: (path: string, length: number) => Promise<string>;\n listFiles: (directory: string) => Promise<string[]>;\n deleteFile: (path: string) => Promise<void>;\n getFileSize: (path: string) => Promise<number>;\n}\n\nexport const create = (params: { log?: (message: string, ...args: any[]) => void }): Utility => {\n\n // eslint-disable-next-line no-console\n const log = params.log || console.log;\n\n const exists = async (path: string): Promise<boolean> => {\n try {\n await fs.promises.stat(path);\n return true;\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n } catch (error: any) {\n return false;\n }\n }\n\n const isDirectory = async (path: string): Promise<boolean> => {\n const stats = await fs.promises.stat(path);\n if (!stats.isDirectory()) {\n log(`${path} is not a directory`);\n return false;\n }\n return true;\n }\n\n const isFile = async (path: string): Promise<boolean> => {\n const stats = await fs.promises.stat(path);\n if (!stats.isFile()) {\n log(`${path} is not a file`);\n return false;\n }\n return true;\n }\n\n const isReadable = async (path: string): Promise<boolean> => {\n try {\n await fs.promises.access(path, fs.constants.R_OK);\n } catch (error: any) {\n log(`${path} is not readable: %s %s`, error.message, error.stack);\n return false;\n }\n return true;\n }\n\n const isWritable = async (path: string): Promise<boolean> => {\n try {\n await fs.promises.access(path, fs.constants.W_OK);\n } catch (error: any) {\n log(`${path} is not writable: %s %s`, error.message, error.stack);\n return false;\n }\n return true;\n }\n\n const isFileReadable = async (path: string): Promise<boolean> => {\n return await exists(path) && await isFile(path) && await isReadable(path);\n }\n\n const isDirectoryWritable = async (path: string): Promise<boolean> => {\n return await exists(path) && await isDirectory(path) && await isWritable(path);\n }\n\n const isDirectoryReadable = async (path: string): Promise<boolean> => {\n return await exists(path) && await isDirectory(path) && await isReadable(path);\n }\n\n const createDirectory = async (path: string): Promise<void> => {\n try {\n await fs.promises.mkdir(path, { recursive: true });\n } catch (mkdirError: any) {\n throw new Error(`Failed to create output directory ${path}: ${mkdirError.message} ${mkdirError.stack}`);\n }\n }\n\n const readFile = async (path: string, encoding: string): Promise<string> => {\n return await fs.promises.readFile(path, { encoding: encoding as BufferEncoding });\n }\n\n const writeFile = async (path: string, data: string | Buffer, encoding: string): Promise<void> => {\n await fs.promises.writeFile(path, data, { encoding: encoding as BufferEncoding });\n }\n\n const forEachFileIn = async (directory: string, callback: (file: string) => Promise<void>, options: { pattern: string | string[] } = { pattern: '*.*' }): Promise<void> => {\n try {\n const files = await glob(options.pattern, { cwd: directory, nodir: true });\n for (const file of files) {\n await callback(path.join(directory, file));\n }\n } catch (err: any) {\n throw new Error(`Failed to glob pattern ${options.pattern} in ${directory}: ${err.message}`);\n }\n }\n\n const readStream = async (path: string): Promise<fs.ReadStream> => {\n return fs.createReadStream(path);\n }\n\n const hashFile = async (path: string, length: number): Promise<string> => {\n const file = await readFile(path, 'utf8');\n return crypto.createHash('sha256').update(file).digest('hex').slice(0, length);\n }\n\n const listFiles = async (directory: string): Promise<string[]> => {\n return await fs.promises.readdir(directory);\n }\n\n const deleteFile = async (path: string): Promise<void> => {\n await fs.promises.unlink(path);\n }\n\n const getFileSize = async (path: string): Promise<number> => {\n const stats = await fs.promises.stat(path);\n return stats.size;\n }\n\n return {\n exists,\n isDirectory,\n isFile,\n isReadable,\n isWritable,\n isFileReadable,\n isDirectoryWritable,\n isDirectoryReadable,\n createDirectory,\n readFile,\n readStream,\n writeFile,\n forEachFileIn,\n hashFile,\n listFiles,\n deleteFile,\n getFileSize,\n };\n}"],"names":["create","params","log","console","exists","path","fs","promises","stat","error","isDirectory","stats","isFile","isReadable","access","constants","R_OK","message","stack","isWritable","W_OK","isFileReadable","isDirectoryWritable","isDirectoryReadable","createDirectory","mkdir","recursive","mkdirError","Error","readFile","encoding","writeFile","data","forEachFileIn","directory","callback","options","pattern","files","glob","cwd","nodir","file","join","err","readStream","createReadStream","hashFile","length","crypto","createHash","update","digest","slice","listFiles","readdir","deleteFile","unlink","getFileSize","size"],"mappings":"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"}
|
package/eslint.config.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redaksjon/protokoll",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.12",
|
|
4
4
|
"description": "Focused audio transcription with intelligent context integration",
|
|
5
5
|
"main": "dist/main.js",
|
|
6
6
|
"type": "module",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
},
|
|
14
14
|
"homepage": "https://github.com/redaksjon/protokoll",
|
|
15
15
|
"scripts": {
|
|
16
|
-
"build": "npm run lint && tsc --noEmit && vite build &&
|
|
16
|
+
"build": "npm run lint && tsc --noEmit && vite build && node scripts/copy-assets.mjs && chmod +x dist/main.js",
|
|
17
17
|
"dev": "vite",
|
|
18
18
|
"watch": "vite build --watch",
|
|
19
19
|
"test": "vitest run --coverage",
|
|
@@ -33,8 +33,7 @@
|
|
|
33
33
|
"author": "Tim O'Brien <tobrien@discursive.com>",
|
|
34
34
|
"license": "Apache-2.0",
|
|
35
35
|
"engines": {
|
|
36
|
-
"node": ">=
|
|
37
|
-
"npm": ">=9.0.0"
|
|
36
|
+
"node": ">=24.0.0"
|
|
38
37
|
},
|
|
39
38
|
"dependencies": {
|
|
40
39
|
"@anthropic-ai/sdk": "^0.71.2",
|
|
@@ -66,7 +65,6 @@
|
|
|
66
65
|
"@typescript-eslint/eslint-plugin": "^8.46.4",
|
|
67
66
|
"@typescript-eslint/parser": "^8.46.4",
|
|
68
67
|
"@vitest/coverage-v8": "^4.0.8",
|
|
69
|
-
"copyfiles": "^2.4.1",
|
|
70
68
|
"eslint": "^9.39.1",
|
|
71
69
|
"eslint-plugin-import": "^2.32.0",
|
|
72
70
|
"globals": "^17.0.0",
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* eslint-disable no-console */
|
|
3
|
+
/**
|
|
4
|
+
* Native Node.js script to copy .md files from src/ to dist/
|
|
5
|
+
* Replaces the copyfiles dependency for Node 24+
|
|
6
|
+
*/
|
|
7
|
+
import { cp, mkdir } from 'node:fs/promises';
|
|
8
|
+
import { dirname, join, relative } from 'node:path';
|
|
9
|
+
import { glob } from 'glob';
|
|
10
|
+
import { fileURLToPath } from 'node:url';
|
|
11
|
+
|
|
12
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
const projectRoot = join(__dirname, '..');
|
|
14
|
+
const srcDir = join(projectRoot, 'src');
|
|
15
|
+
const distDir = join(projectRoot, 'dist');
|
|
16
|
+
|
|
17
|
+
async function copyAssets() {
|
|
18
|
+
// Find all .md files in src/
|
|
19
|
+
const mdFiles = await glob('**/*.md', { cwd: srcDir });
|
|
20
|
+
|
|
21
|
+
if (mdFiles.length === 0) {
|
|
22
|
+
console.log('No .md files found in src/');
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
console.log(`Copying ${mdFiles.length} .md files to dist/...`);
|
|
27
|
+
|
|
28
|
+
for (const file of mdFiles) {
|
|
29
|
+
const srcPath = join(srcDir, file);
|
|
30
|
+
const destPath = join(distDir, file);
|
|
31
|
+
|
|
32
|
+
// Ensure destination directory exists
|
|
33
|
+
await mkdir(dirname(destPath), { recursive: true });
|
|
34
|
+
|
|
35
|
+
// Copy the file
|
|
36
|
+
await cp(srcPath, destPath);
|
|
37
|
+
console.log(` ${relative(projectRoot, srcPath)} → ${relative(projectRoot, destPath)}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
console.log('Done.');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
copyAssets().catch((err) => {
|
|
44
|
+
console.error('Error copying assets:', err);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
});
|
|
47
|
+
|