@redaksjon/protokoll-engine 0.1.1-dev.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) hide show
  1. package/README.md +47 -0
  2. package/dist/agentic/executor.d.ts +21 -0
  3. package/dist/agentic/executor.d.ts.map +1 -0
  4. package/dist/agentic/index.d.ts +27 -0
  5. package/dist/agentic/index.d.ts.map +1 -0
  6. package/dist/agentic/registry.d.ts +11 -0
  7. package/dist/agentic/registry.d.ts.map +1 -0
  8. package/dist/agentic/tools/lookup-person.d.ts +3 -0
  9. package/dist/agentic/tools/lookup-person.d.ts.map +1 -0
  10. package/dist/agentic/tools/lookup-project.d.ts +3 -0
  11. package/dist/agentic/tools/lookup-project.d.ts.map +1 -0
  12. package/dist/agentic/tools/route-note.d.ts +3 -0
  13. package/dist/agentic/tools/route-note.d.ts.map +1 -0
  14. package/dist/agentic/tools/store-context.d.ts +3 -0
  15. package/dist/agentic/tools/store-context.d.ts.map +1 -0
  16. package/dist/agentic/tools/verify-spelling.d.ts +3 -0
  17. package/dist/agentic/tools/verify-spelling.d.ts.map +1 -0
  18. package/dist/agentic/types.d.ts +110 -0
  19. package/dist/agentic/types.d.ts.map +1 -0
  20. package/dist/constants.d.ts +98 -0
  21. package/dist/constants.d.ts.map +1 -0
  22. package/dist/feedback/analyzer.d.ts +13 -0
  23. package/dist/feedback/analyzer.d.ts.map +1 -0
  24. package/dist/feedback/decision-tracker.d.ts +14 -0
  25. package/dist/feedback/decision-tracker.d.ts.map +1 -0
  26. package/dist/feedback/handler.d.ts +14 -0
  27. package/dist/feedback/handler.d.ts.map +1 -0
  28. package/dist/feedback/index.d.ts +12 -0
  29. package/dist/feedback/index.d.ts.map +1 -0
  30. package/dist/feedback/types.d.ts +72 -0
  31. package/dist/feedback/types.d.ts.map +1 -0
  32. package/dist/index.d.ts +24 -0
  33. package/dist/index.d.ts.map +1 -0
  34. package/dist/index.js +32 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/index10.js +4 -0
  37. package/dist/index10.js.map +1 -0
  38. package/dist/index11.js +22 -0
  39. package/dist/index11.js.map +1 -0
  40. package/dist/index12.js +125 -0
  41. package/dist/index12.js.map +1 -0
  42. package/dist/index13.js +124 -0
  43. package/dist/index13.js.map +1 -0
  44. package/dist/index14.js +296 -0
  45. package/dist/index14.js.map +1 -0
  46. package/dist/index15.js +100 -0
  47. package/dist/index15.js.map +1 -0
  48. package/dist/index16.js +107 -0
  49. package/dist/index16.js.map +1 -0
  50. package/dist/index17.js +185 -0
  51. package/dist/index17.js.map +1 -0
  52. package/dist/index18.js +53 -0
  53. package/dist/index18.js.map +1 -0
  54. package/dist/index19.js +19 -0
  55. package/dist/index19.js.map +1 -0
  56. package/dist/index2.js +33 -0
  57. package/dist/index2.js.map +1 -0
  58. package/dist/index20.js +105 -0
  59. package/dist/index20.js.map +1 -0
  60. package/dist/index21.js +26 -0
  61. package/dist/index21.js.map +1 -0
  62. package/dist/index22.js +49 -0
  63. package/dist/index22.js.map +1 -0
  64. package/dist/index23.js +119 -0
  65. package/dist/index23.js.map +1 -0
  66. package/dist/index24.js +330 -0
  67. package/dist/index24.js.map +1 -0
  68. package/dist/index25.js +57 -0
  69. package/dist/index25.js.map +1 -0
  70. package/dist/index26.js +38 -0
  71. package/dist/index26.js.map +1 -0
  72. package/dist/index27.js +127 -0
  73. package/dist/index27.js.map +1 -0
  74. package/dist/index28.js +157 -0
  75. package/dist/index28.js.map +1 -0
  76. package/dist/index29.js +163 -0
  77. package/dist/index29.js.map +1 -0
  78. package/dist/index3.js +36 -0
  79. package/dist/index3.js.map +1 -0
  80. package/dist/index30.js +173 -0
  81. package/dist/index30.js.map +1 -0
  82. package/dist/index31.js +423 -0
  83. package/dist/index31.js.map +1 -0
  84. package/dist/index32.js +161 -0
  85. package/dist/index32.js.map +1 -0
  86. package/dist/index33.js +152 -0
  87. package/dist/index33.js.map +1 -0
  88. package/dist/index34.js +56 -0
  89. package/dist/index34.js.map +1 -0
  90. package/dist/index35.js +103 -0
  91. package/dist/index35.js.map +1 -0
  92. package/dist/index36.js +451 -0
  93. package/dist/index36.js.map +1 -0
  94. package/dist/index37.js +431 -0
  95. package/dist/index37.js.map +1 -0
  96. package/dist/index38.js +87 -0
  97. package/dist/index38.js.map +1 -0
  98. package/dist/index39.js +122 -0
  99. package/dist/index39.js.map +1 -0
  100. package/dist/index4.js +3 -0
  101. package/dist/index4.js.map +1 -0
  102. package/dist/index40.js +299 -0
  103. package/dist/index40.js.map +1 -0
  104. package/dist/index41.js +49 -0
  105. package/dist/index41.js.map +1 -0
  106. package/dist/index42.js +151 -0
  107. package/dist/index42.js.map +1 -0
  108. package/dist/index43.js +226 -0
  109. package/dist/index43.js.map +1 -0
  110. package/dist/index44.js +49 -0
  111. package/dist/index44.js.map +1 -0
  112. package/dist/index45.js +45 -0
  113. package/dist/index45.js.map +1 -0
  114. package/dist/index46.js +37 -0
  115. package/dist/index46.js.map +1 -0
  116. package/dist/index47.js +51 -0
  117. package/dist/index47.js.map +1 -0
  118. package/dist/index48.js +39 -0
  119. package/dist/index48.js.map +1 -0
  120. package/dist/index49.js +239 -0
  121. package/dist/index49.js.map +1 -0
  122. package/dist/index5.js +17 -0
  123. package/dist/index5.js.map +1 -0
  124. package/dist/index50.js +163 -0
  125. package/dist/index50.js.map +1 -0
  126. package/dist/index51.js +81 -0
  127. package/dist/index51.js.map +1 -0
  128. package/dist/index52.js +78 -0
  129. package/dist/index52.js.map +1 -0
  130. package/dist/index53.js +22 -0
  131. package/dist/index53.js.map +1 -0
  132. package/dist/index54.js +8 -0
  133. package/dist/index54.js.map +1 -0
  134. package/dist/index55.js +8 -0
  135. package/dist/index55.js.map +1 -0
  136. package/dist/index56.js +17 -0
  137. package/dist/index56.js.map +1 -0
  138. package/dist/index57.js +4 -0
  139. package/dist/index57.js.map +1 -0
  140. package/dist/index58.js +17 -0
  141. package/dist/index58.js.map +1 -0
  142. package/dist/index59.js +4 -0
  143. package/dist/index59.js.map +1 -0
  144. package/dist/index6.js +22 -0
  145. package/dist/index6.js.map +1 -0
  146. package/dist/index60.js +6 -0
  147. package/dist/index60.js.map +1 -0
  148. package/dist/index7.js +27 -0
  149. package/dist/index7.js.map +1 -0
  150. package/dist/index8.js +22 -0
  151. package/dist/index8.js.map +1 -0
  152. package/dist/index9.js +5 -0
  153. package/dist/index9.js.map +1 -0
  154. package/dist/logging.d.ts +7 -0
  155. package/dist/logging.d.ts.map +1 -0
  156. package/dist/output/index.d.ts +15 -0
  157. package/dist/output/index.d.ts.map +1 -0
  158. package/dist/phases/complete.d.ts +17 -0
  159. package/dist/phases/complete.d.ts.map +1 -0
  160. package/dist/phases/index.d.ts +5 -0
  161. package/dist/phases/index.d.ts.map +1 -0
  162. package/dist/phases/locate.d.ts +15 -0
  163. package/dist/phases/locate.d.ts.map +1 -0
  164. package/dist/phases/simple-replace.d.ts +72 -0
  165. package/dist/phases/simple-replace.d.ts.map +1 -0
  166. package/dist/phases/transcribe.d.ts +19 -0
  167. package/dist/phases/transcribe.d.ts.map +1 -0
  168. package/dist/pipeline/index.d.ts +10 -0
  169. package/dist/pipeline/index.d.ts.map +1 -0
  170. package/dist/pipeline/orchestrator.d.ts +13 -0
  171. package/dist/pipeline/orchestrator.d.ts.map +1 -0
  172. package/dist/pipeline/types.d.ts +58 -0
  173. package/dist/pipeline/types.d.ts.map +1 -0
  174. package/dist/prompt/index.d.ts +3 -0
  175. package/dist/prompt/index.d.ts.map +1 -0
  176. package/dist/prompt/templates.d.ts +40 -0
  177. package/dist/prompt/templates.d.ts.map +1 -0
  178. package/dist/prompt/transcribe.d.ts +42 -0
  179. package/dist/prompt/transcribe.d.ts.map +1 -0
  180. package/dist/reasoning/client.d.ts +42 -0
  181. package/dist/reasoning/client.d.ts.map +1 -0
  182. package/dist/reasoning/index.d.ts +17 -0
  183. package/dist/reasoning/index.d.ts.map +1 -0
  184. package/dist/reasoning/strategy.d.ts +12 -0
  185. package/dist/reasoning/strategy.d.ts.map +1 -0
  186. package/dist/reasoning/types.d.ts +58 -0
  187. package/dist/reasoning/types.d.ts.map +1 -0
  188. package/dist/reflection/collector.d.ts +18 -0
  189. package/dist/reflection/collector.d.ts.map +1 -0
  190. package/dist/reflection/index.d.ts +13 -0
  191. package/dist/reflection/index.d.ts.map +1 -0
  192. package/dist/reflection/reporter.d.ts +10 -0
  193. package/dist/reflection/reporter.d.ts.map +1 -0
  194. package/dist/reflection/types.d.ts +99 -0
  195. package/dist/reflection/types.d.ts.map +1 -0
  196. package/dist/routing/classifier.d.ts +8 -0
  197. package/dist/routing/classifier.d.ts.map +1 -0
  198. package/dist/routing/index.d.ts +12 -0
  199. package/dist/routing/index.d.ts.map +1 -0
  200. package/dist/routing/router.d.ts +8 -0
  201. package/dist/routing/router.d.ts.map +1 -0
  202. package/dist/routing/types.d.ts +68 -0
  203. package/dist/routing/types.d.ts.map +1 -0
  204. package/dist/transcript/feedback.d.ts +70 -0
  205. package/dist/transcript/feedback.d.ts.map +1 -0
  206. package/dist/transcript/index.d.ts +10 -0
  207. package/dist/transcript/index.d.ts.map +1 -0
  208. package/dist/transcript/operations.d.ts +152 -0
  209. package/dist/transcript/operations.d.ts.map +1 -0
  210. package/dist/transcript/pkl-utils.d.ts +66 -0
  211. package/dist/transcript/pkl-utils.d.ts.map +1 -0
  212. package/dist/transcription/index.d.ts +17 -0
  213. package/dist/transcription/index.d.ts.map +1 -0
  214. package/dist/transcription/service.d.ts +10 -0
  215. package/dist/transcription/service.d.ts.map +1 -0
  216. package/dist/transcription/types.d.ts +41 -0
  217. package/dist/transcription/types.d.ts.map +1 -0
  218. package/dist/types.d.ts +28 -0
  219. package/dist/types.d.ts.map +1 -0
  220. package/dist/util/collision-detector.d.ts +77 -0
  221. package/dist/util/collision-detector.d.ts.map +1 -0
  222. package/dist/util/dates.d.ts +57 -0
  223. package/dist/util/dates.d.ts.map +1 -0
  224. package/dist/util/general.d.ts +3 -0
  225. package/dist/util/general.d.ts.map +1 -0
  226. package/dist/util/media.d.ts +9 -0
  227. package/dist/util/media.d.ts.map +1 -0
  228. package/dist/util/metadata.d.ts +138 -0
  229. package/dist/util/metadata.d.ts.map +1 -0
  230. package/dist/util/openai.d.ts +22 -0
  231. package/dist/util/openai.d.ts.map +1 -0
  232. package/dist/util/sounds-like-database.d.ts +98 -0
  233. package/dist/util/sounds-like-database.d.ts.map +1 -0
  234. package/dist/util/storage.d.ts +35 -0
  235. package/dist/util/storage.d.ts.map +1 -0
  236. package/dist/util/text-replacer.d.ts +56 -0
  237. package/dist/util/text-replacer.d.ts.map +1 -0
  238. package/dist/utils/entityFinder.d.ts +29 -0
  239. package/dist/utils/entityFinder.d.ts.map +1 -0
  240. package/package.json +84 -0
