@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 CHANGED
@@ -1,2 +1 @@
1
- 20
2
-
1
+ 24
package/README.md CHANGED
@@ -27,30 +27,30 @@ Protokoll is an intelligent audio transcription system that uses advanced reason
27
27
 
28
28
  **The most important feature of Protokoll is not transcription—it's learning.**
29
29
 
30
- When you first start using Protokoll, it doesn't know anything about you. It doesn't know that "Wagner" is a project you're working on, that "Priya" is your colleague, or that notes about "skiing" should go to your personal folder while notes about "Walmart" should go to a work project.
30
+ When you first start using Protokoll, it doesn't know anything about you. It doesn't know that "Project Alpha" is a client engagement you're working on, that "Priya" is your colleague, or that notes about "skiing" should go to your personal folder while notes about "quarterly planning" should go to a work project.
31
31
 
32
32
  **But that's the point.** Protokoll is designed to learn from you:
33
33
 
34
- 1. **Interactive Discovery**: When you run `protokoll --interactive` and mention "Wagner" for the first time, the system recognizes it doesn't know what Wagner is. It asks: *"Is Wagner a new project? Where should notes about it be stored?"* You tell it, and from that moment forward, every note mentioning Wagner routes correctly.
34
+ 1. **Interactive Discovery**: When you run `protokoll --interactive` and mention "Project Alpha" for the first time, the system recognizes it doesn't know what that is. It asks: *"Is Project Alpha a new project? Where should notes about it be stored?"* You tell it, and from that moment forward, every note mentioning Project Alpha routes correctly.
35
35
 
36
36
  2. **Context Files You Own**: Unlike cloud transcription services that keep your data in their black box, Protokoll stores everything it learns in simple YAML files in your `.protokoll/context/` directory:
37
37
 
38
38
  ```yaml
39
- # .protokoll/context/projects/wagner.yaml
40
- id: wagner
41
- name: Wagner
39
+ # .protokoll/context/projects/project-alpha.yaml
40
+ id: project-alpha
41
+ name: Project Alpha
42
42
  classification:
43
43
  context_type: work
44
- explicit_phrases: ["wagner", "update on wagner"]
45
- topics: ["customer interactions", "shopify"]
44
+ explicit_phrases: ["project alpha", "update on alpha"]
45
+ topics: ["client engagement", "Q1 planning"]
46
46
  routing:
47
- destination: ~/notes/projects/wagner
47
+ destination: ~/notes/projects/alpha
48
48
  structure: month
49
49
  ```
50
50
 
51
51
  **You can read these files. You can edit them. You can version control them.** This is YOUR context, not a proprietary model hidden in someone else's cloud.
52
52
 
53
- 3. **Feedback That Teaches**: Made a mistake? Run `protokoll feedback --recent` to review recent classifications. Tell the system "this note should have gone to the Wagner project because I said 'update on Wagner' at the beginning." Protokoll uses AI to analyze your feedback and automatically update its classification rules.
53
+ 3. **Feedback That Teaches**: Made a mistake? Run `protokoll feedback --recent` to review recent classifications. Tell the system "this note should have gone to Project Alpha because I said 'update on Alpha' at the beginning." Protokoll uses AI to analyze your feedback and automatically update its classification rules.
54
54
 
55
55
  4. **Transparent Reasoning**: Every routing decision includes a reasoning trace. You can see exactly WHY a note was classified the way it was—which phrases matched, which signals contributed, what the confidence level was. No black boxes.
56
56
 
@@ -68,7 +68,7 @@
68
68
  ${args.triggerPhrase ? `Trigger phrase: "${args.triggerPhrase}"` : ''}
69
69
 
70
70
  Is "${args.name}" a new project? If yes, where should notes about it be stored?
