@redaksjon/protokoll 0.0.8 → 0.0.10
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/.cursor/rules/definition-of-done.md +89 -0
- package/.cursor/rules/no-emoticons.md +43 -0
- package/LICENSE +1 -1
- package/README.md +928 -35
- package/dist/agentic/executor.js +315 -0
- package/dist/agentic/executor.js.map +1 -0
- package/dist/agentic/index.js +19 -0
- package/dist/agentic/index.js.map +1 -0
- package/dist/agentic/registry.js +41 -0
- package/dist/agentic/registry.js.map +1 -0
- package/dist/agentic/tools/lookup-person.js +66 -0
- package/dist/agentic/tools/lookup-person.js.map +1 -0
- package/dist/agentic/tools/lookup-project.js +93 -0
- package/dist/agentic/tools/lookup-project.js.map +1 -0
- package/dist/agentic/tools/route-note.js +45 -0
- package/dist/agentic/tools/route-note.js.map +1 -0
- package/dist/agentic/tools/store-context.js +51 -0
- package/dist/agentic/tools/store-context.js.map +1 -0
- package/dist/agentic/tools/verify-spelling.js +57 -0
- package/dist/agentic/tools/verify-spelling.js.map +1 -0
- package/dist/arguments.js +23 -6
- package/dist/arguments.js.map +1 -1
- package/dist/constants.js +13 -11
- package/dist/constants.js.map +1 -1
- package/dist/context/discovery.js +114 -0
- package/dist/context/discovery.js.map +1 -0
- package/dist/context/index.js +58 -0
- package/dist/context/index.js.map +1 -0
- package/dist/context/storage.js +131 -0
- package/dist/context/storage.js.map +1 -0
- package/dist/interactive/handler.js +223 -0
- package/dist/interactive/handler.js.map +1 -0
- package/dist/interactive/index.js +18 -0
- package/dist/interactive/index.js.map +1 -0
- package/dist/interactive/onboarding.js +28 -0
- package/dist/interactive/onboarding.js.map +1 -0
- package/dist/main.js +0 -0
- package/dist/output/index.js +8 -0
- package/dist/output/index.js.map +1 -0
- package/dist/output/manager.js +105 -0
- package/dist/output/manager.js.map +1 -0
- package/dist/phases/complete.js +107 -0
- package/dist/phases/complete.js.map +1 -0
- package/dist/phases/locate.js +14 -5
- package/dist/phases/locate.js.map +1 -1
- package/dist/pipeline/index.js +8 -0
- package/dist/pipeline/index.js.map +1 -0
- package/dist/pipeline/orchestrator.js +281 -0
- package/dist/pipeline/orchestrator.js.map +1 -0
- package/dist/prompt/instructions/transcribe.md +6 -6
- package/dist/prompt/personas/transcriber.md +5 -5
- package/dist/protokoll.js +38 -5
- package/dist/protokoll.js.map +1 -1
- package/dist/reasoning/client.js +150 -0
- package/dist/reasoning/client.js.map +1 -0
- package/dist/reasoning/index.js +36 -0
- package/dist/reasoning/index.js.map +1 -0
- package/dist/reasoning/strategy.js +60 -0
- package/dist/reasoning/strategy.js.map +1 -0
- package/dist/reflection/collector.js +124 -0
- package/dist/reflection/collector.js.map +1 -0
- package/dist/reflection/index.js +16 -0
- package/dist/reflection/index.js.map +1 -0
- package/dist/reflection/reporter.js +238 -0
- package/dist/reflection/reporter.js.map +1 -0
- package/dist/routing/classifier.js +201 -0
- package/dist/routing/classifier.js.map +1 -0
- package/dist/routing/index.js +27 -0
- package/dist/routing/index.js.map +1 -0
- package/dist/routing/router.js +153 -0
- package/dist/routing/router.js.map +1 -0
- package/dist/transcription/index.js +41 -0
- package/dist/transcription/index.js.map +1 -0
- package/dist/transcription/service.js +64 -0
- package/dist/transcription/service.js.map +1 -0
- package/dist/transcription/types.js +31 -0
- package/dist/transcription/types.js.map +1 -0
- package/dist/util/media.js +4 -4
- package/dist/util/media.js.map +1 -1
- package/dist/util/metadata.js +95 -0
- package/dist/util/metadata.js.map +1 -0
- package/dist/util/storage.js +2 -2
- package/dist/util/storage.js.map +1 -1
- package/docs/examples.md +224 -0
- package/docs/index.html +5 -3
- package/docs/package-lock.json +639 -332
- package/docs/package.json +5 -4
- package/docs/troubleshooting.md +257 -0
- package/docs/vite.config.js +9 -3
- package/eslint.config.mjs +1 -0
- package/guide/architecture.md +217 -0
- package/guide/configuration.md +199 -0
- package/guide/context-system.md +215 -0
- package/guide/development.md +273 -0
- package/guide/index.md +91 -0
- package/guide/interactive.md +199 -0
- package/guide/quickstart.md +138 -0
- package/guide/reasoning.md +193 -0
- package/guide/routing.md +222 -0
- package/package.json +10 -7
- package/tsconfig.tsbuildinfo +1 -1
- package/vitest.config.ts +27 -5
- package/dist/phases/transcribe.js +0 -149
- package/dist/phases/transcribe.js.map +0 -1
- package/dist/processor.js +0 -35
- package/dist/processor.js.map +0 -1
- package/dist/prompt/transcribe.js +0 -41
- package/dist/prompt/transcribe.js.map +0 -1
- package/dist/util/general.js +0 -39
- package/dist/util/general.js.map +0 -1
- package/dist/util/openai.js +0 -92
- package/dist/util/openai.js.map +0 -1
package/dist/util/media.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import ffmpeg from 'fluent-ffmpeg';
|
|
2
|
-
import
|
|
2
|
+
import path__default from 'path';
|
|
3
3
|
import { create as create$1 } from './storage.js';
|
|
4
4
|
|
|
5
5
|
const ffprobeAsync = (filePath)=>{
|
|
@@ -65,13 +65,13 @@ const create = (logger)=>{
|
|
|
65
65
|
// Create output directory if it doesn't exist
|
|
66
66
|
await storage.createDirectory(outputDir);
|
|
67
67
|
const outputFiles = [];
|
|
68
|
-
const fileExt =
|
|
69
|
-
const fileName =
|
|
68
|
+
const fileExt = path__default.extname(filePath);
|
|
69
|
+
const fileName = path__default.basename(filePath, fileExt);
|
|
70
70
|
// Create a promise for each segment
|
|
71
71
|
const promises = [];
|
|
72
72
|
for(let i = 0; i < segmentCount; i++){
|
|
73
73
|
const startTime = i * segmentDuration;
|
|
74
|
-
const outputPath =
|
|
74
|
+
const outputPath = path__default.join(outputDir, `${fileName}_part${i + 1}${fileExt}`);
|
|
75
75
|
outputFiles.push(outputPath);
|
|
76
76
|
const promise = new Promise((resolve, reject)=>{
|
|
77
77
|
ffmpeg(filePath).setStartTime(startTime).setDuration(segmentDuration).output(outputPath).on('end', ()=>{
|
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 '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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"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format metadata as Markdown heading section
|
|
3
|
+
*/ const formatMetadataMarkdown = (metadata)=>{
|
|
4
|
+
const lines = [];
|
|
5
|
+
// Title section
|
|
6
|
+
if (metadata.title) {
|
|
7
|
+
lines.push(`# ${metadata.title}`);
|
|
8
|
+
lines.push('');
|
|
9
|
+
}
|
|
10
|
+
// Metadata frontmatter as readable markdown
|
|
11
|
+
lines.push('## Metadata');
|
|
12
|
+
lines.push('');
|
|
13
|
+
// Date and Time
|
|
14
|
+
if (metadata.date) {
|
|
15
|
+
const dateStr = metadata.date.toLocaleDateString('en-US', {
|
|
16
|
+
year: 'numeric',
|
|
17
|
+
month: 'long',
|
|
18
|
+
day: 'numeric'
|
|
19
|
+
});
|
|
20
|
+
lines.push(`**Date**: ${dateStr}`);
|
|
21
|
+
if (metadata.recordingTime) {
|
|
22
|
+
lines.push(`**Time**: ${metadata.recordingTime}`);
|
|
23
|
+
} else {
|
|
24
|
+
const timeStr = metadata.date.toLocaleTimeString('en-US', {
|
|
25
|
+
hour: '2-digit',
|
|
26
|
+
minute: '2-digit',
|
|
27
|
+
hour12: true
|
|
28
|
+
});
|
|
29
|
+
lines.push(`**Time**: ${timeStr}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
lines.push('');
|
|
33
|
+
// Project
|
|
34
|
+
if (metadata.project) {
|
|
35
|
+
lines.push(`**Project**: ${metadata.project}`);
|
|
36
|
+
if (metadata.projectId) {
|
|
37
|
+
lines.push(`**Project ID**: \`${metadata.projectId}\``);
|
|
38
|
+
}
|
|
39
|
+
lines.push('');
|
|
40
|
+
}
|
|
41
|
+
// Routing Information
|
|
42
|
+
if (metadata.routing) {
|
|
43
|
+
lines.push('### Routing');
|
|
44
|
+
lines.push('');
|
|
45
|
+
lines.push(`**Destination**: ${metadata.routing.destination}`);
|
|
46
|
+
lines.push(`**Confidence**: ${(metadata.routing.confidence * 100).toFixed(1)}%`);
|
|
47
|
+
lines.push('');
|
|
48
|
+
if (metadata.routing.signals.length > 0) {
|
|
49
|
+
lines.push('**Classification Signals**:');
|
|
50
|
+
for (const signal of metadata.routing.signals){
|
|
51
|
+
const signalType = signal.type.replace(/_/g, ' ');
|
|
52
|
+
const weight = (signal.weight * 100).toFixed(0);
|
|
53
|
+
lines.push(`- ${signalType}: "${signal.value}" (${weight}% weight)`);
|
|
54
|
+
}
|
|
55
|
+
lines.push('');
|
|
56
|
+
}
|
|
57
|
+
if (metadata.routing.reasoning) {
|
|
58
|
+
lines.push(`**Reasoning**: ${metadata.routing.reasoning}`);
|
|
59
|
+
lines.push('');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Tags
|
|
63
|
+
if (metadata.tags && metadata.tags.length > 0) {
|
|
64
|
+
lines.push('**Tags**: ' + metadata.tags.map((tag)=>`\`${tag}\``).join(', '));
|
|
65
|
+
lines.push('');
|
|
66
|
+
}
|
|
67
|
+
// Duration
|
|
68
|
+
if (metadata.duration) {
|
|
69
|
+
lines.push(`**Duration**: ${metadata.duration}`);
|
|
70
|
+
lines.push('');
|
|
71
|
+
}
|
|
72
|
+
// Separator
|
|
73
|
+
lines.push('---');
|
|
74
|
+
lines.push('');
|
|
75
|
+
return lines.join('\n');
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Extract routing metadata from a RouteDecision
|
|
79
|
+
*/ const createRoutingMetadata = (decision)=>{
|
|
80
|
+
return {
|
|
81
|
+
destination: decision.destination.path,
|
|
82
|
+
confidence: decision.confidence,
|
|
83
|
+
signals: decision.signals,
|
|
84
|
+
reasoning: decision.reasoning
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Extract all tags from routing signals
|
|
89
|
+
*/ const extractTagsFromSignals = (signals)=>{
|
|
90
|
+
return signals.filter((s)=>s.type !== 'context_type') // Skip generic context type
|
|
91
|
+
.map((s)=>s.value).filter((v)=>typeof v === 'string');
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export { createRoutingMetadata, extractTagsFromSignals, formatMetadataMarkdown };
|
|
95
|
+
//# sourceMappingURL=metadata.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata.js","sources":["../../src/util/metadata.ts"],"sourcesContent":["import * as Routing from '@/routing';\n\nexport interface TranscriptMetadata {\n title?: string;\n project?: string;\n projectId?: string;\n routing?: RoutingMetadata;\n tags?: string[];\n date?: Date;\n recordingTime?: string;\n confidence?: number;\n duration?: string;\n}\n\nexport interface RoutingMetadata {\n destination: string;\n confidence: number;\n signals: Routing.ClassificationSignal[];\n reasoning: string;\n}\n\n/**\n * Format metadata as Markdown heading section\n */\nexport const formatMetadataMarkdown = (metadata: TranscriptMetadata): string => {\n const lines: string[] = [];\n \n // Title section\n if (metadata.title) {\n lines.push(`# ${metadata.title}`);\n lines.push('');\n }\n \n // Metadata frontmatter as readable markdown\n lines.push('## Metadata');\n lines.push('');\n \n // Date and Time\n if (metadata.date) {\n const dateStr = metadata.date.toLocaleDateString('en-US', {\n year: 'numeric',\n month: 'long',\n day: 'numeric'\n });\n lines.push(`**Date**: ${dateStr}`);\n \n if (metadata.recordingTime) {\n lines.push(`**Time**: ${metadata.recordingTime}`);\n } else {\n const timeStr = metadata.date.toLocaleTimeString('en-US', {\n hour: '2-digit',\n minute: '2-digit',\n hour12: true\n });\n lines.push(`**Time**: ${timeStr}`);\n }\n }\n \n lines.push('');\n \n // Project\n if (metadata.project) {\n lines.push(`**Project**: ${metadata.project}`);\n if (metadata.projectId) {\n lines.push(`**Project ID**: \\`${metadata.projectId}\\``);\n }\n lines.push('');\n }\n \n // Routing Information\n if (metadata.routing) {\n lines.push('### Routing');\n lines.push('');\n lines.push(`**Destination**: ${metadata.routing.destination}`);\n lines.push(`**Confidence**: ${(metadata.routing.confidence * 100).toFixed(1)}%`);\n lines.push('');\n \n if (metadata.routing.signals.length > 0) {\n lines.push('**Classification Signals**:');\n for (const signal of metadata.routing.signals) {\n const signalType = signal.type.replace(/_/g, ' ');\n const weight = (signal.weight * 100).toFixed(0);\n lines.push(`- ${signalType}: \"${signal.value}\" (${weight}% weight)`);\n }\n lines.push('');\n }\n \n if (metadata.routing.reasoning) {\n lines.push(`**Reasoning**: ${metadata.routing.reasoning}`);\n lines.push('');\n }\n }\n \n // Tags\n if (metadata.tags && metadata.tags.length > 0) {\n lines.push('**Tags**: ' + metadata.tags.map(tag => `\\`${tag}\\``).join(', '));\n lines.push('');\n }\n \n // Duration\n if (metadata.duration) {\n lines.push(`**Duration**: ${metadata.duration}`);\n lines.push('');\n }\n \n // Separator\n lines.push('---');\n lines.push('');\n \n return lines.join('\\n');\n};\n\n/**\n * Extract routing metadata from a RouteDecision\n */\nexport const createRoutingMetadata = (decision: Routing.RouteDecision): RoutingMetadata => {\n return {\n destination: decision.destination.path,\n confidence: decision.confidence,\n signals: decision.signals,\n reasoning: decision.reasoning,\n };\n};\n\n/**\n * Format duration in seconds to readable format (e.g., \"2m 30s\")\n */\nexport const formatDuration = (seconds: number): string => {\n const minutes = Math.floor(seconds / 60);\n const secs = Math.round(seconds % 60);\n \n if (minutes === 0) {\n return `${secs}s`;\n }\n \n if (secs === 0) {\n return `${minutes}m`;\n }\n \n return `${minutes}m ${secs}s`;\n};\n\n/**\n * Format time as HH:MM AM/PM\n */\nexport const formatTime = (date: Date): string => {\n return date.toLocaleTimeString('en-US', {\n hour: '2-digit',\n minute: '2-digit',\n hour12: true\n });\n};\n\n/**\n * Extract topic from routing signals\n */\nexport const extractTopicFromSignals = (signals: Routing.ClassificationSignal[]): string | undefined => {\n const topicSignal = signals.find(s => s.type === 'topic' || s.type === 'context_type');\n return topicSignal?.value;\n};\n\n/**\n * Extract all tags from routing signals\n */\nexport const extractTagsFromSignals = (signals: Routing.ClassificationSignal[]): string[] => {\n return signals\n .filter(s => s.type !== 'context_type') // Skip generic context type\n .map(s => s.value)\n .filter((v): v is string => typeof v === 'string');\n};\n\n"],"names":["formatMetadataMarkdown","metadata","lines","title","push","date","dateStr","toLocaleDateString","year","month","day","recordingTime","timeStr","toLocaleTimeString","hour","minute","hour12","project","projectId","routing","destination","confidence","toFixed","signals","length","signal","signalType","type","replace","weight","value","reasoning","tags","map","tag","join","duration","createRoutingMetadata","decision","path","extractTagsFromSignals","filter","s","v"],"mappings":"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"}
|
package/dist/util/storage.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import { glob } from 'glob';
|
|
3
|
-
import
|
|
3
|
+
import path__default from 'path';
|
|
4
4
|
import crypto from 'crypto';
|
|
5
5
|
|
|
6
6
|
// eslint-disable-next-line no-restricted-imports
|
|
@@ -87,7 +87,7 @@ const create = (params)=>{
|
|
|
87
87
|
nodir: true
|
|
88
88
|
});
|
|
89
89
|
for (const file of files){
|
|
90
|
-
await callback(
|
|
90
|
+
await callback(path__default.join(directory, file));
|
|
91
91
|
}
|
|
92
92
|
} catch (err) {
|
|
93
93
|
throw new Error(`Failed to glob pattern ${options.pattern} in ${directory}: ${err.message}`);
|
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 '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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"}
|
package/docs/examples.md
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# Protokoll Usage Examples
|
|
2
|
+
|
|
3
|
+
## Scenario 1: Daily Voice Notes
|
|
4
|
+
|
|
5
|
+
You record voice notes during your commute. Want them organized by date.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Simple daily processing
|
|
9
|
+
protokoll --input-directory ~/Voice\ Memos --output-directory ~/notes
|
|
10
|
+
|
|
11
|
+
# Result: ~/notes/2026/01/11-commute-thoughts.md
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Scenario 2: Work Project Notes
|
|
15
|
+
|
|
16
|
+
Notes about specific work projects should go to project directories.
|
|
17
|
+
|
|
18
|
+
```yaml
|
|
19
|
+
# ~/.protokoll/config.yaml
|
|
20
|
+
routing:
|
|
21
|
+
projects:
|
|
22
|
+
- projectId: "projectA"
|
|
23
|
+
destination:
|
|
24
|
+
path: "~/work/projectA/notes"
|
|
25
|
+
structure: "month"
|
|
26
|
+
triggers:
|
|
27
|
+
- "projectA note"
|
|
28
|
+
- "about projectA"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Your recording: "This is a note about projectA..."
|
|
33
|
+
protokoll --input-directory ~/recordings
|
|
34
|
+
|
|
35
|
+
# Result: ~/work/projectA/notes/2026/01-meeting.md
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Scenario 3: Learning New Names
|
|
39
|
+
|
|
40
|
+
First time mentioning a colleague in recordings.
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Interactive mode
|
|
44
|
+
protokoll --input-directory ~/recordings --interactive
|
|
45
|
+
|
|
46
|
+
# Protokoll asks:
|
|
47
|
+
# "Unknown name 'Sarah Chen'. Correct spelling?"
|
|
48
|
+
# You answer, it remembers for next time
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Scenario 4: Debugging Issues
|
|
52
|
+
|
|
53
|
+
Something isn't working right.
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
protokoll --input-directory ~/recordings \
|
|
57
|
+
--debug \
|
|
58
|
+
--self-reflection \
|
|
59
|
+
--verbose
|
|
60
|
+
|
|
61
|
+
# Check output/protokoll/ for:
|
|
62
|
+
# - Raw Whisper output
|
|
63
|
+
# - LLM requests/responses
|
|
64
|
+
# - Self-reflection report
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Scenario 5: Multiple Projects
|
|
68
|
+
|
|
69
|
+
You work on several projects and want automatic routing.
|
|
70
|
+
|
|
71
|
+
```yaml
|
|
72
|
+
# ~/.protokoll/config.yaml
|
|
73
|
+
routing:
|
|
74
|
+
default:
|
|
75
|
+
path: "~/notes/personal"
|
|
76
|
+
structure: "month"
|
|
77
|
+
|
|
78
|
+
projects:
|
|
79
|
+
- projectId: "work"
|
|
80
|
+
destination:
|
|
81
|
+
path: "~/work/notes"
|
|
82
|
+
structure: "month"
|
|
83
|
+
triggers:
|
|
84
|
+
- "work note"
|
|
85
|
+
- "office meeting"
|
|
86
|
+
- "standup"
|
|
87
|
+
|
|
88
|
+
- projectId: "side-project"
|
|
89
|
+
destination:
|
|
90
|
+
path: "~/projects/side-project/notes"
|
|
91
|
+
structure: "day"
|
|
92
|
+
triggers:
|
|
93
|
+
- "side project"
|
|
94
|
+
- "weekend coding"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# All recordings get routed automatically
|
|
99
|
+
protokoll --input-directory ~/recordings --recursive
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Scenario 6: Team Context
|
|
103
|
+
|
|
104
|
+
Share context across a team project.
|
|
105
|
+
|
|
106
|
+
```yaml
|
|
107
|
+
# ~/team-project/.protokoll/people/alice.yaml
|
|
108
|
+
id: alice
|
|
109
|
+
name: Alice Johnson
|
|
110
|
+
role: Tech Lead
|
|
111
|
+
sounds_like:
|
|
112
|
+
- "alice"
|
|
113
|
+
- "al"
|
|
114
|
+
context: "Project tech lead"
|
|
115
|
+
|
|
116
|
+
# ~/team-project/.protokoll/people/bob.yaml
|
|
117
|
+
id: bob
|
|
118
|
+
name: Bob Smith
|
|
119
|
+
role: Designer
|
|
120
|
+
sounds_like:
|
|
121
|
+
- "bob"
|
|
122
|
+
- "bobby"
|
|
123
|
+
context: "UI/UX designer"
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
# Process from within project directory
|
|
128
|
+
cd ~/team-project
|
|
129
|
+
protokoll --input-directory ./recordings
|
|
130
|
+
|
|
131
|
+
# Protokoll finds .protokoll/ context automatically
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Scenario 7: Batch Processing
|
|
135
|
+
|
|
136
|
+
Process a backlog of recordings overnight.
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
# Process all recordings without interaction
|
|
140
|
+
protokoll --input-directory ~/backlog \
|
|
141
|
+
--batch \
|
|
142
|
+
--recursive \
|
|
143
|
+
--output-directory ~/processed-notes
|
|
144
|
+
|
|
145
|
+
# Or with a delay to avoid rate limits
|
|
146
|
+
protokoll --input-directory ~/backlog --batch
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Scenario 8: Quality Review
|
|
150
|
+
|
|
151
|
+
Review transcription quality after processing.
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
# Enable self-reflection
|
|
155
|
+
protokoll --input-directory ~/recordings --self-reflection
|
|
156
|
+
|
|
157
|
+
# Check the reflection report
|
|
158
|
+
cat output/protokoll/*-reflection.md
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Example output:
|
|
162
|
+
```markdown
|
|
163
|
+
# Protokoll - Self-Reflection Report
|
|
164
|
+
|
|
165
|
+
## Summary
|
|
166
|
+
- Duration: 12.5s
|
|
167
|
+
- Iterations: 8
|
|
168
|
+
- Tool Calls: 5
|
|
169
|
+
- Confidence: 94.2%
|
|
170
|
+
|
|
171
|
+
## Recommendations
|
|
172
|
+
### 🟢 Low Priority
|
|
173
|
+
1. **Processing took 12.5s**
|
|
174
|
+
- Consider reducing max iterations for shorter transcripts
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Scenario 9: Custom Model Selection
|
|
178
|
+
|
|
179
|
+
Use different models for different quality/speed tradeoffs.
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
# Fast processing with smaller model
|
|
183
|
+
protokoll --input-directory ~/quick-notes --model gpt-4o-mini
|
|
184
|
+
|
|
185
|
+
# High quality with larger model
|
|
186
|
+
protokoll --input-directory ~/important-meetings --model claude-3-5-sonnet
|
|
187
|
+
|
|
188
|
+
# Use latest transcription model
|
|
189
|
+
protokoll --input-directory ~/recordings --transcription-model gpt-4o-transcribe
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Scenario 10: Hierarchical Context
|
|
193
|
+
|
|
194
|
+
Use global and project-specific context together.
|
|
195
|
+
|
|
196
|
+
```
|
|
197
|
+
~/.protokoll/ # Global context
|
|
198
|
+
├── config.yaml
|
|
199
|
+
├── people/
|
|
200
|
+
│ └── family-members.yaml
|
|
201
|
+
└── terms/
|
|
202
|
+
└── common-terms.yaml
|
|
203
|
+
|
|
204
|
+
~/work/.protokoll/ # Work-specific context
|
|
205
|
+
├── config.yaml # Overrides global
|
|
206
|
+
├── people/
|
|
207
|
+
│ └── colleagues.yaml
|
|
208
|
+
└── projects/
|
|
209
|
+
└── current-project.yaml
|
|
210
|
+
|
|
211
|
+
~/work/project-a/.protokoll/ # Project-specific context
|
|
212
|
+
├── people/
|
|
213
|
+
│ └── project-team.yaml
|
|
214
|
+
└── terms/
|
|
215
|
+
└── project-jargon.yaml
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
# When processing from ~/work/project-a/recordings/
|
|
220
|
+
# Protokoll merges context from all three levels
|
|
221
|
+
cd ~/work/project-a
|
|
222
|
+
protokoll --input-directory ./recordings
|
|
223
|
+
```
|
|
224
|
+
|
package/docs/index.html
CHANGED
|
@@ -3,14 +3,16 @@
|
|
|
3
3
|
|
|
4
4
|
<head>
|
|
5
5
|
<meta charset="UTF-8" />
|
|
6
|
-
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
7
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
8
|
-
<title>
|
|
7
|
+
<title>Protokoll - Intelligent Audio Transcription</title>
|
|
8
|
+
<meta name="description"
|
|
9
|
+
content="Transform voice memos into perfectly organized, context-aware notes. Intelligent name recognition, smart routing, full content preservation.">
|
|
10
|
+
|
|
11
|
+
<script type="module" src="/src/main.jsx"></script>
|
|
9
12
|
</head>
|
|
10
13
|
|
|
11
14
|
<body>
|
|
12
15
|
<div id="root"></div>
|
|
13
|
-
<script type="module" src="/src/main.jsx"></script>
|
|
14
16
|
</body>
|
|
15
17
|
|
|
16
18
|
</html>
|