@@ -0,0 +1,103 @@
1
+ import * as path from 'node:path';
2
+ import { getLogger } from './index41.js';
3
+ import { create as create$1 } from './index12.js';
4
+
5
+ const create = (config) => {
6
+ const logger = getLogger();
7
+ const storage$1 = create$1({ log: logger.debug });
8
+ const buildDirectoryPath = (date) => {
9
+ const structure = config.outputStructure || "month";
10
+ const year = date.getFullYear().toString();
11
+ const month = (date.getMonth() + 1).toString();
12
+ const day = date.getDate().toString();
13
+ switch (structure) {
14
+ case "none":
15
+ return config.processedDirectory;
16
+ case "year":
17
+ return path.join(config.processedDirectory, year);
18
+ case "month":
19
+ return path.join(config.processedDirectory, year, month);
20
+ case "day":
21
+ return path.join(config.processedDirectory, year, month, day);
22
+ }
23
+ };
24
+ const formatDateForFilename = (date) => {
25
+ const structure = config.outputStructure || "month";
26
+ const pad = (n) => n.toString().padStart(2, "0");
27
+ const year = date.getFullYear().toString();
28
+ const month = pad(date.getMonth() + 1);
29
+ const day = pad(date.getDate());
30
+ const hours = pad(date.getHours());
31
+ const minutes = pad(date.getMinutes());
32
+ switch (structure) {
33
+ case "day":
34
+ return `${hours}${minutes}`;
35
+ case "month":
36
+ return `${day}-${hours}${minutes}`;
37
+ case "year":
38
+ return `${month}-${day}-${hours}${minutes}`;
39
+ case "none":
40
+ return `${year}-${month}-${day}-${hours}${minutes}`;
41
+ }
42
+ };
43
+ const cleanSubjectOfPatterns = (subject) => {
44
+ let cleaned = subject;
45
+ cleaned = cleaned.replace(/^\d{4}-\d{2}-\d{2}-\d{4}-/, "");
46
+ cleaned = cleaned.replace(/^\d{6}-\d{4}-/, "");
47
+ cleaned = cleaned.replace(/^\d{2}-\d{2}-\d{4}-/, "");
48
+ cleaned = cleaned.replace(/^\d{1,2}-\d{4}-/, "");
49
+ cleaned = cleaned.replace(/^\d{4}-/, "");
50
+ cleaned = cleaned.replace(/-[a-f0-9]{5,8}$/i, "");
51
+ cleaned = cleaned.replace(/^-+/, "");
52
+ return cleaned;
53
+ };
54
+ const complete = async (audioFile, hash, creationTime, subject) => {
55
+ logger.debug("Completing file processing for %s", audioFile);
56
+ if (config.dryRun) {
57
+ logger.info("Dry run: would move %s to processed directory", audioFile);
58
+ return audioFile;
59
+ }
60
+ if (!config.processedDirectory) {
61
+ logger.debug("No processed directory configured, skipping file move");
62
+ return audioFile;
63
+ }
64
+ const targetDir = buildDirectoryPath(creationTime);
65
+ if (!await storage$1.exists(targetDir)) {
66
+ logger.debug("Creating processed directory %s", targetDir);
67
+ await storage$1.createDirectory(targetDir);
68
+ }
69
+ const fileExt = path.extname(audioFile);
70
+ const dateStr = formatDateForFilename(creationTime);
71
+ const shortHash = hash.substring(0, 6);
72
+ let newFilename;
73
+ if (subject) {
74
+ const strippedSubject = cleanSubjectOfPatterns(subject);
75
+ const cleanSubject = strippedSubject.replace(/[^a-zA-Z0-9]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").toLowerCase().substring(0, 50);
76
+ if (cleanSubject) {
77
+ newFilename = `${dateStr}-${cleanSubject}-${shortHash}${fileExt}`;
78
+ } else {
79
+ newFilename = `${dateStr}-${shortHash}${fileExt}`;
80
+ }
81
+ } else {
82
+ newFilename = `${dateStr}-${shortHash}${fileExt}`;
83
+ }
84
+ const newFilePath = path.join(targetDir, newFilename);
85
+ try {
86
+ const fileContent = await storage$1.readFile(audioFile, "binary");
87
+ logger.debug("Moving file from %s to %s", audioFile, newFilePath);
88
+ await storage$1.writeFile(newFilePath, fileContent, "binary");
89
+ await storage$1.deleteFile(audioFile);
90
+ logger.info("Moved to processed: %s", newFilePath);
91
+ return newFilePath;
92
+ } catch (error) {
93
+ logger.error("Failed to move file to processed directory: %s", error);
94
+ return audioFile;
95
+ }
96
+ };
97
+ return {
98
+ complete
99
+ };
100
+ };
101
+
102
+ export { create };
103
+ //# sourceMappingURL=index35.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index35.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 // Strip date prefix and hash suffix from subject if already present\n // This handles cases where subject comes from an already-formatted filename\n const cleanSubjectOfPatterns = (subject: string): string => {\n let cleaned = subject;\n \n // Remove common date-time prefixes (try most specific first):\n // - YYYY-MM-DD-HHmm- (e.g., \"2026-01-14-2330-\")\n // - YYMMDD-HHmm- (e.g., \"260114-2330-\") \n // - MM-DD-HHmm- (e.g., \"01-14-2330-\")\n // - DD-HHmm- (e.g., \"14-2330-\" or \"15-1435-\")\n // - HHmm- (e.g., \"2330-\")\n \n // Pattern 1: YYYY-MM-DD-HHmm- (full ISO-like date with time)\n cleaned = cleaned.replace(/^\\d{4}-\\d{2}-\\d{2}-\\d{4}-/, '');\n \n // Pattern 2: YYMMDD-HHmm- (compact date with time)\n cleaned = cleaned.replace(/^\\d{6}-\\d{4}-/, '');\n \n // Pattern 3: MM-DD-HHmm- (month-day-time)\n cleaned = cleaned.replace(/^\\d{2}-\\d{2}-\\d{4}-/, '');\n \n // Pattern 4: DD-HHmm- (day-time, most common for 'month' structure)\n // This matches patterns like \"15-1435-\" where 15 is day and 1435 is HHmm\n cleaned = cleaned.replace(/^\\d{1,2}-\\d{4}-/, '');\n \n // Pattern 5: Just HHmm- at the start (time only)\n cleaned = cleaned.replace(/^\\d{4}-/, '');\n \n // Remove hash suffix (5-8 hex characters at end, preceded by dash)\n cleaned = cleaned.replace(/-[a-f0-9]{5,8}$/i, '');\n \n // Clean up any leading dashes that might remain\n cleaned = cleaned.replace(/^-+/, '');\n \n return cleaned;\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 // Also strip any existing date/hash patterns from the subject\n const shortHash = hash.substring(0, 6);\n let newFilename: string;\n if (subject) {\n // First strip any existing date prefixes and hash suffixes\n const strippedSubject = cleanSubjectOfPatterns(subject);\n const cleanSubject = strippedSubject\n .replace(/[^a-zA-Z0-9]/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '')\n .toLowerCase()\n .substring(0, 50);\n \n // Only include subject if there's something left after cleaning\n if (cleanSubject) {\n newFilename = `${dateStr}-${cleanSubject}-${shortHash}${fileExt}`;\n } else {\n newFilename = `${dateStr}-${shortHash}${fileExt}`;\n }\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":["Logging.getLogger","storage","Storage.create"],"mappings":"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"}
@@ -0,0 +1,451 @@
1
+ import * as fs from 'fs/promises';
2
+ import * as path from 'node:path';
3
+ import { glob } from 'glob';
4
+ import * as Context from '@redaksjon/context';
5
+ import { create } from './index6.js';
6
+ import { findProjectResilient } from './index15.js';
7
+ import { PklTranscript, listTranscripts as listTranscripts$1 } from '@redaksjon/protokoll-format';
8
+ import { ensurePklExtension } from './index38.js';
9
+
10
+ function isUuidInput(input) {
11
+ return /^[a-f0-9]{8}/.test(input);
12
+ }
13
+ async function findTranscriptByUuid(uuid, searchDirectories) {
14
+ const prefix = uuid.substring(0, 8);
15
+ const pattern = `${prefix}-*.pkl`;
16
+ for (const dir of searchDirectories) {
17
+ const matches = await glob(pattern, { cwd: dir, absolute: true });
18
+ if (matches.length > 0) {
19
+ return matches[0];
20
+ }
21
+ }
22
+ return null;
23
+ }
24
+ const parseTranscript = async (filePathOrUuid, searchDirectories) => {
25
+ let resolvedPath;
26
+ if (isUuidInput(filePathOrUuid)) {
27
+ if (!searchDirectories || searchDirectories.length === 0) {
28
+ throw new Error("Search directories required for UUID lookup");
29
+ }
30
+ const foundPath = await findTranscriptByUuid(filePathOrUuid, searchDirectories);
31
+ if (!foundPath) {
32
+ throw new Error(`Transcript not found for UUID: ${filePathOrUuid}`);
33
+ }
34
+ resolvedPath = foundPath;
35
+ } else {
36
+ resolvedPath = ensurePklExtension(filePathOrUuid);
37
+ }
38
+ const transcript = PklTranscript.open(resolvedPath, { readOnly: true });
39
+ try {
40
+ const pklMetadata = transcript.metadata;
41
+ const content = transcript.content;
42
+ const result = {
43
+ filePath: resolvedPath,
44
+ title: pklMetadata.title,
45
+ metadata: {
46
+ date: pklMetadata.date instanceof Date ? pklMetadata.date.toISOString().split("T")[0] : void 0,
47
+ time: pklMetadata.recordingTime,
48
+ project: pklMetadata.project,
49
+ projectId: pklMetadata.projectId,
50
+ destination: pklMetadata.routing?.destination,
51
+ confidence: pklMetadata.routing?.confidence?.toString(),
52
+ signals: pklMetadata.routing?.signals,
53
+ reasoning: pklMetadata.routing?.reasoning,
54
+ tags: pklMetadata.tags,
55
+ duration: pklMetadata.duration
56
+ },
57
+ content,
58
+ rawText: content
59
+ // For PKL files, content is the enhanced text
60
+ };
61
+ return result;
62
+ } finally {
63
+ transcript.close();
64
+ }
65
+ };
66
+ const extractTimestampFromFilename = (filePath) => {
67
+ const ext = path.extname(filePath);
68
+ const basename = path.basename(filePath, ext);
69
+ const match = basename.match(/^(\d{1,2})-(\d{2})(\d{2})/);
70
+ if (match) {
71
+ return {
72
+ day: parseInt(match[1], 10),
73
+ hour: parseInt(match[2], 10),
74
+ minute: parseInt(match[3], 10)
75
+ };
76
+ }
77
+ return null;
78
+ };
79
+ const slugifyTitle = (title) => {
80
+ return title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/--+/g, "-").replace(/^-|-$/g, "").slice(0, 50);
81
+ };
82
+ const parseDuration = (duration) => {
83
+ const match = duration.match(/(\d+):(\d+)/);
84
+ if (match) {
85
+ const [, minutes, seconds] = match;
86
+ return parseInt(minutes, 10) * 60 + parseInt(seconds, 10);
87
+ }
88
+ return 0;
89
+ };
90
+ const formatDuration = (seconds) => {
91
+ const minutes = Math.floor(seconds / 60);
92
+ const secs = seconds % 60;
93
+ return `${minutes}:${secs.toString().padStart(2, "0")}`;
94
+ };
95
+ const expandPath = (p) => {
96
+ if (p.startsWith("~")) {
97
+ return path.join(process.env.HOME || "", p.slice(1));
98
+ }
99
+ return p;
100
+ };
101
+ const extractDateFromMetadata = (metadata, filePath) => {
102
+ if (metadata.date) {
103
+ return new Date(metadata.date);
104
+ }
105
+ const timestamp = extractTimestampFromFilename(filePath);
106
+ if (timestamp) {
107
+ const now = /* @__PURE__ */ new Date();
108
+ return new Date(now.getFullYear(), now.getMonth(), timestamp.day, timestamp.hour, timestamp.minute);
109
+ }
110
+ return /* @__PURE__ */ new Date();
111
+ };
112
+ const buildRoutingConfig = (context, _targetProject) => {
113
+ const config = context.getConfig();
114
+ const defaultPath = expandPath(config.outputDirectory || "~/notes");
115
+ const resolveRoutingPath = (routingPath) => {
116
+ if (!routingPath) {
117
+ return defaultPath;
118
+ }
119
+ const expanded = expandPath(routingPath);
120
+ if (!expanded.startsWith("/") && !expanded.match(/^[A-Za-z]:/)) {
121
+ return path.resolve(defaultPath, expanded);
122
+ }
123
+ return expanded;
124
+ };
125
+ return {
126
+ default: {
127
+ path: resolveRoutingPath(void 0),
128
+ structure: "month",
129
+ filename_options: ["date", "time", "subject"]
130
+ },
131
+ projects: context.getAllProjects().filter((p) => p.active !== false).map((p) => ({
132
+ projectId: p.id,
133
+ destination: {
134
+ path: resolveRoutingPath(p.routing?.destination),
135
+ structure: p.routing?.structure || "month",
136
+ filename_options: p.routing?.filename_options || ["date", "time", "subject"]
137
+ },
138
+ classification: p.classification,
139
+ active: p.active
140
+ })),
141
+ conflict_resolution: "primary"
142
+ };
143
+ };
144
+ const combineTranscripts = async (filePaths, options = {}) => {
145
+ if (filePaths.length === 0) {
146
+ throw new Error("No transcript files provided");
147
+ }
148
+ const transcripts = [];
149
+ for (const filePath of filePaths) {
150
+ try {
151
+ const parsed = await parseTranscript(filePath);
152
+ transcripts.push(parsed);
153
+ } catch (error) {
154
+ throw new Error(`Failed to parse transcript: ${filePath} - ${error}`);
155
+ }
156
+ }
157
+ transcripts.sort((a, b) => {
158
+ const aName = path.basename(a.filePath);
159
+ const bName = path.basename(b.filePath);
160
+ return aName.localeCompare(bName);
161
+ });
162
+ const firstTranscript = transcripts[0];
163
+ const baseMetadata = { ...firstTranscript.metadata };
164
+ const context = await Context.create({
165
+ startingDir: options.contextDirectory || path.dirname(firstTranscript.filePath),
166
+ contextDirectories: options.contextDirectories
167
+ });
168
+ let targetProject;
169
+ if (options.projectId) {
170
+ targetProject = findProjectResilient(context, options.projectId);
171
+ baseMetadata.project = targetProject.name;
172
+ baseMetadata.projectId = targetProject.id;
173
+ if (targetProject.routing?.destination) {
174
+ const config = context.getConfig();
175
+ const defaultPath = expandPath(config.outputDirectory || "~/notes");
176
+ const routingPath = expandPath(targetProject.routing.destination);
177
+ const resolvedPath = !routingPath.startsWith("/") && !routingPath.match(/^[A-Za-z]:/) ? path.resolve(defaultPath, routingPath) : routingPath;
178
+ baseMetadata.destination = resolvedPath;
179
+ }
180
+ }
181
+ let totalSeconds = 0;
182
+ let hasDuration = false;
183
+ for (const t of transcripts) {
184
+ if (t.metadata.duration) {
185
+ hasDuration = true;
186
+ totalSeconds += parseDuration(t.metadata.duration);
187
+ }
188
+ }
189
+ if (hasDuration && totalSeconds > 0) {
190
+ baseMetadata.duration = formatDuration(totalSeconds);
191
+ }
192
+ const allTags = /* @__PURE__ */ new Set();
193
+ for (const t of transcripts) {
194
+ if (t.metadata.tags) {
195
+ for (const tag of t.metadata.tags) {
196
+ allTags.add(tag);
197
+ }
198
+ }
199
+ }
200
+ if (allTags.size > 0) {
201
+ baseMetadata.tags = Array.from(allTags).sort();
202
+ }
203
+ const combinedTitle = options.title ? options.title : firstTranscript.title ? `${firstTranscript.title} (Combined)` : "Combined Transcript";
204
+ const contentParts = [];
205
+ for (let i = 0; i < transcripts.length; i++) {
206
+ const t = transcripts[i];
207
+ const sectionTitle = t.title || `Part ${i + 1}`;
208
+ const sourceFile = path.basename(t.filePath);
209
+ contentParts.push(`## ${sectionTitle}`);
210
+ contentParts.push(`*Source: ${sourceFile}*`);
211
+ contentParts.push("");
212
+ contentParts.push(t.content);
213
+ contentParts.push("");
214
+ }
215
+ const combinedContent = contentParts.join("\n");
216
+ let outputPath;
217
+ if (targetProject?.routing?.destination) {
218
+ const routingConfig = buildRoutingConfig(context);
219
+ const routing = create(routingConfig, context);
220
+ const audioDate = extractDateFromMetadata(baseMetadata, firstTranscript.filePath);
221
+ const routingContext = {
222
+ transcriptText: combinedContent,
223
+ audioDate,
224
+ sourceFile: firstTranscript.filePath
225
+ };
226
+ const decision = routing.route(routingContext);
227
+ outputPath = routing.buildOutputPath(decision, routingContext);
228
+ outputPath = outputPath.replace(/\.md$/, ".pkl");
229
+ } else {
230
+ const firstDir = path.dirname(firstTranscript.filePath);
231
+ const timestamp = extractTimestampFromFilename(firstTranscript.filePath);
232
+ const filenameSuffix = options.title ? slugifyTitle(options.title) : "combined";
233
+ if (timestamp) {
234
+ const day = timestamp.day.toString().padStart(2, "0");
235
+ const hour = timestamp.hour.toString().padStart(2, "0");
236
+ const minute = timestamp.minute.toString().padStart(2, "0");
237
+ outputPath = path.join(firstDir, `${day}-${hour}${minute}-${filenameSuffix}.pkl`);
238
+ } else {
239
+ outputPath = path.join(firstDir, `${filenameSuffix}.pkl`);
240
+ }
241
+ }
242
+ if (!options.dryRun) {
243
+ const initialMetadata = {
244
+ id: "",
245
+ // Will be auto-generated by PklTranscript.create()
246
+ title: combinedTitle,
247
+ date: baseMetadata.date ? new Date(baseMetadata.date) : void 0,
248
+ recordingTime: baseMetadata.time,
249
+ project: targetProject?.name || baseMetadata.project,
250
+ projectId: targetProject?.id || baseMetadata.projectId,
251
+ tags: baseMetadata.tags || [],
252
+ duration: baseMetadata.duration,
253
+ status: "reviewed"
254
+ };
255
+ if (targetProject) {
256
+ initialMetadata.entities = {
257
+ people: [],
258
+ projects: [{
259
+ id: targetProject.id,
260
+ name: targetProject.name,
261
+ type: "project"
262
+ }],
263
+ terms: [],
264
+ companies: []
265
+ };
266
+ }
267
+ const newTranscript = PklTranscript.create(outputPath, initialMetadata);
268
+ try {
269
+ newTranscript.updateContent(combinedContent);
270
+ } finally {
271
+ newTranscript.close();
272
+ }
273
+ }
274
+ return { outputPath, content: combinedContent };
275
+ };
276
+ const editTranscript = async (filePath, options) => {
277
+ const pklPath = ensurePklExtension(filePath);
278
+ const transcript = PklTranscript.open(pklPath, { readOnly: false });
279
+ try {
280
+ const pklMetadata = transcript.metadata;
281
+ const content = transcript.content;
282
+ const context = await Context.create({
283
+ startingDir: options.contextDirectory || path.dirname(pklPath),
284
+ contextDirectories: options.contextDirectories
285
+ });
286
+ let targetProject;
287
+ if (options.projectId) {
288
+ targetProject = findProjectResilient(context, options.projectId);
289
+ }
290
+ const newTitle = options.title || pklMetadata.title || "Untitled";
291
+ const updatedMetadata = {};
292
+ if (options.title) {
293
+ updatedMetadata.title = newTitle;
294
+ }
295
+ if (targetProject) {
296
+ updatedMetadata.project = targetProject.name;
297
+ updatedMetadata.projectId = targetProject.id;
298
+ const existingEntities = pklMetadata.entities || { people: [], projects: [], terms: [], companies: [] };
299
+ updatedMetadata.entities = {
300
+ people: existingEntities.people || [],
301
+ projects: [{
302
+ id: targetProject.id,
303
+ name: targetProject.name,
304
+ type: "project"
305
+ }],
306
+ terms: existingEntities.terms || [],
307
+ companies: existingEntities.companies || []
308
+ };
309
+ }
310
+ if (options.tagsToAdd || options.tagsToRemove) {
311
+ const currentTags = new Set(pklMetadata.tags || []);
312
+ if (options.tagsToRemove) {
313
+ for (const tag of options.tagsToRemove) {
314
+ currentTags.delete(tag);
315
+ }
316
+ }
317
+ if (options.tagsToAdd) {
318
+ for (const tag of options.tagsToAdd) {
319
+ currentTags.add(tag);
320
+ }
321
+ }
322
+ updatedMetadata.tags = Array.from(currentTags).sort();
323
+ }
324
+ let outputPath = pklPath;
325
+ if (targetProject?.routing?.destination || options.title) {
326
+ const config = context.getConfig();
327
+ const defaultPath = expandPath(config.outputDirectory || "~/notes");
328
+ if (targetProject?.routing?.destination) {
329
+ const routingConfig = buildRoutingConfig(context, targetProject);
330
+ const routing = create(routingConfig, context);
331
+ const audioDate = pklMetadata.date instanceof Date ? pklMetadata.date : /* @__PURE__ */ new Date();
332
+ const routingContext = {
333
+ transcriptText: content,
334
+ audioDate,
335
+ sourceFile: pklPath
336
+ };
337
+ const decision = routing.route(routingContext);
338
+ if (options.title) {
339
+ const basePath = path.dirname(routing.buildOutputPath(decision, routingContext));
340
+ const timestamp = extractTimestampFromFilename(pklPath);
341
+ const sluggedTitle = slugifyTitle(options.title);
342
+ if (timestamp) {
343
+ const day = timestamp.day.toString().padStart(2, "0");
344
+ const hour = timestamp.hour.toString().padStart(2, "0");
345
+ const minute = timestamp.minute.toString().padStart(2, "0");
346
+ outputPath = path.join(basePath, `${day}-${hour}${minute}-${sluggedTitle}.pkl`);
347
+ } else {
348
+ outputPath = path.join(basePath, `${sluggedTitle}.pkl`);
349
+ }
350
+ } else {
351
+ outputPath = routing.buildOutputPath(decision, routingContext);
352
+ outputPath = outputPath.replace(/\.md$/, ".pkl");
353
+ }
354
+ } else if (options.title) {
355
+ const dir = path.dirname(pklPath);
356
+ const timestamp = extractTimestampFromFilename(pklPath);
357
+ const sluggedTitle = slugifyTitle(options.title);
358
+ if (timestamp) {
359
+ const day = timestamp.day.toString().padStart(2, "0");
360
+ const hour = timestamp.hour.toString().padStart(2, "0");
361
+ const minute = timestamp.minute.toString().padStart(2, "0");
362
+ outputPath = path.join(dir, `${day}-${hour}${minute}-${sluggedTitle}.pkl`);
363
+ } else {
364
+ outputPath = path.join(dir, `${sluggedTitle}.pkl`);
365
+ }
366
+ }
367
+ }
368
+ if (!options.dryRun) {
369
+ if (Object.keys(updatedMetadata).length > 0) {
370
+ transcript.updateMetadata(updatedMetadata);
371
+ }
372
+ if (outputPath !== pklPath) {
373
+ transcript.close();
374
+ await fs.mkdir(path.dirname(outputPath), { recursive: true });
375
+ await fs.copyFile(pklPath, outputPath);
376
+ await fs.unlink(pklPath);
377
+ }
378
+ }
379
+ return { outputPath, content };
380
+ } finally {
381
+ try {
382
+ transcript.close();
383
+ } catch {
384
+ }
385
+ }
386
+ };
387
+ const listTranscripts = async (options) => {
388
+ const {
389
+ directory,
390
+ limit = 50,
391
+ offset = 0,
392
+ sortBy = "date",
393
+ startDate,
394
+ endDate,
395
+ search,
396
+ projectId
397
+ } = options;
398
+ const storageOptions = {
399
+ directory,
400
+ limit,
401
+ offset,
402
+ sortBy,
403
+ search,
404
+ project: projectId,
405
+ startDate,
406
+ endDate
407
+ };
408
+ const result = await listTranscripts$1(storageOptions);
409
+ const transcripts = result.transcripts.map((item) => {
410
+ let uuid = "";
411
+ try {
412
+ const transcript = PklTranscript.open(item.filePath, { readOnly: true });
413
+ uuid = transcript.metadata.id;
414
+ transcript.close();
415
+ } catch {
416
+ uuid = "";
417
+ }
418
+ return {
419
+ path: item.filePath,
420
+ filename: path.basename(item.filePath),
421
+ uuid,
422
+ date: item.date instanceof Date ? item.date.toISOString().split("T")[0] : "",
423
+ time: void 0,
424
+ // Not in storage result
425
+ title: item.title,
426
+ hasRawTranscript: false,
427
+ // Not in storage result, would need to open file to check
428
+ createdAt: item.date || /* @__PURE__ */ new Date(),
429
+ status: item.status,
430
+ openTasksCount: void 0,
431
+ // Not in storage result
432
+ contentSize: item.contentPreview?.length,
433
+ entities: item.project ? {
434
+ projects: [{
435
+ id: item.project,
436
+ name: item.project
437
+ }]
438
+ } : void 0
439
+ };
440
+ });
441
+ return {
442
+ transcripts,
443
+ total: result.total,
444
+ hasMore: result.hasMore,
445
+ limit,
446
+ offset
447
+ };
448
+ };
449
+
450
+ export { combineTranscripts, editTranscript, extractTimestampFromFilename, findTranscriptByUuid, isUuidInput, listTranscripts, parseTranscript, slugifyTitle };
451
+ //# sourceMappingURL=index36.js.map