71
- Enter a path (e.g., ~/notes/projects/wagner) or press Enter to use default routing:`,
71
+ Enter a path (e.g., ~/notes/projects/${args.name.toLowerCase().replace(/\s+/g, '-')}) or press Enter to use default routing:`,
72
72
  data: {
73
73
  found: false,
74
74
  clarificationType: 'new_project',
@@ -1 +1 @@
1
- {"version":3,"file":"lookup-project.js","sources":["../../../src/agentic/tools/lookup-project.ts"],"sourcesContent":["/**\n * Lookup Project Tool\n * \n * Looks up project information for routing and context.\n * In interactive mode, prompts to create unknown projects.\n */\n\nimport { TranscriptionTool, ToolContext, ToolResult } from '../types';\n\nexport const create = (ctx: ToolContext): TranscriptionTool => ({\n name: 'lookup_project',\n description: 'Look up project information for routing and context. Use when you need to determine where this note should be filed.',\n parameters: {\n type: 'object',\n properties: {\n name: {\n type: 'string',\n description: 'The project name or identifier',\n },\n triggerPhrase: {\n type: 'string',\n description: 'A phrase from the transcript that might indicate the project',\n },\n },\n required: ['name'],\n },\n execute: async (args: { name: string; triggerPhrase?: string }): Promise<ToolResult> => {\n const context = ctx.contextInstance;\n \n // Look up project by name\n const projects = context.search(args.name);\n const projectMatches = projects.filter(e => e.type === 'project');\n \n if (projectMatches.length > 0) {\n const project = projectMatches[0];\n return {\n success: true,\n data: {\n found: true,\n project,\n },\n };\n }\n \n // Try getting all projects and matching trigger phrases\n if (args.triggerPhrase) {\n const allProjects = context.getAllProjects();\n for (const project of allProjects) {\n const phrases = project.classification?.explicit_phrases ?? [];\n if (phrases.some(p => args.triggerPhrase?.toLowerCase().includes(p.toLowerCase()))) {\n return {\n success: true,\n data: {\n found: true,\n project,\n matchedTrigger: args.triggerPhrase,\n },\n };\n }\n }\n }\n \n // Project not found - in interactive mode, ask about creating it\n if (ctx.interactiveMode) {\n return {\n success: true,\n needsUserInput: true,\n userPrompt: `Unknown project: \"${args.name}\"\n${args.triggerPhrase ? `Trigger phrase: \"${args.triggerPhrase}\"` : ''}\n\nIs \"${args.name}\" a new project? If yes, where should notes about it be stored?\nEnter a path (e.g., ~/notes/projects/wagner) or press Enter to use default routing:`,\n data: {\n found: false,\n clarificationType: 'new_project',\n term: args.name,\n triggerPhrase: args.triggerPhrase,\n message: `Project \"${args.name}\" not found. Asking user if this is a new project.`,\n },\n };\n }\n \n // Non-interactive mode - just use default\n return {\n success: true,\n data: {\n found: false,\n message: `No project found for \"${args.name}\". Will use default routing.`,\n },\n };\n },\n});\n\n"],"names":["create","ctx","name","description","parameters","type","properties","triggerPhrase","required","execute","args","context","contextInstance","projects","search","projectMatches","filter","e","length","project","success","data","found","allProjects","getAllProjects","phrases","classification","explicit_phrases","some","p","toLowerCase","includes","matchedTrigger","interactiveMode","needsUserInput","userPrompt","clarificationType","term","message"],"mappings":"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"}
1
+ {"version":3,"file":"lookup-project.js","sources":["../../../src/agentic/tools/lookup-project.ts"],"sourcesContent":["/**\n * Lookup Project Tool\n * \n * Looks up project information for routing and context.\n * In interactive mode, prompts to create unknown projects.\n */\n\nimport { TranscriptionTool, ToolContext, ToolResult } from '../types';\n\nexport const create = (ctx: ToolContext): TranscriptionTool => ({\n name: 'lookup_project',\n description: 'Look up project information for routing and context. Use when you need to determine where this note should be filed.',\n parameters: {\n type: 'object',\n properties: {\n name: {\n type: 'string',\n description: 'The project name or identifier',\n },\n triggerPhrase: {\n type: 'string',\n description: 'A phrase from the transcript that might indicate the project',\n },\n },\n required: ['name'],\n },\n execute: async (args: { name: string; triggerPhrase?: string }): Promise<ToolResult> => {\n const context = ctx.contextInstance;\n \n // Look up project by name\n const projects = context.search(args.name);\n const projectMatches = projects.filter(e => e.type === 'project');\n \n if (projectMatches.length > 0) {\n const project = projectMatches[0];\n return {\n success: true,\n data: {\n found: true,\n project,\n },\n };\n }\n \n // Try getting all projects and matching trigger phrases\n if (args.triggerPhrase) {\n const allProjects = context.getAllProjects();\n for (const project of allProjects) {\n const phrases = project.classification?.explicit_phrases ?? [];\n if (phrases.some(p => args.triggerPhrase?.toLowerCase().includes(p.toLowerCase()))) {\n return {\n success: true,\n data: {\n found: true,\n project,\n matchedTrigger: args.triggerPhrase,\n },\n };\n }\n }\n }\n \n // Project not found - in interactive mode, ask about creating it\n if (ctx.interactiveMode) {\n return {\n success: true,\n needsUserInput: true,\n userPrompt: `Unknown project: \"${args.name}\"\n${args.triggerPhrase ? `Trigger phrase: \"${args.triggerPhrase}\"` : ''}\n\nIs \"${args.name}\" a new project? If yes, where should notes about it be stored?\nEnter a path (e.g., ~/notes/projects/${args.name.toLowerCase().replace(/\\s+/g, '-')}) or press Enter to use default routing:`,\n data: {\n found: false,\n clarificationType: 'new_project',\n term: args.name,\n triggerPhrase: args.triggerPhrase,\n message: `Project \"${args.name}\" not found. Asking user if this is a new project.`,\n },\n };\n }\n \n // Non-interactive mode - just use default\n return {\n success: true,\n data: {\n found: false,\n message: `No project found for \"${args.name}\". Will use default routing.`,\n },\n };\n },\n});\n\n"],"names":["create","ctx","name","description","parameters","type","properties","triggerPhrase","required","execute","args","context","contextInstance","projects","search","projectMatches","filter","e","length","project","success","data","found","allProjects","getAllProjects","phrases","classification","explicit_phrases","some","p","toLowerCase","includes","matchedTrigger","interactiveMode","needsUserInput","userPrompt","replace","clarificationType","term","message"],"mappings":"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"}
package/dist/constants.js CHANGED
@@ -1,6 +1,6 @@
1
- import os__default from 'os';
1
+ import os__default from 'node:os';
2
2
 
3
- const VERSION = '0.0.10 (HEAD/f513d70 T:v0.0.10 2026-01-12 22:04:56 -0800) linux x64 v22.21.1';
3
+ const VERSION = '0.0.12 (HEAD/f716744 T:v0.0.12 2026-01-13 00:29:23 -0800) linux x64 v24.12.0';
4
4
  const PROGRAM_NAME = 'protokoll';
5
5
  const DEFAULT_DIFF = true;
6
6
  const DEFAULT_LOG = false;
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sources":["../src/constants.ts"],"sourcesContent":["import os from 'os';\nimport { FilenameOption } from '@theunwalked/dreadcabinet';\nimport { FilesystemStructure } from '@theunwalked/dreadcabinet';\n\nexport const VERSION = '__VERSION__ (__GIT_BRANCH__/__GIT_COMMIT__ __GIT_TAGS__ __GIT_COMMIT_DATE__) __SYSTEM_INFO__';\nexport const PROGRAM_NAME = 'protokoll';\nexport const DEFAULT_CHARACTER_ENCODING = 'utf-8';\nexport const DEFAULT_BINARY_TO_TEXT_ENCODING = 'base64';\nexport const DEFAULT_DIFF = true;\nexport const DEFAULT_LOG = false;\nexport const DEFAULT_TIMEZONE = 'Etc/UTC';\nexport const DATE_FORMAT_MONTH_DAY = 'M-D';\nexport const DATE_FORMAT_YEAR = 'YYYY';\nexport const DATE_FORMAT_YEAR_MONTH = 'YYYY-M';\nexport const DATE_FORMAT_YEAR_MONTH_DAY = 'YYYY-M-D';\nexport const DATE_FORMAT_YEAR_MONTH_DAY_SLASH = 'YYYY/M/D';\nexport const DATE_FORMAT_YEAR_MONTH_DAY_HOURS_MINUTES = 'YYYY-M-D-HHmm';\nexport const DATE_FORMAT_YEAR_MONTH_DAY_HOURS_MINUTES_SECONDS = 'YYYY-M-D-HHmmss';\nexport const DATE_FORMAT_YEAR_MONTH_DAY_HOURS_MINUTES_SECONDS_MILLISECONDS = 'YYYY-M-D-HHmmss.SSS';\nexport const DATE_FORMAT_MONTH = 'M';\nexport const DATE_FORMAT_DAY = 'D';\nexport const DATE_FORMAT_HOURS = 'HHmm';\nexport const DATE_FORMAT_MINUTES = 'mm';\nexport const DATE_FORMAT_SECONDS = 'ss';\nexport const DATE_FORMAT_MILLISECONDS = 'SSS';\nexport const DEFAULT_VERBOSE = false;\nexport const DEFAULT_DRY_RUN = false;\nexport const DEFAULT_DEBUG = false;\nexport const DEFAULT_CONTENT_TYPES = ['diff'];\nexport const DEFAULT_RECURSIVE = false;\nexport const DEFAULT_INPUT_DIRECTORY = './';\nexport const DEFAULT_OUTPUT_DIRECTORY = './';\n\nexport const DEFAULT_AUDIO_EXTENSIONS = ['mp3', 'mp4', 'mpeg', 'mpga', 'm4a', 'wav', 'webm'];\n\nexport const ALLOWED_CONTENT_TYPES = ['log', 'diff'];\nexport const ALLOWED_AUDIO_EXTENSIONS = ['mp3', 'mp4', 'mpeg', 'mpga', 'm4a', 'wav', 'webm'];\n\nexport const DEFAULT_OUTPUT_STRUCTURE = 'month' as FilesystemStructure;\nexport const DEFAULT_OUTPUT_FILENAME_OPTIONS = ['date', 'time', 'subject'] as FilenameOption[];\n\nexport const ALLOWED_OUTPUT_STRUCTURES = ['none', 'year', 'month', 'day'] as FilesystemStructure[];\nexport const ALLOWED_OUTPUT_FILENAME_OPTIONS = ['date', 'time', 'subject'] as FilenameOption[];\n\nexport const DEFAULT_CONFIG_DIR = `./.${PROGRAM_NAME}`;\nexport const DEFAULT_PROCESSED_DIR = './processed';\n\n// Context System Constants\nexport const DEFAULT_CONTEXT_DIR_NAME = '.protokoll';\nexport const DEFAULT_CONTEXT_CONFIG_FILE_NAME = 'config.yaml';\nexport const DEFAULT_MAX_DISCOVERY_LEVELS = 10;\n\nexport const CONTEXT_SUBDIRECTORIES = {\n people: 'people',\n projects: 'projects',\n companies: 'companies',\n terms: 'terms',\n} as const;\n\nexport const DEFAULT_PERSONAS_DIR = `/personas`;\n\nexport const DEFAULT_PERSONA_TRANSCRIBER_FILE = `${DEFAULT_PERSONAS_DIR}/transcriber.md`;\n\nexport const DEFAULT_INSTRUCTIONS_DIR = `/instructions`;\n\nexport const DEFAULT_INSTRUCTIONS_TRANSCRIBE_FILE = `${DEFAULT_INSTRUCTIONS_DIR}/transcribe.md`;\n\n// Note: We no longer maintain a static allowlist of models\n// This allows for dynamic model discovery and future model additions\n// Users can specify any model supported by their OpenAI API\n\nexport const DEFAULT_TRANSCRIPTION_MODEL = 'whisper-1';\nexport const DEFAULT_MODEL = 'gpt-5.2';\nexport const DEFAULT_REASONING_LEVEL = 'medium';\n\nexport const DEFAULT_OVERRIDES = false;\nexport const DEFAULT_MAX_AUDIO_SIZE = 26214400; // 25MB in bytes\nexport const DEFAULT_TEMP_DIRECTORY = os.tmpdir(); // Use OS default temp directory\nexport const DEFAULT_INTERACTIVE = false;\nexport const DEFAULT_SELF_REFLECTION = true;\n\n// Output Management Constants\nexport const DEFAULT_INTERMEDIATE_DIRECTORY = './output/protokoll';\nexport const DEFAULT_KEEP_INTERMEDIATES = true;\nexport const OUTPUT_FILE_TYPES = [\n 'transcript',\n 'context',\n 'request',\n 'response',\n 'reflection',\n 'session',\n] as const;\n\n// Define Protokoll-specific defaults\nexport const PROTOKOLL_DEFAULTS = {\n dryRun: DEFAULT_DRY_RUN,\n verbose: DEFAULT_VERBOSE,\n debug: DEFAULT_DEBUG,\n diff: DEFAULT_DIFF,\n log: DEFAULT_LOG,\n transcriptionModel: DEFAULT_TRANSCRIPTION_MODEL,\n model: DEFAULT_MODEL,\n contentTypes: DEFAULT_CONTENT_TYPES,\n overrides: DEFAULT_OVERRIDES,\n maxAudioSize: DEFAULT_MAX_AUDIO_SIZE,\n tempDirectory: DEFAULT_TEMP_DIRECTORY || os.tmpdir(),\n configDirectory: DEFAULT_CONFIG_DIR,\n interactive: DEFAULT_INTERACTIVE,\n selfReflection: DEFAULT_SELF_REFLECTION,\n};\n"],"names":["VERSION","PROGRAM_NAME","DEFAULT_DIFF","DEFAULT_LOG","DEFAULT_TIMEZONE","DATE_FORMAT_YEAR_MONTH_DAY_HOURS_MINUTES_SECONDS","DEFAULT_VERBOSE","DEFAULT_DRY_RUN","DEFAULT_DEBUG","DEFAULT_CONTENT_TYPES","DEFAULT_INPUT_DIRECTORY","DEFAULT_OUTPUT_DIRECTORY","DEFAULT_AUDIO_EXTENSIONS","ALLOWED_AUDIO_EXTENSIONS","DEFAULT_OUTPUT_STRUCTURE","DEFAULT_OUTPUT_FILENAME_OPTIONS","ALLOWED_OUTPUT_STRUCTURES","ALLOWED_OUTPUT_FILENAME_OPTIONS","DEFAULT_CONFIG_DIR","DEFAULT_TRANSCRIPTION_MODEL","DEFAULT_MODEL","DEFAULT_OVERRIDES","DEFAULT_MAX_AUDIO_SIZE","DEFAULT_TEMP_DIRECTORY","os","tmpdir","DEFAULT_INTERACTIVE","DEFAULT_SELF_REFLECTION","DEFAULT_INTERMEDIATE_DIRECTORY","PROTOKOLL_DEFAULTS","dryRun","verbose","debug","diff","log","transcriptionModel","model","contentTypes","overrides","maxAudioSize","tempDirectory","configDirectory","interactive","selfReflection"],"mappings":";;AAIO,MAAMA,UAAU;AAChB,MAAMC,eAAe;AAGrB,MAAMC,eAAe;AACrB,MAAMC,cAAc;AACpB,MAAMC,mBAAmB;AAOzB,MAAMC,mDAAmD;AAQzD,MAAMC,kBAAkB;AACxB,MAAMC,kBAAkB;AACxB,MAAMC,gBAAgB;MAChBC,qBAAAA,GAAwB;AAAC,IAAA;;AAE/B,MAAMC,0BAA0B;AAChC,MAAMC,2BAA2B;MAE3BC,wBAAAA,GAA2B;AAAC,IAAA,KAAA;AAAO,IAAA,KAAA;AAAO,IAAA,MAAA;AAAQ,IAAA,MAAA;AAAQ,IAAA,KAAA;AAAO,IAAA,KAAA;AAAO,IAAA;;MAGxEC,wBAAAA,GAA2B;AAAC,IAAA,KAAA;AAAO,IAAA,KAAA;AAAO,IAAA,MAAA;AAAQ,IAAA,MAAA;AAAQ,IAAA,KAAA;AAAO,IAAA,KAAA;AAAO,IAAA;;AAE9E,MAAMC,2BAA2B;MAC3BC,+BAAAA,GAAkC;AAAC,IAAA,MAAA;AAAQ,IAAA,MAAA;AAAQ,IAAA;;MAEnDC,yBAAAA,GAA4B;AAAC,IAAA,MAAA;AAAQ,IAAA,MAAA;AAAQ,IAAA,OAAA;AAAS,IAAA;;MACtDC,+BAAAA,GAAkC;AAAC,IAAA,MAAA;AAAQ,IAAA,MAAA;AAAQ,IAAA;;MAEnDC,kBAAAA,GAAqB,CAAC,GAAG,EAAEjB;AAuBxC;AACA;AACA;AAEO,MAAMkB,8BAA8B;AACpC,MAAMC,gBAAgB;AAGtB,MAAMC,oBAAoB;AAC1B,MAAMC,sBAAAA,GAAyB,SAAS;MAClCC,sBAAAA,GAAyBC,WAAAA,CAAGC,MAAM,GAAG;AAC3C,MAAMC,sBAAsB;AAC5B,MAAMC,0BAA0B;AAEvC;AACO,MAAMC,iCAAiC;AAW9C;MACaC,kBAAAA,GAAqB;IAC9BC,MAAAA,EAAQvB,eAAAA;IACRwB,OAAAA,EAASzB,eAAAA;IACT0B,KAAAA,EAAOxB,aAAAA;IACPyB,IAAAA,EAAM/B,YAAAA;IACNgC,GAAAA,EAAK/B,WAAAA;IACLgC,kBAAAA,EAAoBhB,2BAAAA;IACpBiB,KAAAA,EAAOhB,aAAAA;IACPiB,YAAAA,EAAc5B,qBAAAA;IACd6B,SAAAA,EAAWjB,iBAAAA;IACXkB,YAAAA,EAAcjB,sBAAAA;IACdkB,aAAAA,EAAejB,sBAAAA,IAA0BC,YAAGC,MAAM,EAAA;IAClDgB,eAAAA,EAAiBvB,kBAAAA;IACjBwB,WAAAA,EAAahB,mBAAAA;IACbiB,cAAAA,EAAgBhB;AACpB;;;;"}
1
+ {"version":3,"file":"constants.js","sources":["../src/constants.ts"],"sourcesContent":["import os from 'node:os';\nimport { FilenameOption } from '@theunwalked/dreadcabinet';\nimport { FilesystemStructure } from '@theunwalked/dreadcabinet';\n\nexport const VERSION = '__VERSION__ (__GIT_BRANCH__/__GIT_COMMIT__ __GIT_TAGS__ __GIT_COMMIT_DATE__) __SYSTEM_INFO__';\nexport const PROGRAM_NAME = 'protokoll';\nexport const DEFAULT_CHARACTER_ENCODING = 'utf-8';\nexport const DEFAULT_BINARY_TO_TEXT_ENCODING = 'base64';\nexport const DEFAULT_DIFF = true;\nexport const DEFAULT_LOG = false;\nexport const DEFAULT_TIMEZONE = 'Etc/UTC';\nexport const DATE_FORMAT_MONTH_DAY = 'M-D';\nexport const DATE_FORMAT_YEAR = 'YYYY';\nexport const DATE_FORMAT_YEAR_MONTH = 'YYYY-M';\nexport const DATE_FORMAT_YEAR_MONTH_DAY = 'YYYY-M-D';\nexport const DATE_FORMAT_YEAR_MONTH_DAY_SLASH = 'YYYY/M/D';\nexport const DATE_FORMAT_YEAR_MONTH_DAY_HOURS_MINUTES = 'YYYY-M-D-HHmm';\nexport const DATE_FORMAT_YEAR_MONTH_DAY_HOURS_MINUTES_SECONDS = 'YYYY-M-D-HHmmss';\nexport const DATE_FORMAT_YEAR_MONTH_DAY_HOURS_MINUTES_SECONDS_MILLISECONDS = 'YYYY-M-D-HHmmss.SSS';\nexport const DATE_FORMAT_MONTH = 'M';\nexport const DATE_FORMAT_DAY = 'D';\nexport const DATE_FORMAT_HOURS = 'HHmm';\nexport const DATE_FORMAT_MINUTES = 'mm';\nexport const DATE_FORMAT_SECONDS = 'ss';\nexport const DATE_FORMAT_MILLISECONDS = 'SSS';\nexport const DEFAULT_VERBOSE = false;\nexport const DEFAULT_DRY_RUN = false;\nexport const DEFAULT_DEBUG = false;\nexport const DEFAULT_CONTENT_TYPES = ['diff'];\nexport const DEFAULT_RECURSIVE = false;\nexport const DEFAULT_INPUT_DIRECTORY = './';\nexport const DEFAULT_OUTPUT_DIRECTORY = './';\n\nexport const DEFAULT_AUDIO_EXTENSIONS = ['mp3', 'mp4', 'mpeg', 'mpga', 'm4a', 'wav', 'webm'];\n\nexport const ALLOWED_CONTENT_TYPES = ['log', 'diff'];\nexport const ALLOWED_AUDIO_EXTENSIONS = ['mp3', 'mp4', 'mpeg', 'mpga', 'm4a', 'wav', 'webm'];\n\nexport const DEFAULT_OUTPUT_STRUCTURE = 'month' as FilesystemStructure;\nexport const DEFAULT_OUTPUT_FILENAME_OPTIONS = ['date', 'time', 'subject'] as FilenameOption[];\n\nexport const ALLOWED_OUTPUT_STRUCTURES = ['none', 'year', 'month', 'day'] as FilesystemStructure[];\nexport const ALLOWED_OUTPUT_FILENAME_OPTIONS = ['date', 'time', 'subject'] as FilenameOption[];\n\nexport const DEFAULT_CONFIG_DIR = `./.${PROGRAM_NAME}`;\nexport const DEFAULT_PROCESSED_DIR = './processed';\n\n// Context System Constants\nexport const DEFAULT_CONTEXT_DIR_NAME = '.protokoll';\nexport const DEFAULT_CONTEXT_CONFIG_FILE_NAME = 'config.yaml';\nexport const DEFAULT_MAX_DISCOVERY_LEVELS = 10;\n\nexport const CONTEXT_SUBDIRECTORIES = {\n people: 'people',\n projects: 'projects',\n companies: 'companies',\n terms: 'terms',\n} as const;\n\nexport const DEFAULT_PERSONAS_DIR = `/personas`;\n\nexport const DEFAULT_PERSONA_TRANSCRIBER_FILE = `${DEFAULT_PERSONAS_DIR}/transcriber.md`;\n\nexport const DEFAULT_INSTRUCTIONS_DIR = `/instructions`;\n\nexport const DEFAULT_INSTRUCTIONS_TRANSCRIBE_FILE = `${DEFAULT_INSTRUCTIONS_DIR}/transcribe.md`;\n\n// Note: We no longer maintain a static allowlist of models\n// This allows for dynamic model discovery and future model additions\n// Users can specify any model supported by their OpenAI API\n\nexport const DEFAULT_TRANSCRIPTION_MODEL = 'whisper-1';\nexport const DEFAULT_MODEL = 'gpt-5.2';\nexport const DEFAULT_REASONING_LEVEL = 'medium';\n\nexport const DEFAULT_OVERRIDES = false;\nexport const DEFAULT_MAX_AUDIO_SIZE = 26214400; // 25MB in bytes\nexport const DEFAULT_TEMP_DIRECTORY = os.tmpdir(); // Use OS default temp directory\nexport const DEFAULT_INTERACTIVE = false;\nexport const DEFAULT_SELF_REFLECTION = true;\n\n// Output Management Constants\nexport const DEFAULT_INTERMEDIATE_DIRECTORY = './output/protokoll';\nexport const DEFAULT_KEEP_INTERMEDIATES = true;\nexport const OUTPUT_FILE_TYPES = [\n 'transcript',\n 'context',\n 'request',\n 'response',\n 'reflection',\n 'session',\n] as const;\n\n// Define Protokoll-specific defaults\nexport const PROTOKOLL_DEFAULTS = {\n dryRun: DEFAULT_DRY_RUN,\n verbose: DEFAULT_VERBOSE,\n debug: DEFAULT_DEBUG,\n diff: DEFAULT_DIFF,\n log: DEFAULT_LOG,\n transcriptionModel: DEFAULT_TRANSCRIPTION_MODEL,\n model: DEFAULT_MODEL,\n contentTypes: DEFAULT_CONTENT_TYPES,\n overrides: DEFAULT_OVERRIDES,\n maxAudioSize: DEFAULT_MAX_AUDIO_SIZE,\n tempDirectory: DEFAULT_TEMP_DIRECTORY || os.tmpdir(),\n configDirectory: DEFAULT_CONFIG_DIR,\n interactive: DEFAULT_INTERACTIVE,\n selfReflection: DEFAULT_SELF_REFLECTION,\n};\n"],"names":["VERSION","PROGRAM_NAME","DEFAULT_DIFF","DEFAULT_LOG","DEFAULT_TIMEZONE","DATE_FORMAT_YEAR_MONTH_DAY_HOURS_MINUTES_SECONDS","DEFAULT_VERBOSE","DEFAULT_DRY_RUN","DEFAULT_DEBUG","DEFAULT_CONTENT_TYPES","DEFAULT_INPUT_DIRECTORY","DEFAULT_OUTPUT_DIRECTORY","DEFAULT_AUDIO_EXTENSIONS","ALLOWED_AUDIO_EXTENSIONS","DEFAULT_OUTPUT_STRUCTURE","DEFAULT_OUTPUT_FILENAME_OPTIONS","ALLOWED_OUTPUT_STRUCTURES","ALLOWED_OUTPUT_FILENAME_OPTIONS","DEFAULT_CONFIG_DIR","DEFAULT_TRANSCRIPTION_MODEL","DEFAULT_MODEL","DEFAULT_OVERRIDES","DEFAULT_MAX_AUDIO_SIZE","DEFAULT_TEMP_DIRECTORY","os","tmpdir","DEFAULT_INTERACTIVE","DEFAULT_SELF_REFLECTION","DEFAULT_INTERMEDIATE_DIRECTORY","PROTOKOLL_DEFAULTS","dryRun","verbose","debug","diff","log","transcriptionModel","model","contentTypes","overrides","maxAudioSize","tempDirectory","configDirectory","interactive","selfReflection"],"mappings":";;AAIO,MAAMA,UAAU;AAChB,MAAMC,eAAe;AAGrB,MAAMC,eAAe;AACrB,MAAMC,cAAc;AACpB,MAAMC,mBAAmB;AAOzB,MAAMC,mDAAmD;AAQzD,MAAMC,kBAAkB;AACxB,MAAMC,kBAAkB;AACxB,MAAMC,gBAAgB;MAChBC,qBAAAA,GAAwB;AAAC,IAAA;;AAE/B,MAAMC,0BAA0B;AAChC,MAAMC,2BAA2B;MAE3BC,wBAAAA,GAA2B;AAAC,IAAA,KAAA;AAAO,IAAA,KAAA;AAAO,IAAA,MAAA;AAAQ,IAAA,MAAA;AAAQ,IAAA,KAAA;AAAO,IAAA,KAAA;AAAO,IAAA;;MAGxEC,wBAAAA,GAA2B;AAAC,IAAA,KAAA;AAAO,IAAA,KAAA;AAAO,IAAA,MAAA;AAAQ,IAAA,MAAA;AAAQ,IAAA,KAAA;AAAO,IAAA,KAAA;AAAO,IAAA;;AAE9E,MAAMC,2BAA2B;MAC3BC,+BAAAA,GAAkC;AAAC,IAAA,MAAA;AAAQ,IAAA,MAAA;AAAQ,IAAA;;MAEnDC,yBAAAA,GAA4B;AAAC,IAAA,MAAA;AAAQ,IAAA,MAAA;AAAQ,IAAA,OAAA;AAAS,IAAA;;MACtDC,+BAAAA,GAAkC;AAAC,IAAA,MAAA;AAAQ,IAAA,MAAA;AAAQ,IAAA;;MAEnDC,kBAAAA,GAAqB,CAAC,GAAG,EAAEjB;AAuBxC;AACA;AACA;AAEO,MAAMkB,8BAA8B;AACpC,MAAMC,gBAAgB;AAGtB,MAAMC,oBAAoB;AAC1B,MAAMC,sBAAAA,GAAyB,SAAS;MAClCC,sBAAAA,GAAyBC,WAAAA,CAAGC,MAAM,GAAG;AAC3C,MAAMC,sBAAsB;AAC5B,MAAMC,0BAA0B;AAEvC;AACO,MAAMC,iCAAiC;AAW9C;MACaC,kBAAAA,GAAqB;IAC9BC,MAAAA,EAAQvB,eAAAA;IACRwB,OAAAA,EAASzB,eAAAA;IACT0B,KAAAA,EAAOxB,aAAAA;IACPyB,IAAAA,EAAM/B,YAAAA;IACNgC,GAAAA,EAAK/B,WAAAA;IACLgC,kBAAAA,EAAoBhB,2BAAAA;IACpBiB,KAAAA,EAAOhB,aAAAA;IACPiB,YAAAA,EAAc5B,qBAAAA;IACd6B,SAAAA,EAAWjB,iBAAAA;IACXkB,YAAAA,EAAcjB,sBAAAA;IACdkB,aAAAA,EAAejB,sBAAAA,IAA0BC,YAAGC,MAAM,EAAA;IAClDgB,eAAAA,EAAiBvB,kBAAAA;IACjBwB,WAAAA,EAAahB,mBAAAA;IACbiB,cAAAA,EAAgBhB;AACpB;;;;"}
@@ -1,4 +1,4 @@
1
- import * as path from 'path';
1
+ import * as path from 'node:path';
2
2
  import * as fs from 'fs/promises';
3
3
  import * as yaml from 'js-yaml';
4
4
 
@@ -1 +1 @@
1
- {"version":3,"file":"discovery.js","sources":["../../src/context/discovery.ts"],"sourcesContent":["/**\n * Hierarchical Configuration Discovery\n * \n * Follows Cardigantime pattern: walks up directory tree finding .protokoll/\n * directories. Merges config with local taking precedence.\n * \n * Example:\n * /home/user/projects/work/projectA/ <- CWD\n * └── .protokoll/config.yaml <- Highest precedence\n * /home/user/projects/work/\n * └── .protokoll/config.yaml <- Work context\n * /home/user/\n * └── .protokoll/config.yaml <- User defaults\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 fs from 'fs/promises';\nimport * as yaml from 'js-yaml';\nimport { ContextDiscoveryOptions, DiscoveredContextDir, HierarchicalContextResult } from './types';\n\n/**\n * Discover configuration directories by walking up the directory tree\n */\nexport const discoverConfigDirectories = async (\n options: ContextDiscoveryOptions\n): Promise<DiscoveredContextDir[]> => {\n const {\n configDirName,\n maxLevels = 10,\n startingDir = process.cwd(),\n } = options;\n\n const discovered: DiscoveredContextDir[] = [];\n let currentDir = path.resolve(startingDir);\n let level = 0;\n const visited = new Set<string>();\n\n while (level < maxLevels) {\n const realPath = path.resolve(currentDir);\n if (visited.has(realPath)) break;\n visited.add(realPath);\n\n const configDirPath = path.join(currentDir, configDirName);\n \n try {\n const stat = await fs.stat(configDirPath);\n if (stat.isDirectory()) {\n discovered.push({ path: configDirPath, level });\n }\n } catch {\n // Directory doesn't exist, continue searching\n }\n\n const parentDir = path.dirname(currentDir);\n if (parentDir === currentDir) break; // Reached root\n \n currentDir = parentDir;\n level++;\n }\n\n return discovered;\n};\n\n/**\n * Load and merge hierarchical configuration\n */\nexport const loadHierarchicalConfig = async (\n options: ContextDiscoveryOptions\n): Promise<HierarchicalContextResult> => {\n const discoveredDirs = await discoverConfigDirectories(options);\n \n if (discoveredDirs.length === 0) {\n return {\n config: {},\n discoveredDirs: [],\n contextDirs: [],\n };\n }\n\n // Sort by level descending (lowest precedence first)\n const sortedDirs = [...discoveredDirs].sort((a, b) => b.level - a.level);\n \n const configs: Record<string, unknown>[] = [];\n const contextDirs: string[] = [];\n \n for (const dir of sortedDirs) {\n const configPath = path.join(dir.path, options.configFileName);\n \n try {\n const content = await fs.readFile(configPath, 'utf-8');\n const parsed = yaml.load(content);\n if (parsed && typeof parsed === 'object') {\n configs.push(parsed as Record<string, unknown>);\n }\n } catch {\n // No config file in this directory\n }\n \n // Add context directory\n const contextDir = path.join(dir.path, 'context');\n try {\n const stat = await fs.stat(contextDir);\n if (stat.isDirectory()) {\n contextDirs.push(contextDir);\n }\n } catch {\n // No context subdirectory\n }\n }\n\n // Merge configs (later entries override earlier)\n const mergedConfig = configs.reduce(\n (acc, curr) => deepMerge(acc, curr), \n {} as Record<string, unknown>\n );\n\n return {\n config: mergedConfig,\n discoveredDirs,\n contextDirs,\n };\n};\n\n/**\n * Deep merge utility (similar to Cardigantime's implementation)\n */\nexport function deepMerge<T extends Record<string, unknown>>(target: T, source: T): T {\n if (source === null || source === undefined) return target;\n if (target === null || target === undefined) return source;\n \n if (typeof source !== 'object' || typeof target !== 'object') {\n return source;\n }\n \n if (Array.isArray(source)) {\n return [...source] as unknown as T;\n }\n \n const result = { ...target } as Record<string, unknown>;\n \n for (const key in source) {\n if (Object.prototype.hasOwnProperty.call(source, key)) {\n const targetVal = result[key];\n const sourceVal = source[key];\n \n if (\n typeof targetVal === 'object' && \n typeof sourceVal === 'object' &&\n targetVal !== null &&\n sourceVal !== null &&\n !Array.isArray(targetVal) && \n !Array.isArray(sourceVal)\n ) {\n result[key] = deepMerge(\n targetVal as Record<string, unknown>, \n sourceVal as Record<string, unknown>\n );\n } else {\n result[key] = sourceVal;\n }\n }\n }\n \n return result as T;\n}\n\n"],"names":["discoverConfigDirectories","options","configDirName","maxLevels","startingDir","process","cwd","discovered","currentDir","path","resolve","level","visited","Set","realPath","has","add","configDirPath","join","stat","fs","isDirectory","push","parentDir","dirname","loadHierarchicalConfig","discoveredDirs","length","config","contextDirs","sortedDirs","sort","a","b","configs","dir","configPath","configFileName","content","readFile","parsed","yaml","load","contextDir","mergedConfig","reduce","acc","curr","deepMerge","target","source","undefined","Array","isArray","result","key","Object","prototype","hasOwnProperty","call","targetVal","sourceVal"],"mappings":"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"}
1
+ {"version":3,"file":"discovery.js","sources":["../../src/context/discovery.ts"],"sourcesContent":["/**\n * Hierarchical Configuration Discovery\n * \n * Follows Cardigantime pattern: walks up directory tree finding .protokoll/\n * directories. Merges config with local taking precedence.\n * \n * Example:\n * /home/user/projects/work/projectA/ <- CWD\n * └── .protokoll/config.yaml <- Highest precedence\n * /home/user/projects/work/\n * └── .protokoll/config.yaml <- Work context\n * /home/user/\n * └── .protokoll/config.yaml <- User defaults\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 fs from 'fs/promises';\nimport * as yaml from 'js-yaml';\nimport { ContextDiscoveryOptions, DiscoveredContextDir, HierarchicalContextResult } from './types';\n\n/**\n * Discover configuration directories by walking up the directory tree\n */\nexport const discoverConfigDirectories = async (\n options: ContextDiscoveryOptions\n): Promise<DiscoveredContextDir[]> => {\n const {\n configDirName,\n maxLevels = 10,\n startingDir = process.cwd(),\n } = options;\n\n const discovered: DiscoveredContextDir[] = [];\n let currentDir = path.resolve(startingDir);\n let level = 0;\n const visited = new Set<string>();\n\n while (level < maxLevels) {\n const realPath = path.resolve(currentDir);\n if (visited.has(realPath)) break;\n visited.add(realPath);\n\n const configDirPath = path.join(currentDir, configDirName);\n \n try {\n const stat = await fs.stat(configDirPath);\n if (stat.isDirectory()) {\n discovered.push({ path: configDirPath, level });\n }\n } catch {\n // Directory doesn't exist, continue searching\n }\n\n const parentDir = path.dirname(currentDir);\n if (parentDir === currentDir) break; // Reached root\n \n currentDir = parentDir;\n level++;\n }\n\n return discovered;\n};\n\n/**\n * Load and merge hierarchical configuration\n */\nexport const loadHierarchicalConfig = async (\n options: ContextDiscoveryOptions\n): Promise<HierarchicalContextResult> => {\n const discoveredDirs = await discoverConfigDirectories(options);\n \n if (discoveredDirs.length === 0) {\n return {\n config: {},\n discoveredDirs: [],\n contextDirs: [],\n };\n }\n\n // Sort by level descending (lowest precedence first)\n const sortedDirs = [...discoveredDirs].sort((a, b) => b.level - a.level);\n \n const configs: Record<string, unknown>[] = [];\n const contextDirs: string[] = [];\n \n for (const dir of sortedDirs) {\n const configPath = path.join(dir.path, options.configFileName);\n \n try {\n const content = await fs.readFile(configPath, 'utf-8');\n const parsed = yaml.load(content);\n if (parsed && typeof parsed === 'object') {\n configs.push(parsed as Record<string, unknown>);\n }\n } catch {\n // No config file in this directory\n }\n \n // Add context directory\n const contextDir = path.join(dir.path, 'context');\n try {\n const stat = await fs.stat(contextDir);\n if (stat.isDirectory()) {\n contextDirs.push(contextDir);\n }\n } catch {\n // No context subdirectory\n }\n }\n\n // Merge configs (later entries override earlier)\n const mergedConfig = configs.reduce(\n (acc, curr) => deepMerge(acc, curr), \n {} as Record<string, unknown>\n );\n\n return {\n config: mergedConfig,\n discoveredDirs,\n contextDirs,\n };\n};\n\n/**\n * Deep merge utility (similar to Cardigantime's implementation)\n */\nexport function deepMerge<T extends Record<string, unknown>>(target: T, source: T): T {\n if (source === null || source === undefined) return target;\n if (target === null || target === undefined) return source;\n \n if (typeof source !== 'object' || typeof target !== 'object') {\n return source;\n }\n \n if (Array.isArray(source)) {\n return [...source] as unknown as T;\n }\n \n const result = { ...target } as Record<string, unknown>;\n \n for (const key in source) {\n if (Object.prototype.hasOwnProperty.call(source, key)) {\n const targetVal = result[key];\n const sourceVal = source[key];\n \n if (\n typeof targetVal === 'object' && \n typeof sourceVal === 'object' &&\n targetVal !== null &&\n sourceVal !== null &&\n !Array.isArray(targetVal) && \n !Array.isArray(sourceVal)\n ) {\n result[key] = deepMerge(\n targetVal as Record<string, unknown>, \n sourceVal as Record<string, unknown>\n );\n } else {\n result[key] = sourceVal;\n }\n }\n }\n \n return result as T;\n}\n\n"],"names":["discoverConfigDirectories","options","configDirName","maxLevels","startingDir","process","cwd","discovered","currentDir","path","resolve","level","visited","Set","realPath","has","add","configDirPath","join","stat","fs","isDirectory","push","parentDir","dirname","loadHierarchicalConfig","discoveredDirs","length","config","contextDirs","sortedDirs","sort","a","b","configs","dir","configPath","configFileName","content","readFile","parsed","yaml","load","contextDir","mergedConfig","reduce","acc","curr","deepMerge","target","source","undefined","Array","isArray","result","key","Object","prototype","hasOwnProperty","call","targetVal","sourceVal"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import * as yaml from 'js-yaml';
2
2
  import * as fs from 'fs/promises';
3
- import * as path from 'path';
3
+ import * as path from 'node:path';
4
4
 
5
5
  const DIRECTORY_TO_TYPE = {
6
6
  'people': 'person',
@@ -1 +1 @@
1
- {"version":3,"file":"storage.js","sources":["../../src/context/storage.ts"],"sourcesContent":["/**\n * Context Storage\n * \n * Handles loading and saving entity YAML files from context directories.\n * Supports hierarchical loading where later directories override earlier ones.\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 yaml from 'js-yaml';\nimport * as fs from 'fs/promises';\nimport * as path from 'path';\nimport { Entity, EntityType } from './types';\n\nexport interface StorageInstance {\n load(contextDirs: string[]): Promise<void>;\n save(entity: Entity, targetDir: string): Promise<void>;\n get<T extends Entity>(type: EntityType, id: string): T | undefined;\n getAll<T extends Entity>(type: EntityType): T[];\n search(query: string): Entity[];\n findBySoundsLike(phonetic: string): Entity | undefined;\n clear(): void;\n}\n\ntype DirectoryName = 'people' | 'projects' | 'companies' | 'terms';\n\nconst DIRECTORY_TO_TYPE: Record<DirectoryName, EntityType> = {\n 'people': 'person',\n 'projects': 'project',\n 'companies': 'company',\n 'terms': 'term',\n};\n\nconst TYPE_TO_DIRECTORY: Record<EntityType, DirectoryName> = {\n 'person': 'people',\n 'project': 'projects',\n 'company': 'companies',\n 'term': 'terms',\n};\n\nexport const create = (): StorageInstance => {\n const entities: Map<EntityType, Map<string, Entity>> = new Map([\n ['person', new Map()],\n ['project', new Map()],\n ['company', new Map()],\n ['term', new Map()],\n ]);\n\n const load = async (contextDirs: string[]): Promise<void> => {\n // Load from all context directories (later directories override)\n for (const contextDir of contextDirs) {\n for (const dirName of Object.keys(DIRECTORY_TO_TYPE) as DirectoryName[]) {\n const typeDir = path.join(contextDir, dirName);\n const entityType = DIRECTORY_TO_TYPE[dirName];\n \n try {\n const files = await fs.readdir(typeDir);\n for (const file of files) {\n if (!file.endsWith('.yaml') && !file.endsWith('.yml')) continue;\n \n const content = await fs.readFile(path.join(typeDir, file), 'utf-8');\n const parsed = yaml.load(content) as Partial<Entity>;\n \n if (parsed && parsed.id) {\n entities.get(entityType)?.set(parsed.id, {\n ...parsed,\n type: entityType,\n } as Entity);\n }\n }\n } catch {\n // Directory doesn't exist, skip\n }\n }\n }\n };\n\n const save = async (entity: Entity, targetDir: string): Promise<void> => {\n const dirName = TYPE_TO_DIRECTORY[entity.type];\n const dirPath = path.join(targetDir, 'context', dirName);\n await fs.mkdir(dirPath, { recursive: true });\n \n const filePath = path.join(dirPath, `${entity.id}.yaml`);\n \n // Remove type from saved YAML (it's inferred from directory)\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { type: _entityType, ...entityWithoutType } = entity;\n const content = yaml.dump(entityWithoutType, { lineWidth: -1 });\n await fs.writeFile(filePath, content, 'utf-8');\n \n entities.get(entity.type)?.set(entity.id, entity);\n };\n\n const get = <T extends Entity>(type: EntityType, id: string): T | undefined => {\n return entities.get(type)?.get(id) as T | undefined;\n };\n\n const getAll = <T extends Entity>(type: EntityType): T[] => {\n return Array.from(entities.get(type)?.values() ?? []) as T[];\n };\n\n const search = (query: string): Entity[] => {\n const normalizedQuery = query.toLowerCase();\n const results: Entity[] = [];\n \n for (const entityMap of entities.values()) {\n for (const entity of entityMap.values()) {\n if (entity.name.toLowerCase().includes(normalizedQuery)) {\n results.push(entity);\n }\n }\n }\n \n return results;\n };\n\n const findBySoundsLike = (phonetic: string): Entity | undefined => {\n const normalized = phonetic.toLowerCase().trim();\n \n for (const entityMap of entities.values()) {\n for (const entity of entityMap.values()) {\n // Check sounds_like field on entities that have it\n const entityWithSoundsLike = entity as Entity & { sounds_like?: string[] };\n const variants = entityWithSoundsLike.sounds_like;\n if (variants?.some(v => v.toLowerCase() === normalized)) {\n return entity;\n }\n }\n }\n \n return undefined;\n };\n\n const clear = (): void => {\n for (const entityMap of entities.values()) {\n entityMap.clear();\n }\n };\n\n return { load, save, get, getAll, search, findBySoundsLike, clear };\n};\n\n"],"names":["DIRECTORY_TO_TYPE","TYPE_TO_DIRECTORY","create","entities","Map","load","contextDirs","contextDir","dirName","Object","keys","typeDir","path","join","entityType","files","fs","readdir","file","endsWith","content","readFile","parsed","yaml","id","get","set","type","save","entity","targetDir","dirPath","mkdir","recursive","filePath","_entityType","entityWithoutType","dump","lineWidth","writeFile","getAll","Array","from","values","search","query","normalizedQuery","toLowerCase","results","entityMap","name","includes","push","findBySoundsLike","phonetic","normalized","trim","entityWithSoundsLike","variants","sounds_like","some","v","undefined","clear"],"mappings":";;;;AA2BA,MAAMA,iBAAAA,GAAuD;IACzD,QAAA,EAAU,QAAA;IACV,UAAA,EAAY,SAAA;IACZ,WAAA,EAAa,SAAA;IACb,OAAA,EAAS;AACb,CAAA;AAEA,MAAMC,iBAAAA,GAAuD;IACzD,QAAA,EAAU,QAAA;IACV,SAAA,EAAW,UAAA;IACX,SAAA,EAAW,WAAA;IACX,MAAA,EAAQ;AACZ,CAAA;MAEaC,MAAAA,GAAS,IAAA;IAClB,MAAMC,QAAAA,GAAiD,IAAIC,GAAAA,CAAI;AAC3D,QAAA;AAAC,YAAA,QAAA;YAAU,IAAIA,GAAAA;AAAM,SAAA;AACrB,QAAA;AAAC,YAAA,SAAA;YAAW,IAAIA,GAAAA;AAAM,SAAA;AACtB,QAAA;AAAC,YAAA,SAAA;YAAW,IAAIA,GAAAA;AAAM,SAAA;AACtB,QAAA;AAAC,YAAA,MAAA;YAAQ,IAAIA,GAAAA;AAAM;AACtB,KAAA,CAAA;AAED,IAAA,MAAMC,OAAO,OAAOC,WAAAA,GAAAA;;QAEhB,KAAK,MAAMC,cAAcD,WAAAA,CAAa;AAClC,YAAA,KAAK,MAAME,OAAAA,IAAWC,MAAAA,CAAOC,IAAI,CAACV,iBAAAA,CAAAA,CAAuC;AACrE,gBAAA,MAAMW,OAAAA,GAAUC,IAAAA,CAAKC,IAAI,CAACN,UAAAA,EAAYC,OAAAA,CAAAA;gBACtC,MAAMM,UAAAA,GAAad,iBAAiB,CAACQ,OAAAA,CAAQ;gBAE7C,IAAI;AACA,oBAAA,MAAMO,KAAAA,GAAQ,MAAMC,EAAAA,CAAGC,OAAO,CAACN,OAAAA,CAAAA;oBAC/B,KAAK,MAAMO,QAAQH,KAAAA,CAAO;wBACtB,IAAI,CAACG,KAAKC,QAAQ,CAAC,YAAY,CAACD,IAAAA,CAAKC,QAAQ,CAAC,MAAA,CAAA,EAAS;wBAEvD,MAAMC,OAAAA,GAAU,MAAMJ,EAAAA,CAAGK,QAAQ,CAACT,IAAAA,CAAKC,IAAI,CAACF,OAAAA,EAASO,IAAAA,CAAAA,EAAO,OAAA,CAAA;wBAC5D,MAAMI,MAAAA,GAASC,IAAAA,CAAKlB,IAAI,CAACe,OAAAA,CAAAA;wBAEzB,IAAIE,MAAAA,IAAUA,MAAAA,CAAOE,EAAE,EAAE;AACrBrB,4BAAAA,IAAAA,aAAAA;6BAAAA,aAAAA,GAAAA,QAAAA,CAASsB,GAAG,CAACX,UAAAA,CAAAA,MAAAA,IAAAA,IAAbX,aAAAA,KAAAA,KAAAA,CAAAA,GAAAA,KAAAA,CAAAA,GAAAA,cAA0BuB,GAAG,CAACJ,MAAAA,CAAOE,EAAE,EAAE;AACrC,gCAAA,GAAGF,MAAM;gCACTK,IAAAA,EAAMb;AACV,6BAAA,CAAA;AACJ,wBAAA;AACJ,oBAAA;AACJ,gBAAA,CAAA,CAAE,OAAM;;AAER,gBAAA;AACJ,YAAA;AACJ,QAAA;AACJ,IAAA,CAAA;IAEA,MAAMc,IAAAA,GAAO,OAAOC,MAAAA,EAAgBC,SAAAA,GAAAA;AAahC3B,QAAAA,IAAAA,aAAAA;AAZA,QAAA,MAAMK,OAAAA,GAAUP,iBAAiB,CAAC4B,MAAAA,CAAOF,IAAI,CAAC;AAC9C,QAAA,MAAMI,OAAAA,GAAUnB,IAAAA,CAAKC,IAAI,CAACiB,WAAW,SAAA,EAAWtB,OAAAA,CAAAA;QAChD,MAAMQ,EAAAA,CAAGgB,KAAK,CAACD,OAAAA,EAAS;YAAEE,SAAAA,EAAW;AAAK,SAAA,CAAA;QAE1C,MAAMC,QAAAA,GAAWtB,IAAAA,CAAKC,IAAI,CAACkB,OAAAA,EAAS,GAAGF,MAAAA,CAAOL,EAAE,CAAC,KAAK,CAAC,CAAA;;;AAIvD,QAAA,MAAM,EAAEG,IAAAA,EAAMQ,WAAW,EAAE,GAAGC,mBAAmB,GAAGP,MAAAA;AACpD,QAAA,MAAMT,OAAAA,GAAUG,IAAAA,CAAKc,IAAI,CAACD,iBAAAA,EAAmB;AAAEE,YAAAA,SAAAA,EAAW;AAAG,SAAA,CAAA;AAC7D,QAAA,MAAMtB,EAAAA,CAAGuB,SAAS,CAACL,QAAAA,EAAUd,OAAAA,EAAS,OAAA,CAAA;AAEtCjB,QAAAA,CAAAA,aAAAA,GAAAA,QAAAA,CAASsB,GAAG,CAACI,MAAAA,CAAOF,IAAI,CAAA,MAAA,IAAA,IAAxBxB,aAAAA,KAAAA,MAAAA,GAAAA,MAAAA,GAAAA,aAAAA,CAA2BuB,GAAG,CAACG,MAAAA,CAAOL,EAAE,EAAEK,MAAAA,CAAAA;AAC9C,IAAA,CAAA;IAEA,MAAMJ,GAAAA,GAAM,CAAmBE,IAAAA,EAAkBH,EAAAA,GAAAA;AACtCrB,QAAAA,IAAAA,aAAAA;QAAP,OAAA,CAAOA,aAAAA,GAAAA,SAASsB,GAAG,CAACE,mBAAbxB,aAAAA,KAAAA,MAAAA,GAAAA,MAAAA,GAAAA,aAAAA,CAAoBsB,GAAG,CAACD,EAAAA,CAAAA;AACnC,IAAA,CAAA;AAEA,IAAA,MAAMgB,SAAS,CAAmBb,IAAAA,GAAAA;;AACZxB,QAAAA,IAAAA,aAAAA;AAAlB,QAAA,OAAOsC,KAAAA,CAAMC,IAAI,CAAA,CAAA,IAAA,GAAA,CAACvC,aAAAA,GAAAA,QAAAA,CAASsB,GAAG,CAACE,IAAAA,CAAAA,MAAAA,IAAAA,IAAbxB,aAAAA,KAAAA,MAAAA,GAAAA,MAAAA,GAAAA,aAAAA,CAAoBwC,MAAM,EAAA,MAAA,IAAA,IAAA,IAAA,KAAA,MAAA,GAAA,IAAA,GAAM,EAAE,CAAA;AACxD,IAAA,CAAA;AAEA,IAAA,MAAMC,SAAS,CAACC,KAAAA,GAAAA;QACZ,MAAMC,eAAAA,GAAkBD,MAAME,WAAW,EAAA;AACzC,QAAA,MAAMC,UAAoB,EAAE;AAE5B,QAAA,KAAK,MAAMC,SAAAA,IAAa9C,QAAAA,CAASwC,MAAM,EAAA,CAAI;AACvC,YAAA,KAAK,MAAMd,MAAAA,IAAUoB,SAAAA,CAAUN,MAAM,EAAA,CAAI;AACrC,gBAAA,IAAId,OAAOqB,IAAI,CAACH,WAAW,EAAA,CAAGI,QAAQ,CAACL,eAAAA,CAAAA,EAAkB;AACrDE,oBAAAA,OAAAA,CAAQI,IAAI,CAACvB,MAAAA,CAAAA;AACjB,gBAAA;AACJ,YAAA;AACJ,QAAA;QAEA,OAAOmB,OAAAA;AACX,IAAA,CAAA;AAEA,IAAA,MAAMK,mBAAmB,CAACC,QAAAA,GAAAA;AACtB,QAAA,MAAMC,UAAAA,GAAaD,QAAAA,CAASP,WAAW,EAAA,CAAGS,IAAI,EAAA;AAE9C,QAAA,KAAK,MAAMP,SAAAA,IAAa9C,QAAAA,CAASwC,MAAM,EAAA,CAAI;AACvC,YAAA,KAAK,MAAMd,MAAAA,IAAUoB,SAAAA,CAAUN,MAAM,EAAA,CAAI;;AAErC,gBAAA,MAAMc,oBAAAA,GAAuB5B,MAAAA;gBAC7B,MAAM6B,QAAAA,GAAWD,qBAAqBE,WAAW;gBACjD,IAAID,QAAAA,KAAAA,IAAAA,IAAAA,QAAAA,KAAAA,MAAAA,GAAAA,MAAAA,GAAAA,QAAAA,CAAUE,IAAI,CAACC,CAAAA,CAAAA,GAAKA,CAAAA,CAAEd,WAAW,EAAA,KAAOQ,UAAAA,CAAAA,EAAa;oBACrD,OAAO1B,MAAAA;AACX,gBAAA;AACJ,YAAA;AACJ,QAAA;QAEA,OAAOiC,SAAAA;AACX,IAAA,CAAA;AAEA,IAAA,MAAMC,KAAAA,GAAQ,IAAA;AACV,QAAA,KAAK,MAAMd,SAAAA,IAAa9C,QAAAA,CAASwC,MAAM,EAAA,CAAI;AACvCM,YAAAA,SAAAA,CAAUc,KAAK,EAAA;AACnB,QAAA;AACJ,IAAA,CAAA;IAEA,OAAO;AAAE1D,QAAAA,IAAAA;AAAMuB,QAAAA,IAAAA;AAAMH,QAAAA,GAAAA;AAAKe,QAAAA,MAAAA;AAAQI,QAAAA,MAAAA;AAAQS,QAAAA,gBAAAA;AAAkBU,QAAAA;AAAM,KAAA;AACtE;;;;"}
1
+ {"version":3,"file":"storage.js","sources":["../../src/context/storage.ts"],"sourcesContent":["/**\n * Context Storage\n * \n * Handles loading and saving entity YAML files from context directories.\n * Supports hierarchical loading where later directories override earlier ones.\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 yaml from 'js-yaml';\nimport * as fs from 'fs/promises';\nimport * as path from 'node:path';\nimport { Entity, EntityType } from './types';\n\nexport interface StorageInstance {\n load(contextDirs: string[]): Promise<void>;\n save(entity: Entity, targetDir: string): Promise<void>;\n get<T extends Entity>(type: EntityType, id: string): T | undefined;\n getAll<T extends Entity>(type: EntityType): T[];\n search(query: string): Entity[];\n findBySoundsLike(phonetic: string): Entity | undefined;\n clear(): void;\n}\n\ntype DirectoryName = 'people' | 'projects' | 'companies' | 'terms';\n\nconst DIRECTORY_TO_TYPE: Record<DirectoryName, EntityType> = {\n 'people': 'person',\n 'projects': 'project',\n 'companies': 'company',\n 'terms': 'term',\n};\n\nconst TYPE_TO_DIRECTORY: Record<EntityType, DirectoryName> = {\n 'person': 'people',\n 'project': 'projects',\n 'company': 'companies',\n 'term': 'terms',\n};\n\nexport const create = (): StorageInstance => {\n const entities: Map<EntityType, Map<string, Entity>> = new Map([\n ['person', new Map()],\n ['project', new Map()],\n ['company', new Map()],\n ['term', new Map()],\n ]);\n\n const load = async (contextDirs: string[]): Promise<void> => {\n // Load from all context directories (later directories override)\n for (const contextDir of contextDirs) {\n for (const dirName of Object.keys(DIRECTORY_TO_TYPE) as DirectoryName[]) {\n const typeDir = path.join(contextDir, dirName);\n const entityType = DIRECTORY_TO_TYPE[dirName];\n \n try {\n const files = await fs.readdir(typeDir);\n for (const file of files) {\n if (!file.endsWith('.yaml') && !file.endsWith('.yml')) continue;\n \n const content = await fs.readFile(path.join(typeDir, file), 'utf-8');\n const parsed = yaml.load(content) as Partial<Entity>;\n \n if (parsed && parsed.id) {\n entities.get(entityType)?.set(parsed.id, {\n ...parsed,\n type: entityType,\n } as Entity);\n }\n }\n } catch {\n // Directory doesn't exist, skip\n }\n }\n }\n };\n\n const save = async (entity: Entity, targetDir: string): Promise<void> => {\n const dirName = TYPE_TO_DIRECTORY[entity.type];\n const dirPath = path.join(targetDir, 'context', dirName);\n await fs.mkdir(dirPath, { recursive: true });\n \n const filePath = path.join(dirPath, `${entity.id}.yaml`);\n \n // Remove type from saved YAML (it's inferred from directory)\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { type: _entityType, ...entityWithoutType } = entity;\n const content = yaml.dump(entityWithoutType, { lineWidth: -1 });\n await fs.writeFile(filePath, content, 'utf-8');\n \n entities.get(entity.type)?.set(entity.id, entity);\n };\n\n const get = <T extends Entity>(type: EntityType, id: string): T | undefined => {\n return entities.get(type)?.get(id) as T | undefined;\n };\n\n const getAll = <T extends Entity>(type: EntityType): T[] => {\n return Array.from(entities.get(type)?.values() ?? []) as T[];\n };\n\n const search = (query: string): Entity[] => {\n const normalizedQuery = query.toLowerCase();\n const results: Entity[] = [];\n \n for (const entityMap of entities.values()) {\n for (const entity of entityMap.values()) {\n if (entity.name.toLowerCase().includes(normalizedQuery)) {\n results.push(entity);\n }\n }\n }\n \n return results;\n };\n\n const findBySoundsLike = (phonetic: string): Entity | undefined => {\n const normalized = phonetic.toLowerCase().trim();\n \n for (const entityMap of entities.values()) {\n for (const entity of entityMap.values()) {\n // Check sounds_like field on entities that have it\n const entityWithSoundsLike = entity as Entity & { sounds_like?: string[] };\n const variants = entityWithSoundsLike.sounds_like;\n if (variants?.some(v => v.toLowerCase() === normalized)) {\n return entity;\n }\n }\n }\n \n return undefined;\n };\n\n const clear = (): void => {\n for (const entityMap of entities.values()) {\n entityMap.clear();\n }\n };\n\n return { load, save, get, getAll, search, findBySoundsLike, clear };\n};\n\n"],"names":["DIRECTORY_TO_TYPE","TYPE_TO_DIRECTORY","create","entities","Map","load","contextDirs","contextDir","dirName","Object","keys","typeDir","path","join","entityType","files","fs","readdir","file","endsWith","content","readFile","parsed","yaml","id","get","set","type","save","entity","targetDir","dirPath","mkdir","recursive","filePath","_entityType","entityWithoutType","dump","lineWidth","writeFile","getAll","Array","from","values","search","query","normalizedQuery","toLowerCase","results","entityMap","name","includes","push","findBySoundsLike","phonetic","normalized","trim","entityWithSoundsLike","variants","sounds_like","some","v","undefined","clear"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import * as path from 'path';
1
+ import * as path from 'node:path';
2
2
  import * as fs from 'fs/promises';
3
3
  import { getLogger } from '../logging.js';
4
4
  import { formatMetadataMarkdown } from '../util/metadata.js';
@@ -1 +1 @@
1
- {"version":3,"file":"manager.js","sources":["../../src/output/manager.ts"],"sourcesContent":["/**\n * Output Manager\n *\n * Manages intermediate files and final output destinations.\n * Follows the kodrdriv pattern for debugging and intermediate file management.\n */\n\nimport * as path from 'path';\nimport * as fs from 'fs/promises';\nimport { OutputConfig, IntermediateFiles, OutputPaths } from './types';\nimport * as Logging from '../logging';\nimport * as Metadata from '../util/metadata';\n\nexport interface ManagerInstance {\n createOutputPaths(\n audioFile: string,\n routedDestination: string,\n hash: string,\n date: Date\n ): OutputPaths;\n \n ensureDirectories(paths: OutputPaths): Promise<void>;\n \n writeIntermediate(\n paths: OutputPaths,\n type: keyof IntermediateFiles,\n content: unknown\n ): Promise<string>;\n \n writeTranscript(paths: OutputPaths, content: string, metadata?: Metadata.TranscriptMetadata): Promise<string>;\n \n cleanIntermediates(paths: OutputPaths): Promise<void>;\n}\n\nexport const create = (config: OutputConfig): ManagerInstance => {\n const logger = Logging.getLogger();\n \n const formatTimestamp = (date: Date): string => {\n // Format: YYYY-MM-DD-HHmm (full year, dashes for separation)\n const pad = (n: number) => n.toString().padStart(2, '0');\n const year = date.getFullYear().toString();\n const month = pad(date.getMonth() + 1);\n const day = pad(date.getDate());\n const hours = pad(date.getHours());\n const minutes = pad(date.getMinutes());\n return `${year}-${month}-${day}-${hours}${minutes}`;\n };\n \n const createOutputPaths = (\n _audioFile: string,\n routedDestination: string,\n hash: string,\n date: Date\n ): OutputPaths => {\n const timestamp = formatTimestamp(date);\n const shortHash = hash.slice(0, 6);\n // Hash at the end for easier filename correlation\n const buildFilename = (type: string, ext: string) => `${timestamp}-${type}-${shortHash}${ext}`;\n \n const intermediateDir = config.intermediateDir;\n \n return {\n final: routedDestination,\n intermediate: {\n transcript: path.join(intermediateDir, buildFilename('transcript', '.json')),\n context: path.join(intermediateDir, buildFilename('context', '.json')),\n request: path.join(intermediateDir, buildFilename('request', '.json')),\n response: path.join(intermediateDir, buildFilename('response', '.json')),\n reflection: path.join(intermediateDir, buildFilename('reflection', '.md')),\n session: path.join(intermediateDir, buildFilename('session', '.json')),\n },\n };\n };\n \n const ensureDirectories = async (paths: OutputPaths): Promise<void> => {\n // Ensure intermediate directory\n await fs.mkdir(path.dirname(paths.intermediate.transcript), { recursive: true });\n \n // Ensure final directory\n await fs.mkdir(path.dirname(paths.final), { recursive: true });\n \n logger.debug('Ensured output directories', {\n intermediate: path.dirname(paths.intermediate.transcript),\n final: path.dirname(paths.final),\n });\n };\n \n const writeIntermediate = async (\n paths: OutputPaths,\n type: keyof IntermediateFiles,\n content: unknown\n ): Promise<string> => {\n const filePath = paths.intermediate[type];\n if (!filePath) {\n throw new Error(`Invalid intermediate type: ${type}`);\n }\n \n const contentStr = typeof content === 'string' \n ? content \n : JSON.stringify(content, null, 2);\n \n await fs.writeFile(filePath, contentStr, 'utf-8');\n logger.debug('Wrote intermediate file', { type, path: filePath });\n \n return filePath;\n };\n \n const writeTranscript = async (\n paths: OutputPaths,\n content: string,\n metadata?: Metadata.TranscriptMetadata\n ): Promise<string> => {\n // Prepend metadata if provided\n let finalContent = content;\n if (metadata) {\n const metadataSection = Metadata.formatMetadataMarkdown(metadata);\n finalContent = metadataSection + content;\n }\n \n await fs.writeFile(paths.final, finalContent, 'utf-8');\n logger.info('Wrote final transcript', { path: paths.final });\n return paths.final;\n };\n \n const cleanIntermediates = async (paths: OutputPaths): Promise<void> => {\n if (config.keepIntermediates) {\n logger.debug('Keeping intermediate files');\n return;\n }\n \n for (const [type, filePath] of Object.entries(paths.intermediate)) {\n if (filePath) {\n try {\n await fs.unlink(filePath);\n logger.debug('Removed intermediate file', { type, path: filePath });\n } catch {\n // File might not exist, that's OK\n }\n }\n }\n };\n \n return {\n createOutputPaths,\n ensureDirectories,\n writeIntermediate,\n writeTranscript,\n cleanIntermediates,\n };\n};\n\n"],"names":["create","config","logger","Logging","formatTimestamp","date","pad","n","toString","padStart","year","getFullYear","month","getMonth","day","getDate","hours","getHours","minutes","getMinutes","createOutputPaths","_audioFile","routedDestination","hash","timestamp","shortHash","slice","buildFilename","type","ext","intermediateDir","final","intermediate","transcript","path","join","context","request","response","reflection","session","ensureDirectories","paths","fs","mkdir","dirname","recursive","debug","writeIntermediate","content","filePath","Error","contentStr","JSON","stringify","writeFile","writeTranscript","metadata","finalContent","metadataSection","Metadata","info","cleanIntermediates","keepIntermediates","Object","entries","unlink"],"mappings":"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"}
1
+ {"version":3,"file":"manager.js","sources":["../../src/output/manager.ts"],"sourcesContent":["/**\n * Output Manager\n *\n * Manages intermediate files and final output destinations.\n * Follows the kodrdriv pattern for debugging and intermediate file management.\n */\n\nimport * as path from 'node:path';\nimport * as fs from 'fs/promises';\nimport { OutputConfig, IntermediateFiles, OutputPaths } from './types';\nimport * as Logging from '../logging';\nimport * as Metadata from '../util/metadata';\n\nexport interface ManagerInstance {\n createOutputPaths(\n audioFile: string,\n routedDestination: string,\n hash: string,\n date: Date\n ): OutputPaths;\n \n ensureDirectories(paths: OutputPaths): Promise<void>;\n \n writeIntermediate(\n paths: OutputPaths,\n type: keyof IntermediateFiles,\n content: unknown\n ): Promise<string>;\n \n writeTranscript(paths: OutputPaths, content: string, metadata?: Metadata.TranscriptMetadata): Promise<string>;\n \n cleanIntermediates(paths: OutputPaths): Promise<void>;\n}\n\nexport const create = (config: OutputConfig): ManagerInstance => {\n const logger = Logging.getLogger();\n \n const formatTimestamp = (date: Date): string => {\n // Format: YYYY-MM-DD-HHmm (full year, dashes for separation)\n const pad = (n: number) => n.toString().padStart(2, '0');\n const year = date.getFullYear().toString();\n const month = pad(date.getMonth() + 1);\n const day = pad(date.getDate());\n const hours = pad(date.getHours());\n const minutes = pad(date.getMinutes());\n return `${year}-${month}-${day}-${hours}${minutes}`;\n };\n \n const createOutputPaths = (\n _audioFile: string,\n routedDestination: string,\n hash: string,\n date: Date\n ): OutputPaths => {\n const timestamp = formatTimestamp(date);\n const shortHash = hash.slice(0, 6);\n // Hash at the end for easier filename correlation\n const buildFilename = (type: string, ext: string) => `${timestamp}-${type}-${shortHash}${ext}`;\n \n const intermediateDir = config.intermediateDir;\n \n return {\n final: routedDestination,\n intermediate: {\n transcript: path.join(intermediateDir, buildFilename('transcript', '.json')),\n context: path.join(intermediateDir, buildFilename('context', '.json')),\n request: path.join(intermediateDir, buildFilename('request', '.json')),\n response: path.join(intermediateDir, buildFilename('response', '.json')),\n reflection: path.join(intermediateDir, buildFilename('reflection', '.md')),\n session: path.join(intermediateDir, buildFilename('session', '.json')),\n },\n };\n };\n \n const ensureDirectories = async (paths: OutputPaths): Promise<void> => {\n // Ensure intermediate directory\n await fs.mkdir(path.dirname(paths.intermediate.transcript), { recursive: true });\n \n // Ensure final directory\n await fs.mkdir(path.dirname(paths.final), { recursive: true });\n \n logger.debug('Ensured output directories', {\n intermediate: path.dirname(paths.intermediate.transcript),\n final: path.dirname(paths.final),\n });\n };\n \n const writeIntermediate = async (\n paths: OutputPaths,\n type: keyof IntermediateFiles,\n content: unknown\n ): Promise<string> => {\n const filePath = paths.intermediate[type];\n if (!filePath) {\n throw new Error(`Invalid intermediate type: ${type}`);\n }\n \n const contentStr = typeof content === 'string' \n ? content \n : JSON.stringify(content, null, 2);\n \n await fs.writeFile(filePath, contentStr, 'utf-8');\n logger.debug('Wrote intermediate file', { type, path: filePath });\n \n return filePath;\n };\n \n const writeTranscript = async (\n paths: OutputPaths,\n content: string,\n metadata?: Metadata.TranscriptMetadata\n ): Promise<string> => {\n // Prepend metadata if provided\n let finalContent = content;\n if (metadata) {\n const metadataSection = Metadata.formatMetadataMarkdown(metadata);\n finalContent = metadataSection + content;\n }\n \n await fs.writeFile(paths.final, finalContent, 'utf-8');\n logger.info('Wrote final transcript', { path: paths.final });\n return paths.final;\n };\n \n const cleanIntermediates = async (paths: OutputPaths): Promise<void> => {\n if (config.keepIntermediates) {\n logger.debug('Keeping intermediate files');\n return;\n }\n \n for (const [type, filePath] of Object.entries(paths.intermediate)) {\n if (filePath) {\n try {\n await fs.unlink(filePath);\n logger.debug('Removed intermediate file', { type, path: filePath });\n } catch {\n // File might not exist, that's OK\n }\n }\n }\n };\n \n return {\n createOutputPaths,\n ensureDirectories,\n writeIntermediate,\n writeTranscript,\n cleanIntermediates,\n };\n};\n\n"],"names":["create","config","logger","Logging","formatTimestamp","date","pad","n","toString","padStart","year","getFullYear","month","getMonth","day","getDate","hours","getHours","minutes","getMinutes","createOutputPaths","_audioFile","routedDestination","hash","timestamp","shortHash","slice","buildFilename","type","ext","intermediateDir","final","intermediate","transcript","path","join","context","request","response","reflection","session","ensureDirectories","paths","fs","mkdir","dirname","recursive","debug","writeIntermediate","content","filePath","Error","contentStr","JSON","stringify","writeFile","writeTranscript","metadata","finalContent","metadataSection","Metadata","info","cleanIntermediates","keepIntermediates","Object","entries","unlink"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import * as path from 'path';
1
+ import * as path from 'node:path';
2
2
  import { getLogger } from '../logging.js';
3
3
  import { create as create$1 } from '../util/storage.js';
4
4
 
@@ -1 +1 @@
1
- {"version":3,"file":"complete.js","sources":["../../src/phases/complete.ts"],"sourcesContent":["/**\n * Complete Phase\n * \n * Handles post-processing completion: moving audio files to the processed directory\n * after successful transcription.\n */\n\nimport * as path from 'path';\nimport * as Logging from '@/logging';\nimport * as Storage from '@/util/storage';\n\nexport type FilesystemStructure = 'none' | 'year' | 'month' | 'day';\n\nexport interface CompleteConfig {\n processedDirectory: string;\n outputStructure?: FilesystemStructure;\n dryRun?: boolean;\n}\n\nexport interface Instance {\n complete(audioFile: string, hash: string, creationTime: Date, subject?: string): Promise<string>;\n}\n\nexport const create = (config: CompleteConfig): Instance => {\n const logger = Logging.getLogger();\n const storage = Storage.create({ log: logger.debug });\n\n // Build directory path matching output structure (year/month)\n const buildDirectoryPath = (date: Date): string => {\n const structure = config.outputStructure || 'month';\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 config.processedDirectory;\n case 'year':\n return path.join(config.processedDirectory, year);\n case 'month':\n return path.join(config.processedDirectory, year, month);\n case 'day':\n return path.join(config.processedDirectory, year, month, day);\n }\n };\n\n // Format date portion of filename based on directory structure\n // Don't repeat info already in the path\n const formatDateForFilename = (date: Date): string => {\n const structure = config.outputStructure || 'month';\n const pad = (n: number) => n.toString().padStart(2, '0');\n const year = date.getFullYear().toString();\n const month = pad(date.getMonth() + 1);\n const day = pad(date.getDate());\n const hours = pad(date.getHours());\n const minutes = pad(date.getMinutes());\n\n switch (structure) {\n case 'day':\n // Path has year/month/day - only time in filename\n return `${hours}${minutes}`;\n case 'month':\n // Path has year/month - day and time in filename\n return `${day}-${hours}${minutes}`;\n case 'year':\n // Path has year - month, day and time in filename\n return `${month}-${day}-${hours}${minutes}`;\n case 'none':\n // No date in path - full date in filename (YYYY-MM-DD-HHmm)\n return `${year}-${month}-${day}-${hours}${minutes}`;\n }\n };\n\n const complete = async (\n audioFile: string, \n hash: string, \n creationTime: Date, \n subject?: string\n ): Promise<string> => {\n logger.debug('Completing file processing for %s', audioFile);\n\n if (config.dryRun) {\n logger.info('Dry run: would move %s to processed directory', audioFile);\n return audioFile;\n }\n\n if (!config.processedDirectory) {\n logger.debug('No processed directory configured, skipping file move');\n return audioFile;\n }\n\n // Build the target directory path with year/month structure\n const targetDir = buildDirectoryPath(creationTime);\n\n // Create the target directory if it doesn't exist\n if (!await storage.exists(targetDir)) {\n logger.debug('Creating processed directory %s', targetDir);\n await storage.createDirectory(targetDir);\n }\n\n // Get the file extension\n const fileExt = path.extname(audioFile);\n\n // Format date for filename (adjusted based on directory structure)\n const dateStr = formatDateForFilename(creationTime);\n\n // Create new filename: <date>-<subject>-<hash>\n // Hash is at the end for easier correlation with output files\n // Clean subject by removing special characters and spaces\n const shortHash = hash.substring(0, 6);\n let newFilename: string;\n if (subject) {\n const cleanSubject = subject\n .replace(/[^a-zA-Z0-9]/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '')\n .toLowerCase()\n .substring(0, 50);\n newFilename = `${dateStr}-${cleanSubject}-${shortHash}${fileExt}`;\n } else {\n newFilename = `${dateStr}-${shortHash}${fileExt}`;\n }\n \n const newFilePath = path.join(targetDir, newFilename);\n\n try {\n // Read the original file\n const fileContent = await storage.readFile(audioFile, 'binary');\n\n // Write to the new location\n logger.debug('Moving file from %s to %s', audioFile, newFilePath);\n await storage.writeFile(newFilePath, fileContent, 'binary');\n\n // Remove the original file\n await storage.deleteFile(audioFile);\n\n logger.info('Moved to processed: %s', newFilePath);\n return newFilePath;\n } catch (error) {\n logger.error('Failed to move file to processed directory: %s', error);\n // Don't fail the whole process, just log the error\n return audioFile;\n }\n };\n\n return {\n complete,\n };\n};\n\n"],"names":["create","config","logger","Logging","storage","Storage","log","debug","buildDirectoryPath","date","structure","outputStructure","year","getFullYear","toString","month","getMonth","day","getDate","processedDirectory","path","join","formatDateForFilename","pad","n","padStart","hours","getHours","minutes","getMinutes","complete","audioFile","hash","creationTime","subject","dryRun","info","targetDir","exists","createDirectory","fileExt","extname","dateStr","shortHash","substring","newFilename","cleanSubject","replace","toLowerCase","newFilePath","fileContent","readFile","writeFile","deleteFile","error"],"mappings":";;;;AAuBO,MAAMA,SAAS,CAACC,MAAAA,GAAAA;IACnB,MAAMC,MAAAA,GAASC,SAAiB,EAAA;IAChC,MAAMC,OAAAA,GAAUC,QAAc,CAAC;AAAEC,QAAAA,GAAAA,EAAKJ,OAAOK;AAAM,KAAA,CAAA;;AAGnD,IAAA,MAAMC,qBAAqB,CAACC,IAAAA,GAAAA;QACxB,MAAMC,SAAAA,GAAYT,MAAAA,CAAOU,eAAe,IAAI,OAAA;AAC5C,QAAA,MAAMC,IAAAA,GAAOH,IAAAA,CAAKI,WAAW,EAAA,CAAGC,QAAQ,EAAA;QACxC,MAAMC,KAAAA,GAAQ,CAACN,IAAAA,CAAKO,QAAQ,EAAA,GAAK,CAAA,EAAGF,QAAQ,EAAA;AAC5C,QAAA,MAAMG,GAAAA,GAAMR,IAAAA,CAAKS,OAAO,EAAA,CAAGJ,QAAQ,EAAA;QAEnC,OAAQJ,SAAAA;YACJ,KAAK,MAAA;AACD,gBAAA,OAAOT,OAAOkB,kBAAkB;YACpC,KAAK,MAAA;AACD,gBAAA,OAAOC,IAAAA,CAAKC,IAAI,CAACpB,MAAAA,CAAOkB,kBAAkB,EAAEP,IAAAA,CAAAA;YAChD,KAAK,OAAA;AACD,gBAAA,OAAOQ,KAAKC,IAAI,CAACpB,MAAAA,CAAOkB,kBAAkB,EAAEP,IAAAA,EAAMG,KAAAA,CAAAA;YACtD,KAAK,KAAA;AACD,gBAAA,OAAOK,KAAKC,IAAI,CAACpB,OAAOkB,kBAAkB,EAAEP,MAAMG,KAAAA,EAAOE,GAAAA,CAAAA;AACjE;AACJ,IAAA,CAAA;;;AAIA,IAAA,MAAMK,wBAAwB,CAACb,IAAAA,GAAAA;QAC3B,MAAMC,SAAAA,GAAYT,MAAAA,CAAOU,eAAe,IAAI,OAAA;QAC5C,MAAMY,GAAAA,GAAM,CAACC,CAAAA,GAAcA,CAAAA,CAAEV,QAAQ,EAAA,CAAGW,QAAQ,CAAC,CAAA,EAAG,GAAA,CAAA;AACpD,QAAA,MAAMb,IAAAA,GAAOH,IAAAA,CAAKI,WAAW,EAAA,CAAGC,QAAQ,EAAA;AACxC,QAAA,MAAMC,KAAAA,GAAQQ,GAAAA,CAAId,IAAAA,CAAKO,QAAQ,EAAA,GAAK,CAAA,CAAA;QACpC,MAAMC,GAAAA,GAAMM,GAAAA,CAAId,IAAAA,CAAKS,OAAO,EAAA,CAAA;QAC5B,MAAMQ,KAAAA,GAAQH,GAAAA,CAAId,IAAAA,CAAKkB,QAAQ,EAAA,CAAA;QAC/B,MAAMC,OAAAA,GAAUL,GAAAA,CAAId,IAAAA,CAAKoB,UAAU,EAAA,CAAA;QAEnC,OAAQnB,SAAAA;YACJ,KAAK,KAAA;;gBAED,OAAO,CAAA,EAAGgB,QAAQE,OAAAA,CAAAA,CAAS;YAC/B,KAAK,OAAA;;AAED,gBAAA,OAAO,CAAA,EAAGX,GAAAA,CAAI,CAAC,EAAES,QAAQE,OAAAA,CAAAA,CAAS;YACtC,KAAK,MAAA;;gBAED,OAAO,CAAA,EAAGb,MAAM,CAAC,EAAEE,IAAI,CAAC,EAAES,QAAQE,OAAAA,CAAAA,CAAS;YAC/C,KAAK,MAAA;;gBAED,OAAO,CAAA,EAAGhB,IAAAA,CAAK,CAAC,EAAEG,KAAAA,CAAM,CAAC,EAAEE,GAAAA,CAAI,CAAC,EAAES,KAAAA,CAAAA,EAAQE,OAAAA,CAAAA,CAAS;AAC3D;AACJ,IAAA,CAAA;AAEA,IAAA,MAAME,QAAAA,GAAW,OACbC,SAAAA,EACAC,IAAAA,EACAC,YAAAA,EACAC,OAAAA,GAAAA;QAEAhC,MAAAA,CAAOK,KAAK,CAAC,mCAAA,EAAqCwB,SAAAA,CAAAA;QAElD,IAAI9B,MAAAA,CAAOkC,MAAM,EAAE;YACfjC,MAAAA,CAAOkC,IAAI,CAAC,+CAAA,EAAiDL,SAAAA,CAAAA;YAC7D,OAAOA,SAAAA;AACX,QAAA;QAEA,IAAI,CAAC9B,MAAAA,CAAOkB,kBAAkB,EAAE;AAC5BjB,YAAAA,MAAAA,CAAOK,KAAK,CAAC,uDAAA,CAAA;YACb,OAAOwB,SAAAA;AACX,QAAA;;AAGA,QAAA,MAAMM,YAAY7B,kBAAAA,CAAmByB,YAAAA,CAAAA;;AAGrC,QAAA,IAAI,CAAC,MAAM7B,OAAAA,CAAQkC,MAAM,CAACD,SAAAA,CAAAA,EAAY;YAClCnC,MAAAA,CAAOK,KAAK,CAAC,iCAAA,EAAmC8B,SAAAA,CAAAA;YAChD,MAAMjC,OAAAA,CAAQmC,eAAe,CAACF,SAAAA,CAAAA;AAClC,QAAA;;QAGA,MAAMG,OAAAA,GAAUpB,IAAAA,CAAKqB,OAAO,CAACV,SAAAA,CAAAA;;AAG7B,QAAA,MAAMW,UAAUpB,qBAAAA,CAAsBW,YAAAA,CAAAA;;;;AAKtC,QAAA,MAAMU,SAAAA,GAAYX,IAAAA,CAAKY,SAAS,CAAC,CAAA,EAAG,CAAA,CAAA;QACpC,IAAIC,WAAAA;AACJ,QAAA,IAAIX,OAAAA,EAAS;AACT,YAAA,MAAMY,eAAeZ,OAAAA,CAChBa,OAAO,CAAC,eAAA,EAAiB,GAAA,CAAA,CACzBA,OAAO,CAAC,KAAA,EAAO,GAAA,CAAA,CACfA,OAAO,CAAC,QAAA,EAAU,EAAA,CAAA,CAClBC,WAAW,EAAA,CACXJ,SAAS,CAAC,CAAA,EAAG,EAAA,CAAA;YAClBC,WAAAA,GAAc,CAAA,EAAGH,QAAQ,CAAC,EAAEI,aAAa,CAAC,EAAEH,YAAYH,OAAAA,CAAAA,CAAS;QACrE,CAAA,MAAO;AACHK,YAAAA,WAAAA,GAAc,CAAA,EAAGH,OAAAA,CAAQ,CAAC,EAAEC,YAAYH,OAAAA,CAAAA,CAAS;AACrD,QAAA;AAEA,QAAA,MAAMS,WAAAA,GAAc7B,IAAAA,CAAKC,IAAI,CAACgB,SAAAA,EAAWQ,WAAAA,CAAAA;QAEzC,IAAI;;AAEA,YAAA,MAAMK,WAAAA,GAAc,MAAM9C,OAAAA,CAAQ+C,QAAQ,CAACpB,SAAAA,EAAW,QAAA,CAAA;;YAGtD7B,MAAAA,CAAOK,KAAK,CAAC,2BAAA,EAA6BwB,SAAAA,EAAWkB,WAAAA,CAAAA;AACrD,YAAA,MAAM7C,OAAAA,CAAQgD,SAAS,CAACH,WAAAA,EAAaC,WAAAA,EAAa,QAAA,CAAA;;YAGlD,MAAM9C,OAAAA,CAAQiD,UAAU,CAACtB,SAAAA,CAAAA;YAEzB7B,MAAAA,CAAOkC,IAAI,CAAC,wBAAA,EAA0Ba,WAAAA,CAAAA;YACtC,OAAOA,WAAAA;AACX,QAAA,CAAA,CAAE,OAAOK,KAAAA,EAAO;YACZpD,MAAAA,CAAOoD,KAAK,CAAC,gDAAA,EAAkDA,KAAAA,CAAAA;;YAE/D,OAAOvB,SAAAA;AACX,QAAA;AACJ,IAAA,CAAA;IAEA,OAAO;AACHD,QAAAA;AACJ,KAAA;AACJ;;;;"}
1
+ {"version":3,"file":"complete.js","sources":["../../src/phases/complete.ts"],"sourcesContent":["/**\n * Complete Phase\n * \n * Handles post-processing completion: moving audio files to the processed directory\n * after successful transcription.\n */\n\nimport * as path from 'node:path';\nimport * as Logging from '@/logging';\nimport * as Storage from '@/util/storage';\n\nexport type FilesystemStructure = 'none' | 'year' | 'month' | 'day';\n\nexport interface CompleteConfig {\n processedDirectory: string;\n outputStructure?: FilesystemStructure;\n dryRun?: boolean;\n}\n\nexport interface Instance {\n complete(audioFile: string, hash: string, creationTime: Date, subject?: string): Promise<string>;\n}\n\nexport const create = (config: CompleteConfig): Instance => {\n const logger = Logging.getLogger();\n const storage = Storage.create({ log: logger.debug });\n\n // Build directory path matching output structure (year/month)\n const buildDirectoryPath = (date: Date): string => {\n const structure = config.outputStructure || 'month';\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 config.processedDirectory;\n case 'year':\n return path.join(config.processedDirectory, year);\n case 'month':\n return path.join(config.processedDirectory, year, month);\n case 'day':\n return path.join(config.processedDirectory, year, month, day);\n }\n };\n\n // Format date portion of filename based on directory structure\n // Don't repeat info already in the path\n const formatDateForFilename = (date: Date): string => {\n const structure = config.outputStructure || 'month';\n const pad = (n: number) => n.toString().padStart(2, '0');\n const year = date.getFullYear().toString();\n const month = pad(date.getMonth() + 1);\n const day = pad(date.getDate());\n const hours = pad(date.getHours());\n const minutes = pad(date.getMinutes());\n\n switch (structure) {\n case 'day':\n // Path has year/month/day - only time in filename\n return `${hours}${minutes}`;\n case 'month':\n // Path has year/month - day and time in filename\n return `${day}-${hours}${minutes}`;\n case 'year':\n // Path has year - month, day and time in filename\n return `${month}-${day}-${hours}${minutes}`;\n case 'none':\n // No date in path - full date in filename (YYYY-MM-DD-HHmm)\n return `${year}-${month}-${day}-${hours}${minutes}`;\n }\n };\n\n const complete = async (\n audioFile: string, \n hash: string, \n creationTime: Date, \n subject?: string\n ): Promise<string> => {\n logger.debug('Completing file processing for %s', audioFile);\n\n if (config.dryRun) {\n logger.info('Dry run: would move %s to processed directory', audioFile);\n return audioFile;\n }\n\n if (!config.processedDirectory) {\n logger.debug('No processed directory configured, skipping file move');\n return audioFile;\n }\n\n // Build the target directory path with year/month structure\n const targetDir = buildDirectoryPath(creationTime);\n\n // Create the target directory if it doesn't exist\n if (!await storage.exists(targetDir)) {\n logger.debug('Creating processed directory %s', targetDir);\n await storage.createDirectory(targetDir);\n }\n\n // Get the file extension\n const fileExt = path.extname(audioFile);\n\n // Format date for filename (adjusted based on directory structure)\n const dateStr = formatDateForFilename(creationTime);\n\n // Create new filename: <date>-<subject>-<hash>\n // Hash is at the end for easier correlation with output files\n // Clean subject by removing special characters and spaces\n const shortHash = hash.substring(0, 6);\n let newFilename: string;\n if (subject) {\n const cleanSubject = subject\n .replace(/[^a-zA-Z0-9]/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '')\n .toLowerCase()\n .substring(0, 50);\n newFilename = `${dateStr}-${cleanSubject}-${shortHash}${fileExt}`;\n } else {\n newFilename = `${dateStr}-${shortHash}${fileExt}`;\n }\n \n const newFilePath = path.join(targetDir, newFilename);\n\n try {\n // Read the original file\n const fileContent = await storage.readFile(audioFile, 'binary');\n\n // Write to the new location\n logger.debug('Moving file from %s to %s', audioFile, newFilePath);\n await storage.writeFile(newFilePath, fileContent, 'binary');\n\n // Remove the original file\n await storage.deleteFile(audioFile);\n\n logger.info('Moved to processed: %s', newFilePath);\n return newFilePath;\n } catch (error) {\n logger.error('Failed to move file to processed directory: %s', error);\n // Don't fail the whole process, just log the error\n return audioFile;\n }\n };\n\n return {\n complete,\n };\n};\n\n"],"names":["create","config","logger","Logging","storage","Storage","log","debug","buildDirectoryPath","date","structure","outputStructure","year","getFullYear","toString","month","getMonth","day","getDate","processedDirectory","path","join","formatDateForFilename","pad","n","padStart","hours","getHours","minutes","getMinutes","complete","audioFile","hash","creationTime","subject","dryRun","info","targetDir","exists","createDirectory","fileExt","extname","dateStr","shortHash","substring","newFilename","cleanSubject","replace","toLowerCase","newFilePath","fileContent","readFile","writeFile","deleteFile","error"],"mappings":"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"}
@@ -3,7 +3,7 @@ import { create as create$3 } from '../util/media.js';
3
3
  import { create as create$1 } from '../util/storage.js';
4
4
  import { create as create$2 } from '../util/dates.js';
5
5
  import { DEFAULT_INTERMEDIATE_DIRECTORY } from '../constants.js';
6
- import path__default from 'path';
6
+ import path__default from 'node:path';
7
7
 
8
8
  const create = (config, operator)=>{
9
9
  const logger = getLogger();
@@ -1 +1 @@
1
- {"version":3,"file":"locate.js","sources":["../../src/phases/locate.ts"],"sourcesContent":["import * as Logging from '@/logging';\nimport * as Media from '@/util/media';\nimport * as Storage from '@/util/storage';\nimport * as Dreadcabinet from '@theunwalked/dreadcabinet';\nimport * as Dates from '@/util/dates';\nimport { Config } from '@/protokoll';\nimport { DEFAULT_INTERMEDIATE_DIRECTORY } from '@/constants';\nimport path from 'path';\n\n// Helper function to promisify ffmpeg.\n\nexport interface Instance {\n locate: (audioFile: string) => Promise<{\n creationTime: Date;\n outputPath: string;\n contextPath: string;\n interimPath: string;\n transcriptionFilename: string;\n hash: string;\n audioFile: string;\n }>;\n}\n\nexport const create = (config: Config, operator: Dreadcabinet.Operator): Instance => {\n const logger = Logging.getLogger();\n const storage = Storage.create({ log: logger.debug });\n const dates = Dates.create({ timezone: config.timezone });\n const media = Media.create(logger);\n\n const locate = async (audioFile: string): Promise<{\n creationTime: Date;\n outputPath: string;\n contextPath: string;\n interimPath: string;\n transcriptionFilename: string;\n hash: string;\n audioFile: string;\n }> => {\n logger.debug('Processing file %s', audioFile);\n\n // Extract audio file creation time\n let creationTime = await media.getAudioCreationTime(audioFile);\n try {\n if (creationTime) {\n logger.info('Audio recording time: %s', creationTime.toISOString());\n } else {\n logger.warn('Could not determine audio recording time for %s, using current date', audioFile);\n creationTime = dates.now();\n }\n } catch (error: any) {\n logger.error('Error determining audio recording time for %s: %s, using current date', audioFile, error.message);\n creationTime = dates.now();\n }\n\n // Calculate the hash of file and output directory\n const hash = (await storage.hashFile(audioFile, 100)).substring(0, 8);\n const outputPath: string = await operator.constructOutputDirectory(creationTime);\n const transcriptionFilename = await operator.constructFilename(creationTime, 'transcription', hash);\n \n // Use output/protokoll for intermediate files instead of polluting output directory\n // This follows the kodrdriv pattern for debugging and intermediate file management\n const intermediateBase = DEFAULT_INTERMEDIATE_DIRECTORY;\n const shortHash = hash.substring(0, 6);\n const pad = (n: number) => n.toString().padStart(2, '0');\n const timestamp = `${creationTime.getFullYear().toString().slice(2)}${pad(creationTime.getMonth() + 1)}${pad(creationTime.getDate())}-${pad(creationTime.getHours())}${pad(creationTime.getMinutes())}`;\n const sessionDir = `${timestamp}-${shortHash}`;\n \n const interimPath: string = path.join(intermediateBase, sessionDir);\n await storage.createDirectory(interimPath);\n \n const contextPath: string = path.join(interimPath, 'context');\n await storage.createDirectory(contextPath);\n \n logger.debug('Intermediate files will be stored in: %s', interimPath);\n\n return {\n creationTime,\n outputPath,\n contextPath,\n interimPath,\n transcriptionFilename,\n hash,\n audioFile,\n };\n }\n\n return {\n locate,\n }\n}\n\n\n"],"names":["create","config","operator","logger","Logging","storage","Storage","log","debug","dates","Dates","timezone","media","Media","locate","audioFile","creationTime","getAudioCreationTime","info","toISOString","warn","now","error","message","hash","hashFile","substring","outputPath","constructOutputDirectory","transcriptionFilename","constructFilename","intermediateBase","DEFAULT_INTERMEDIATE_DIRECTORY","shortHash","pad","n","toString","padStart","timestamp","getFullYear","slice","getMonth","getDate","getHours","getMinutes","sessionDir","interimPath","path","join","createDirectory","contextPath"],"mappings":"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"}
1
+ {"version":3,"file":"locate.js","sources":["../../src/phases/locate.ts"],"sourcesContent":["import * as Logging from '@/logging';\nimport * as Media from '@/util/media';\nimport * as Storage from '@/util/storage';\nimport * as Dreadcabinet from '@theunwalked/dreadcabinet';\nimport * as Dates from '@/util/dates';\nimport { Config } from '@/protokoll';\nimport { DEFAULT_INTERMEDIATE_DIRECTORY } from '@/constants';\nimport path from 'node:path';\n\n// Helper function to promisify ffmpeg.\n\nexport interface Instance {\n locate: (audioFile: string) => Promise<{\n creationTime: Date;\n outputPath: string;\n contextPath: string;\n interimPath: string;\n transcriptionFilename: string;\n hash: string;\n audioFile: string;\n }>;\n}\n\nexport const create = (config: Config, operator: Dreadcabinet.Operator): Instance => {\n const logger = Logging.getLogger();\n const storage = Storage.create({ log: logger.debug });\n const dates = Dates.create({ timezone: config.timezone });\n const media = Media.create(logger);\n\n const locate = async (audioFile: string): Promise<{\n creationTime: Date;\n outputPath: string;\n contextPath: string;\n interimPath: string;\n transcriptionFilename: string;\n hash: string;\n audioFile: string;\n }> => {\n logger.debug('Processing file %s', audioFile);\n\n // Extract audio file creation time\n let creationTime = await media.getAudioCreationTime(audioFile);\n try {\n if (creationTime) {\n logger.info('Audio recording time: %s', creationTime.toISOString());\n } else {\n logger.warn('Could not determine audio recording time for %s, using current date', audioFile);\n creationTime = dates.now();\n }\n } catch (error: any) {\n logger.error('Error determining audio recording time for %s: %s, using current date', audioFile, error.message);\n creationTime = dates.now();\n }\n\n // Calculate the hash of file and output directory\n const hash = (await storage.hashFile(audioFile, 100)).substring(0, 8);\n const outputPath: string = await operator.constructOutputDirectory(creationTime);\n const transcriptionFilename = await operator.constructFilename(creationTime, 'transcription', hash);\n \n // Use output/protokoll for intermediate files instead of polluting output directory\n // This follows the kodrdriv pattern for debugging and intermediate file management\n const intermediateBase = DEFAULT_INTERMEDIATE_DIRECTORY;\n const shortHash = hash.substring(0, 6);\n const pad = (n: number) => n.toString().padStart(2, '0');\n const timestamp = `${creationTime.getFullYear().toString().slice(2)}${pad(creationTime.getMonth() + 1)}${pad(creationTime.getDate())}-${pad(creationTime.getHours())}${pad(creationTime.getMinutes())}`;\n const sessionDir = `${timestamp}-${shortHash}`;\n \n const interimPath: string = path.join(intermediateBase, sessionDir);\n await storage.createDirectory(interimPath);\n \n const contextPath: string = path.join(interimPath, 'context');\n await storage.createDirectory(contextPath);\n \n logger.debug('Intermediate files will be stored in: %s', interimPath);\n\n return {\n creationTime,\n outputPath,\n contextPath,\n interimPath,\n transcriptionFilename,\n hash,\n audioFile,\n };\n }\n\n return {\n locate,\n }\n}\n\n\n"],"names":["create","config","operator","logger","Logging","storage","Storage","log","debug","dates","Dates","timezone","media","Media","locate","audioFile","creationTime","getAudioCreationTime","info","toISOString","warn","now","error","message","hash","hashFile","substring","outputPath","constructOutputDirectory","transcriptionFilename","constructFilename","intermediateBase","DEFAULT_INTERMEDIATE_DIRECTORY","shortHash","pad","n","toString","padStart","timestamp","getFullYear","slice","getMonth","getDate","getHours","getMinutes","sessionDir","interimPath","path","join","createDirectory","contextPath"],"mappings":"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"}
@@ -72,7 +72,7 @@ const create = async (config)=>{
72
72
  var _outputPath_split_pop;
73
73
  const filename = (_outputPath_split_pop = outputPath.split('/').pop()) === null || _outputPath_split_pop === void 0 ? void 0 : _outputPath_split_pop.replace('.md', '');
74
74
  if (!filename) return undefined;
75
- // Remove date prefix (e.g., "27-0716-" from "27-0716-wagner-webhooks")
75
+ // Remove date prefix (e.g., "27-0716-" from "27-0716-meeting-notes")
76
76
  const withoutDate = filename.replace(/^\d{2}-\d{4}-/, '');
77
77
  if (!withoutDate) return undefined;
78
78
  // Convert kebab-case to Title Case