@redaksjon/protokoll 1.0.13 → 1.0.14-dev.20260216152331.67acb08

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.
@@ -1,8 +1,8 @@
1
- import { resolve, isAbsolute, relative, extname, join, dirname, basename } from 'node:path';
1
+ import { resolve, relative, isAbsolute, extname, join, dirname, basename } from 'node:path';
2
2
  import * as Metadata from '@redaksjon/protokoll-engine';
3
3
  import { Transcript, Media, Util, Pipeline, findIgnoredResilient, findCompanyResilient, findTermResilient, findPersonResilient, findProjectResilient, Reasoning, VALID_STATUSES, isValidStatus } from '@redaksjon/protokoll-engine';
4
4
  import * as yaml from 'js-yaml';
5
- import { stat, readdir, mkdir } from 'node:fs/promises';
5
+ import { stat, readdir, mkdir, unlink } from 'node:fs/promises';
6
6
  import { readFileSync } from 'node:fs';
7
7
  import { fileURLToPath } from 'node:url';
8
8
  import { create as create$1, parseEntityUri as parseEntityUri$1, createRelationship, createDocumentContent, createCodeContent, createMarkdownContent, createTextContent, createUrlContent } from '@redaksjon/context';
@@ -277,7 +277,7 @@ const resourceTemplates = [
277
277
  }
278
278
  ];
279
279
 
280
- const VERSION = "1.0.13 (HEAD/8ec1dcf T:v1.0.13 2026-02-15 13:08:35 -0800) linux arm64 v24.13.1";
280
+ const VERSION = "1.0.14-dev.20260216152331.67acb08 (working/67acb08 2026-02-16 07:22:44 -0800) linux arm64 v24.13.1";
281
281
  const PROGRAM_NAME = "protokoll";
282
282
  const DATE_FORMAT_YEAR_MONTH_DAY_HOURS_MINUTES_SECONDS = "YYYY-M-D-HHmmss";
283
283
  const DEFAULT_AUDIO_EXTENSIONS = ["mp3", "mp4", "mpeg", "mpga", "m4a", "wav", "webm", "qta"];
@@ -668,7 +668,7 @@ const ensurePklExtension$1 = Transcript.ensurePklExtension;
668
668
  function isUuidInput(input) {
669
669
  return /^[a-f0-9]{8}/.test(input);
670
670
  }
671
- async function findTranscriptByUuid(uuid, searchDirectories) {
671
+ async function findTranscriptByUuid$1(uuid, searchDirectories) {
672
672
  return Transcript.findTranscriptByUuid(uuid, searchDirectories);
673
673
  }
674
674
  const logger = getLogger();
@@ -821,7 +821,7 @@ async function resolveTranscriptPath$1(uriOrPathOrUuid, contextDirectory) {
821
821
  }
822
822
  const outputDirectory = await getConfiguredDirectory("outputDirectory");
823
823
  if (isUuidInput(uriOrPathOrUuid)) {
824
- const foundPath = await findTranscriptByUuid(uriOrPathOrUuid, [outputDirectory]);
824
+ const foundPath = await findTranscriptByUuid$1(uriOrPathOrUuid, [outputDirectory]);
825
825
  if (!foundPath) {
826
826
  throw new Error(`Transcript not found for UUID: ${uriOrPathOrUuid}`);
827
827
  }
@@ -858,6 +858,25 @@ async function resolveTranscriptPath$1(uriOrPathOrUuid, contextDirectory) {
858
858
  return existsResult.path;
859
859
  }
860
860
 
861
+ const shared = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
862
+ __proto__: null,
863
+ fileExists,
864
+ formatEntity,
865
+ getAudioMetadata,
866
+ getConfiguredDirectory,
867
+ getContextDirectories,
868
+ logger,
869
+ media,
870
+ mergeArray,
871
+ resolveTranscriptPath: resolveTranscriptPath$1,
872
+ sanitizePath,
873
+ slugify,
874
+ storage,
875
+ validateNotRemoteMode,
876
+ validatePathWithinDirectory,
877
+ validatePathWithinOutputDirectory
878
+ }, Symbol.toStringTag, { value: 'Module' }));
879
+
861
880
  const { listTranscripts, resolveTranscriptPath, readTranscriptContent, stripTranscriptExtension } = Transcript;
862
881
  async function readTranscriptResource(transcriptPath) {
863
882
  if (!transcriptPath || typeof transcriptPath !== "string") {
@@ -2023,6 +2042,8 @@ async function handleProcessAudio(args) {
2023
2042
  const outputFilenameOptions = contextConfig.outputFilenameOptions || DEFAULT_OUTPUT_FILENAME_OPTIONS;
2024
2043
  const processedDirectory = config.processedDirectory ?? void 0;
2025
2044
  const { creationTime, hash } = await getAudioMetadata(audioFile);
2045
+ const { getWeightModelService, updateTranscriptInWeightModel } = await import('./weightModel.js');
2046
+ const weightModelService = getWeightModelService();
2026
2047
  const pipeline = await Pipeline.create({
2027
2048
  model: args.model || DEFAULT_MODEL,
2028
2049
  transcriptionModel: args.transcriptionModel || DEFAULT_TRANSCRIPTION_MODEL,
@@ -2041,7 +2062,11 @@ async function handleProcessAudio(args) {
2041
2062
  outputFilenameOptions,
2042
2063
  processedDirectory: processedDirectory || void 0,
2043
2064
  maxAudioSize: DEFAULT_MAX_AUDIO_SIZE,
2044
- tempDirectory: DEFAULT_TEMP_DIRECTORY
2065
+ tempDirectory: DEFAULT_TEMP_DIRECTORY,
2066
+ weightModelProvider: weightModelService?.provider,
2067
+ onTranscriptEntitiesUpdated: (uuid, entityIds, projectId) => {
2068
+ updateTranscriptInWeightModel(uuid, entityIds, projectId);
2069
+ }
2045
2070
  });
2046
2071
  const result = await pipeline.process({
2047
2072
  audioFile,
@@ -2133,6 +2158,18 @@ const listProjectsTool = {
2133
2158
  includeInactive: {
2134
2159
  type: "boolean",
2135
2160
  description: "Include inactive projects (default: false)"
2161
+ },
2162
+ limit: {
2163
+ type: "number",
2164
+ description: "Maximum number of results to return (default: 50)"
2165
+ },
2166
+ offset: {
2167
+ type: "number",
2168
+ description: "Number of results to skip for pagination (default: 0)"
2169
+ },
2170
+ search: {
2171
+ type: "string",
2172
+ description: "Filter by name/ID substring match (case-insensitive)"
2136
2173
  }
2137
2174
  },
2138
2175
  required: []
@@ -2147,6 +2184,18 @@ const listPeopleTool = {
2147
2184
  contextDirectory: {
2148
2185
  type: "string",
2149
2186
  description: "Path to the .protokoll context directory"
2187
+ },
2188
+ limit: {
2189
+ type: "number",
2190
+ description: "Maximum number of results to return (default: 50)"
2191
+ },
2192
+ offset: {
2193
+ type: "number",
2194
+ description: "Number of results to skip for pagination (default: 0)"
2195
+ },
2196
+ search: {
2197
+ type: "string",
2198
+ description: "Filter by name/ID substring match (case-insensitive)"
2150
2199
  }
2151
2200
  },
2152
2201
  required: []
@@ -2161,6 +2210,18 @@ const listTermsTool = {
2161
2210
  contextDirectory: {
2162
2211
  type: "string",
2163
2212
  description: "Path to the .protokoll context directory"
2213
+ },
2214
+ limit: {
2215
+ type: "number",
2216
+ description: "Maximum number of results to return (default: 50)"
2217
+ },
2218
+ offset: {
2219
+ type: "number",
2220
+ description: "Number of results to skip for pagination (default: 0)"
2221
+ },
2222
+ search: {
2223
+ type: "string",
2224
+ description: "Filter by name/ID substring match (case-insensitive)"
2164
2225
  }
2165
2226
  },
2166
2227
  required: []
@@ -2175,6 +2236,18 @@ const listCompaniesTool = {
2175
2236
  contextDirectory: {
2176
2237
  type: "string",
2177
2238
  description: "Path to the .protokoll context directory"
2239
+ },
2240
+ limit: {
2241
+ type: "number",
2242
+ description: "Maximum number of results to return (default: 50)"
2243
+ },
2244
+ offset: {
2245
+ type: "number",
2246
+ description: "Number of results to skip for pagination (default: 0)"
2247
+ },
2248
+ search: {
2249
+ type: "string",
2250
+ description: "Filter by name/ID substring match (case-insensitive)"
2178
2251
  }
2179
2252
  },
2180
2253
  required: []
@@ -2193,6 +2266,14 @@ const searchContextTool = {
2193
2266
  contextDirectory: {
2194
2267
  type: "string",
2195
2268
  description: "Path to the .protokoll context directory"
2269
+ },
2270
+ limit: {
2271
+ type: "number",
2272
+ description: "Maximum number of results to return (default: 50)"
2273
+ },
2274
+ offset: {
2275
+ type: "number",
2276
+ description: "Number of results to skip for pagination (default: 0)"
2196
2277
  }
2197
2278
  },
2198
2279
  required: ["query"]
@@ -2221,6 +2302,35 @@ const getEntityTool = {
2221
2302
  required: ["entityType", "entityId"]
2222
2303
  }
2223
2304
  };
2305
+ const predictEntitiesTool = {
2306
+ name: "protokoll_predict_entities",
2307
+ description: "Predict likely entities based on transcript context using weight model. Returns ranked entity suggestions based on co-occurrence patterns and project affinity. Useful for intelligent entity correction suggestions.",
2308
+ inputSchema: {
2309
+ type: "object",
2310
+ properties: {
2311
+ transcriptPath: {
2312
+ type: "string",
2313
+ description: "Path to the transcript file"
2314
+ },
2315
+ maxPredictions: {
2316
+ type: "number",
2317
+ description: "Maximum number of predictions to return (default: 10)",
2318
+ minimum: 1,
2319
+ maximum: 50
2320
+ },
2321
+ minScore: {
2322
+ type: "number",
2323
+ description: "Minimum prediction score (default: 1)",
2324
+ minimum: 0
2325
+ },
2326
+ contextDirectory: {
2327
+ type: "string",
2328
+ description: "Path to the .protokoll context directory"
2329
+ }
2330
+ },
2331
+ required: ["transcriptPath"]
2332
+ }
2333
+ };
2224
2334
  async function handleContextStatus(args) {
2225
2335
  const context = await getContextInstance(args.contextDirectory);
2226
2336
  const dirs = context.getDiscoveredDirs();
@@ -2252,9 +2362,22 @@ async function handleListProjects(args) {
2252
2362
  if (!args.includeInactive) {
2253
2363
  projects = projects.filter((p) => p.active !== false);
2254
2364
  }
2365
+ if (args.search) {
2366
+ const searchLower = args.search.toLowerCase();
2367
+ projects = projects.filter(
2368
+ (p) => p.name.toLowerCase().includes(searchLower) || p.id.toLowerCase().includes(searchLower)
2369
+ );
2370
+ }
2371
+ const total = projects.length;
2372
+ const limit = args.limit ?? 50;
2373
+ const offset = args.offset ?? 0;
2374
+ const paginatedProjects = projects.slice(offset, offset + limit);
2255
2375
  return {
2256
- count: projects.length,
2257
- projects: projects.map((p) => ({
2376
+ total,
2377
+ limit,
2378
+ offset,
2379
+ count: paginatedProjects.length,
2380
+ projects: paginatedProjects.map((p) => ({
2258
2381
  id: p.id,
2259
2382
  name: p.name,
2260
2383
  active: p.active !== false,
@@ -2267,10 +2390,23 @@ async function handleListProjects(args) {
2267
2390
  }
2268
2391
  async function handleListPeople(args) {
2269
2392
  const context = await getContextInstance(args.contextDirectory);
2270
- const people = context.getAllPeople();
2393
+ let people = context.getAllPeople();
2394
+ if (args.search) {
2395
+ const searchLower = args.search.toLowerCase();
2396
+ people = people.filter(
2397
+ (p) => p.name.toLowerCase().includes(searchLower) || p.id.toLowerCase().includes(searchLower) || p.sounds_like?.some((s) => s.toLowerCase().includes(searchLower))
2398
+ );
2399
+ }
2400
+ const total = people.length;
2401
+ const limit = args.limit ?? 50;
2402
+ const offset = args.offset ?? 0;
2403
+ const paginatedPeople = people.slice(offset, offset + limit);
2271
2404
  return {
2272
- count: people.length,
2273
- people: people.map((p) => ({
2405
+ total,
2406
+ limit,
2407
+ offset,
2408
+ count: paginatedPeople.length,
2409
+ people: paginatedPeople.map((p) => ({
2274
2410
  id: p.id,
2275
2411
  name: p.name,
2276
2412
  company: p.company,
@@ -2281,10 +2417,23 @@ async function handleListPeople(args) {
2281
2417
  }
2282
2418
  async function handleListTerms(args) {
2283
2419
  const context = await getContextInstance(args.contextDirectory);
2284
- const terms = context.getAllTerms();
2420
+ let terms = context.getAllTerms();
2421
+ if (args.search) {
2422
+ const searchLower = args.search.toLowerCase();
2423
+ terms = terms.filter(
2424
+ (t) => t.name.toLowerCase().includes(searchLower) || t.id.toLowerCase().includes(searchLower) || t.sounds_like?.some((s) => s.toLowerCase().includes(searchLower))
2425
+ );
2426
+ }
2427
+ const total = terms.length;
2428
+ const limit = args.limit ?? 50;
2429
+ const offset = args.offset ?? 0;
2430
+ const paginatedTerms = terms.slice(offset, offset + limit);
2285
2431
  return {
2286
- count: terms.length,
2287
- terms: terms.map((t) => ({
2432
+ total,
2433
+ limit,
2434
+ offset,
2435
+ count: paginatedTerms.length,
2436
+ terms: paginatedTerms.map((t) => ({
2288
2437
  id: t.id,
2289
2438
  name: t.name,
2290
2439
  expansion: t.expansion,
@@ -2295,10 +2444,23 @@ async function handleListTerms(args) {
2295
2444
  }
2296
2445
  async function handleListCompanies(args) {
2297
2446
  const context = await getContextInstance(args.contextDirectory);
2298
- const companies = context.getAllCompanies();
2447
+ let companies = context.getAllCompanies();
2448
+ if (args.search) {
2449
+ const searchLower = args.search.toLowerCase();
2450
+ companies = companies.filter(
2451
+ (c) => c.name.toLowerCase().includes(searchLower) || c.id.toLowerCase().includes(searchLower) || c.sounds_like?.some((s) => s.toLowerCase().includes(searchLower))
2452
+ );
2453
+ }
2454
+ const total = companies.length;
2455
+ const limit = args.limit ?? 50;
2456
+ const offset = args.offset ?? 0;
2457
+ const paginatedCompanies = companies.slice(offset, offset + limit);
2299
2458
  return {
2300
- count: companies.length,
2301
- companies: companies.map((c) => ({
2459
+ total,
2460
+ limit,
2461
+ offset,
2462
+ count: paginatedCompanies.length,
2463
+ companies: paginatedCompanies.map((c) => ({
2302
2464
  id: c.id,
2303
2465
  name: c.name,
2304
2466
  fullName: c.fullName,
@@ -2310,10 +2472,17 @@ async function handleListCompanies(args) {
2310
2472
  async function handleSearchContext(args) {
2311
2473
  const context = await getContextInstance(args.contextDirectory);
2312
2474
  const results = context.search(args.query);
2475
+ const total = results.length;
2476
+ const limit = args.limit ?? 50;
2477
+ const offset = args.offset ?? 0;
2478
+ const paginatedResults = results.slice(offset, offset + limit);
2313
2479
  return {
2314
2480
  query: args.query,
2315
- count: results.length,
2316
- results: results.map(formatEntity)
2481
+ total,
2482
+ limit,
2483
+ offset,
2484
+ count: paginatedResults.length,
2485
+ results: paginatedResults.map(formatEntity)
2317
2486
  };
2318
2487
  }
2319
2488
  async function handleGetEntity(args) {
@@ -2344,6 +2513,36 @@ async function handleGetEntity(args) {
2344
2513
  filePath
2345
2514
  };
2346
2515
  }
2516
+ async function handlePredictEntities(args) {
2517
+ const { resolveTranscriptPath } = await Promise.resolve().then(() => shared);
2518
+ const { Transcript: TranscriptUtils } = await import('@redaksjon/protokoll-engine');
2519
+ const { ensurePklExtension } = TranscriptUtils;
2520
+ const { PklTranscript } = await import('@redaksjon/protokoll-format');
2521
+ const absolutePath = await resolveTranscriptPath(args.transcriptPath, args.contextDirectory);
2522
+ const pklPath = ensurePklExtension(absolutePath);
2523
+ const transcript = PklTranscript.open(pklPath, { readOnly: true });
2524
+ const projectId = transcript.metadata.project;
2525
+ const entities = transcript.metadata.entities || {};
2526
+ const knownEntityIds = [
2527
+ ...(entities.people || []).map((e) => e.id),
2528
+ ...(entities.projects || []).map((e) => e.id),
2529
+ ...(entities.terms || []).map((e) => e.id),
2530
+ ...(entities.companies || []).map((e) => e.id)
2531
+ ];
2532
+ transcript.close();
2533
+ const { getWeightModelService } = await import('./weightModel.js');
2534
+ const service = getWeightModelService();
2535
+ if (!service?.isReady || !service.provider) {
2536
+ return { success: true, predictions: [] };
2537
+ }
2538
+ const predictions = service.provider.predictLikelyEntities({
2539
+ knownEntityIds,
2540
+ projectId,
2541
+ maxPredictions: args.maxPredictions || 10,
2542
+ minScore: args.minScore ?? 1
2543
+ });
2544
+ return { success: true, predictions };
2545
+ }
2347
2546
 
2348
2547
  const addPersonTool = {
2349
2548
  name: "protokoll_add_person",
@@ -2898,6 +3097,51 @@ const addCompanyTool = {
2898
3097
  required: ["name"]
2899
3098
  }
2900
3099
  };
3100
+ const editCompanyTool = {
3101
+ name: "protokoll_edit_company",
3102
+ description: "Edit an existing company with manual modifications. Can update company details and manage sounds_like variants.",
3103
+ inputSchema: {
3104
+ type: "object",
3105
+ properties: {
3106
+ id: {
3107
+ type: "string",
3108
+ description: "Company ID to edit"
3109
+ },
3110
+ name: {
3111
+ type: "string",
3112
+ description: "Update company name"
3113
+ },
3114
+ fullName: {
3115
+ type: "string",
3116
+ description: "Set full legal name"
3117
+ },
3118
+ industry: {
3119
+ type: "string",
3120
+ description: "Set industry"
3121
+ },
3122
+ sounds_like: {
3123
+ type: "array",
3124
+ items: { type: "string" },
3125
+ description: "Replace entire sounds_like array"
3126
+ },
3127
+ add_sounds_like: {
3128
+ type: "array",
3129
+ items: { type: "string" },
3130
+ description: "Add sounds_like variants"
3131
+ },
3132
+ remove_sounds_like: {
3133
+ type: "array",
3134
+ items: { type: "string" },
3135
+ description: "Remove sounds_like variants"
3136
+ },
3137
+ contextDirectory: {
3138
+ type: "string",
3139
+ description: "Path to the .protokoll context directory"
3140
+ }
3141
+ },
3142
+ required: ["id"]
3143
+ }
3144
+ };
2901
3145
  const deleteEntityTool = {
2902
3146
  name: "protokoll_delete_entity",
2903
3147
  description: "Delete an entity from the context. Removes the entity's YAML file from the context directory.",
@@ -3426,6 +3670,47 @@ async function handleAddCompany(args) {
3426
3670
  entity: formatEntity(company)
3427
3671
  };
3428
3672
  }
3673
+ async function handleEditCompany(args) {
3674
+ const context = await create({
3675
+ startingDir: args.contextDirectory || process.cwd()
3676
+ });
3677
+ if (!context.hasContext()) {
3678
+ throw new Error("No .protokoll directory found. Initialize context first.");
3679
+ }
3680
+ const existingCompany = findCompanyResilient(context, args.id);
3681
+ const updatedSoundsLike = mergeArray(
3682
+ existingCompany.sounds_like,
3683
+ args.sounds_like,
3684
+ args.add_sounds_like,
3685
+ args.remove_sounds_like
3686
+ );
3687
+ const updatedCompany = {
3688
+ ...existingCompany,
3689
+ ...args.name !== void 0 && { name: args.name },
3690
+ ...args.fullName !== void 0 && { fullName: args.fullName },
3691
+ ...args.industry !== void 0 && { industry: args.industry },
3692
+ updatedAt: /* @__PURE__ */ new Date()
3693
+ };
3694
+ if (updatedSoundsLike !== void 0) {
3695
+ updatedCompany.sounds_like = updatedSoundsLike;
3696
+ } else if (existingCompany.sounds_like && (args.sounds_like !== void 0 || args.remove_sounds_like)) {
3697
+ delete updatedCompany.sounds_like;
3698
+ }
3699
+ await context.saveEntity(updatedCompany, true);
3700
+ const changes = [];
3701
+ if (args.name !== void 0) changes.push(`name: "${args.name}"`);
3702
+ if (args.fullName !== void 0) changes.push(`fullName: "${args.fullName}"`);
3703
+ if (args.industry !== void 0) changes.push(`industry: "${args.industry}"`);
3704
+ if (args.sounds_like !== void 0) changes.push(`sounds_like replaced with ${args.sounds_like.length} items`);
3705
+ if (args.add_sounds_like?.length) changes.push(`added ${args.add_sounds_like.length} sounds_like variants`);
3706
+ if (args.remove_sounds_like?.length) changes.push(`removed ${args.remove_sounds_like.length} sounds_like variants`);
3707
+ return {
3708
+ success: true,
3709
+ message: `Updated company "${existingCompany.name}"`,
3710
+ changes,
3711
+ company: formatEntity(updatedCompany)
3712
+ };
3713
+ }
3429
3714
  async function handleDeleteEntity(args) {
3430
3715
  const context = await create({
3431
3716
  startingDir: args.contextDirectory || process.cwd()
@@ -3460,6 +3745,34 @@ async function handleDeleteEntity(args) {
3460
3745
  };
3461
3746
  }
3462
3747
 
3748
+ const entityTools = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
3749
+ __proto__: null,
3750
+ addCompanyTool,
3751
+ addPersonTool,
3752
+ addProjectTool,
3753
+ addTermTool,
3754
+ deleteEntityTool,
3755
+ editCompanyTool,
3756
+ editPersonTool,
3757
+ editProjectTool,
3758
+ editTermTool,
3759
+ handleAddCompany,
3760
+ handleAddPerson,
3761
+ handleAddProject,
3762
+ handleAddTerm,
3763
+ handleDeleteEntity,
3764
+ handleEditCompany,
3765
+ handleEditPerson,
3766
+ handleEditProject,
3767
+ handleEditTerm,
3768
+ handleMergeTerms,
3769
+ handleUpdateProject,
3770
+ handleUpdateTerm,
3771
+ mergeTermsTool,
3772
+ updateProjectTool,
3773
+ updateTermTool
3774
+ }, Symbol.toStringTag, { value: 'Module' }));
3775
+
3463
3776
  const suggestProjectMetadataTool = {
3464
3777
  name: "protokoll_suggest_project_metadata",
3465
3778
  description: "Generate project metadata suggestions without creating the project. Returns sounds_like (phonetic variants for transcription), explicit_phrases (content-matching trigger phrases), topics and description from source content. Useful for interactive workflows where AI assistant presents suggestions for user review before creating the project.",
@@ -3585,6 +3898,15 @@ const listTranscriptsTool = {
3585
3898
  type: "string",
3586
3899
  description: "Search for transcripts containing this text (searches filename and content)"
3587
3900
  },
3901
+ entityId: {
3902
+ type: "string",
3903
+ description: "Filter to transcripts that reference this entity ID"
3904
+ },
3905
+ entityType: {
3906
+ type: "string",
3907
+ enum: ["person", "project", "term", "company"],
3908
+ description: "Entity type to filter by (used with entityId to narrow search)"
3909
+ },
3588
3910
  contextDirectory: {
3589
3911
  type: "string",
3590
3912
  description: "Optional: Path to the .protokoll context directory"
@@ -3835,6 +4157,72 @@ const createNoteTool = {
3835
4157
  required: ["title"]
3836
4158
  }
3837
4159
  };
4160
+ const getEnhancementLogTool = {
4161
+ name: "protokoll_get_enhancement_log",
4162
+ description: "Get the enhancement log for a transcript. Returns a timestamped audit trail of enhancement pipeline steps (transcribe, enhance, simple-replace phases). Shows what happened during processing: entities found, corrections applied, tools called, etc.",
4163
+ inputSchema: {
4164
+ type: "object",
4165
+ properties: {
4166
+ transcriptPath: {
4167
+ type: "string",
4168
+ description: 'Transcript URI (preferred) or relative path from output directory. URI format: "protokoll://transcript/2026/2/12-1606-meeting" (no file extension). Path format: "2026/2/12-1606-meeting" or "2026/2/12-1606-meeting.pkl"'
4169
+ },
4170
+ phase: {
4171
+ type: "string",
4172
+ enum: ["transcribe", "enhance", "simple-replace"],
4173
+ description: "Optional: Filter to a specific phase"
4174
+ },
4175
+ limit: {
4176
+ type: "number",
4177
+ description: "Maximum number of entries to return (default: 100)"
4178
+ },
4179
+ offset: {
4180
+ type: "number",
4181
+ description: "Number of entries to skip for pagination (default: 0)"
4182
+ },
4183
+ contextDirectory: {
4184
+ type: "string",
4185
+ description: "Optional: Path to the .protokoll context directory"
4186
+ }
4187
+ },
4188
+ required: ["transcriptPath"]
4189
+ }
4190
+ };
4191
+ const correctToEntityTool = {
4192
+ name: "protokoll_correct_to_entity",
4193
+ description: "Correct misheard text in transcript by mapping to existing or new entity. Atomically updates transcript content, adds misspelling to entity sounds_like array, updates entity references, and logs the correction to enhancement_log. This is the primary mechanism for training the transcription system.",
4194
+ inputSchema: {
4195
+ type: "object",
4196
+ properties: {
4197
+ transcriptPath: {
4198
+ type: "string",
4199
+ description: "Path to transcript file"
4200
+ },
4201
+ selectedText: {
4202
+ type: "string",
4203
+ description: "The misheard text to correct"
4204
+ },
4205
+ entityType: {
4206
+ type: "string",
4207
+ enum: ["person", "project", "term", "company"],
4208
+ description: "Type of entity"
4209
+ },
4210
+ entityId: {
4211
+ type: "string",
4212
+ description: "ID of existing entity (for map-to-existing flow)"
4213
+ },
4214
+ entityName: {
4215
+ type: "string",
4216
+ description: "Name of new entity to create (for create-new flow)"
4217
+ },
4218
+ contextDirectory: {
4219
+ type: "string",
4220
+ description: "Path to .protokoll context directory"
4221
+ }
4222
+ },
4223
+ required: ["transcriptPath", "selectedText", "entityType"]
4224
+ }
4225
+ };
3838
4226
  async function handleReadTranscript(args) {
3839
4227
  const absolutePath = await resolveTranscriptPath$1(args.transcriptPath, args.contextDirectory);
3840
4228
  const transcriptData = await readTranscript(absolutePath);
@@ -3875,6 +4263,8 @@ async function handleListTranscripts(args) {
3875
4263
  startDate: args.startDate,
3876
4264
  endDate: args.endDate,
3877
4265
  search: args.search
4266
+ // entityId: args.entityId,
4267
+ // entityType: args.entityType,
3878
4268
  });
3879
4269
  const outputDirectory = await getConfiguredDirectory("outputDirectory", args.contextDirectory);
3880
4270
  const relativeTranscripts = await Promise.all(
@@ -3904,7 +4294,9 @@ async function handleListTranscripts(args) {
3904
4294
  sortBy: args.sortBy ?? "date",
3905
4295
  startDate: args.startDate,
3906
4296
  endDate: args.endDate,
3907
- search: args.search
4297
+ search: args.search,
4298
+ entityId: args.entityId,
4299
+ entityType: args.entityType
3908
4300
  }
3909
4301
  };
3910
4302
  }
@@ -4155,11 +4547,16 @@ async function handleUpdateTranscriptEntityReferences(args) {
4155
4547
  };
4156
4548
  const pklPath = ensurePklExtension(absolutePath);
4157
4549
  const transcript = PklTranscript.open(pklPath, { readOnly: false });
4550
+ const transcriptUuid = transcript.metadata.id;
4551
+ const projectId = transcript.metadata.project;
4158
4552
  try {
4159
4553
  transcript.updateMetadata({ entities });
4160
4554
  } finally {
4161
4555
  transcript.close();
4162
4556
  }
4557
+ const { updateTranscriptInWeightModel } = await import('./weightModel.js');
4558
+ const allEntityIds = entityReferences.map((e) => e.id);
4559
+ updateTranscriptInWeightModel(transcriptUuid, allEntityIds, projectId);
4163
4560
  const outputDirectory = await getConfiguredDirectory("outputDirectory", args.contextDirectory);
4164
4561
  const relativePath = await sanitizePath(pklPath, outputDirectory);
4165
4562
  return {
@@ -4291,6 +4688,206 @@ async function handleCreateNote(args) {
4291
4688
  message: `Note "${args.title}" created successfully`
4292
4689
  };
4293
4690
  }
4691
+ async function handleGetEnhancementLog(args) {
4692
+ const absolutePath = await resolveTranscriptPath$1(args.transcriptPath, args.contextDirectory);
4693
+ const transcript = PklTranscript.open(absolutePath, { readOnly: true });
4694
+ try {
4695
+ const allEntries = [];
4696
+ const limit = args.limit ?? 100;
4697
+ const offset = args.offset ?? 0;
4698
+ const total = allEntries.length;
4699
+ const entries = allEntries.slice(offset, offset + limit);
4700
+ const serializedEntries = entries.map((entry) => ({
4701
+ id: entry.id,
4702
+ timestamp: entry.timestamp.toISOString(),
4703
+ phase: entry.phase,
4704
+ action: entry.action,
4705
+ details: entry.details,
4706
+ entities: entry.entities
4707
+ }));
4708
+ return {
4709
+ entries: serializedEntries,
4710
+ total,
4711
+ limit,
4712
+ offset,
4713
+ hasMore: offset + limit < total
4714
+ };
4715
+ } finally {
4716
+ transcript.close();
4717
+ }
4718
+ }
4719
+ function applyCorrections(transcriptText, corrections) {
4720
+ let correctedText = transcriptText;
4721
+ for (const [original, corrected] of corrections) {
4722
+ if (original !== corrected && corrected.trim() !== "") {
4723
+ const regex = new RegExp(original.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "gi");
4724
+ correctedText = correctedText.replace(regex, corrected);
4725
+ }
4726
+ }
4727
+ return correctedText;
4728
+ }
4729
+ async function handleCorrectToEntity(args) {
4730
+ const context = await create({ startingDir: args.contextDirectory || process.cwd() });
4731
+ const absolutePath = await resolveTranscriptPath$1(args.transcriptPath, args.contextDirectory);
4732
+ const pklPath = ensurePklExtension(absolutePath);
4733
+ let finalEntityId;
4734
+ let finalEntityName;
4735
+ let isNewEntity = false;
4736
+ if (args.entityName) {
4737
+ const EntityTools2 = await Promise.resolve().then(() => entityTools);
4738
+ const createArgs = { name: args.entityName, contextDirectory: args.contextDirectory };
4739
+ try {
4740
+ let result;
4741
+ switch (args.entityType) {
4742
+ case "person":
4743
+ result = await EntityTools2.handleAddPerson(createArgs);
4744
+ break;
4745
+ case "project":
4746
+ result = await EntityTools2.handleAddProject(createArgs);
4747
+ break;
4748
+ case "term":
4749
+ result = await EntityTools2.handleAddTerm({ term: args.entityName, contextDirectory: args.contextDirectory });
4750
+ break;
4751
+ case "company":
4752
+ result = await EntityTools2.handleAddCompany(createArgs);
4753
+ break;
4754
+ }
4755
+ finalEntityId = result.entity.id;
4756
+ finalEntityName = result.entity.name;
4757
+ isNewEntity = true;
4758
+ } catch (error) {
4759
+ const match = error.message?.match(/ID\s+["']([^"']+)["']\s+already exists/i);
4760
+ if (match) {
4761
+ finalEntityId = match[1];
4762
+ const { findPersonResilient, findProjectResilient, findTermResilient, findCompanyResilient } = await import('@redaksjon/protokoll-engine');
4763
+ let entity;
4764
+ switch (args.entityType) {
4765
+ case "person":
4766
+ entity = findPersonResilient(context, finalEntityId);
4767
+ break;
4768
+ case "project":
4769
+ entity = findProjectResilient(context, finalEntityId);
4770
+ break;
4771
+ case "term":
4772
+ entity = findTermResilient(context, finalEntityId);
4773
+ break;
4774
+ case "company":
4775
+ entity = findCompanyResilient(context, finalEntityId);
4776
+ break;
4777
+ }
4778
+ finalEntityName = entity.name;
4779
+ } else {
4780
+ throw error;
4781
+ }
4782
+ }
4783
+ } else if (args.entityId) {
4784
+ finalEntityId = args.entityId;
4785
+ const { findPersonResilient, findProjectResilient, findTermResilient, findCompanyResilient } = await import('@redaksjon/protokoll-engine');
4786
+ let entity;
4787
+ switch (args.entityType) {
4788
+ case "person":
4789
+ entity = findPersonResilient(context, finalEntityId);
4790
+ break;
4791
+ case "project":
4792
+ entity = findProjectResilient(context, finalEntityId);
4793
+ break;
4794
+ case "term":
4795
+ entity = findTermResilient(context, finalEntityId);
4796
+ break;
4797
+ case "company":
4798
+ entity = findCompanyResilient(context, finalEntityId);
4799
+ break;
4800
+ }
4801
+ finalEntityName = entity.name;
4802
+ } else {
4803
+ throw new Error("Either entityId or entityName must be provided");
4804
+ }
4805
+ const transcript = PklTranscript.open(pklPath, { readOnly: false });
4806
+ const originalContent = transcript.content;
4807
+ const corrections = /* @__PURE__ */ new Map([[args.selectedText, finalEntityName]]);
4808
+ const correctedContent = applyCorrections(originalContent, corrections);
4809
+ transcript.updateContent(correctedContent);
4810
+ const EntityTools = await Promise.resolve().then(() => entityTools);
4811
+ const editArgs = {
4812
+ id: finalEntityId,
4813
+ add_sounds_like: [args.selectedText],
4814
+ contextDirectory: args.contextDirectory
4815
+ };
4816
+ switch (args.entityType) {
4817
+ case "person":
4818
+ await EntityTools.handleEditPerson(editArgs);
4819
+ break;
4820
+ case "project":
4821
+ await EntityTools.handleEditProject(editArgs);
4822
+ break;
4823
+ case "term":
4824
+ await EntityTools.handleEditTerm(editArgs);
4825
+ break;
4826
+ case "company":
4827
+ await EntityTools.handleEditCompany(editArgs);
4828
+ break;
4829
+ }
4830
+ const entities = transcript.metadata.entities || { people: [], projects: [], terms: [], companies: [] };
4831
+ const entityRef = { id: finalEntityId, name: finalEntityName, type: args.entityType };
4832
+ let entityArray;
4833
+ switch (args.entityType) {
4834
+ case "person":
4835
+ entityArray = entities.people || [];
4836
+ if (!entityArray.some((e) => e.id === finalEntityId)) {
4837
+ entities.people = [...entityArray, entityRef];
4838
+ }
4839
+ break;
4840
+ case "project":
4841
+ entityArray = entities.projects || [];
4842
+ if (!entityArray.some((e) => e.id === finalEntityId)) {
4843
+ entities.projects = [...entityArray, entityRef];
4844
+ }
4845
+ break;
4846
+ case "term":
4847
+ entityArray = entities.terms || [];
4848
+ if (!entityArray.some((e) => e.id === finalEntityId)) {
4849
+ entities.terms = [...entityArray, entityRef];
4850
+ }
4851
+ break;
4852
+ case "company":
4853
+ entityArray = entities.companies || [];
4854
+ if (!entityArray.some((e) => e.id === finalEntityId)) {
4855
+ entities.companies = [...entityArray, entityRef];
4856
+ }
4857
+ break;
4858
+ }
4859
+ transcript.updateMetadata({ entities });
4860
+ transcript.enhancementLog.logStep(
4861
+ /* @__PURE__ */ new Date(),
4862
+ "user-correction",
4863
+ // Type will be correct after protokoll-format link
4864
+ "correction_applied",
4865
+ {
4866
+ original: args.selectedText,
4867
+ replacement: finalEntityName,
4868
+ entityId: finalEntityId,
4869
+ entityType: args.entityType,
4870
+ isNewEntity
4871
+ },
4872
+ [{ id: finalEntityId, name: finalEntityName, type: args.entityType }]
4873
+ );
4874
+ transcript.close();
4875
+ const allEntityIds = [
4876
+ ...(entities.people || []).map((e) => e.id),
4877
+ ...(entities.projects || []).map((e) => e.id),
4878
+ ...(entities.terms || []).map((e) => e.id),
4879
+ ...(entities.companies || []).map((e) => e.id)
4880
+ ];
4881
+ const { updateTranscriptInWeightModel } = await import('./weightModel.js');
4882
+ updateTranscriptInWeightModel(transcript.metadata.id, allEntityIds, transcript.metadata.project);
4883
+ return {
4884
+ success: true,
4885
+ message: `Corrected "${args.selectedText}" to "${finalEntityName}"`,
4886
+ correction: { original: args.selectedText, replacement: finalEntityName },
4887
+ entity: { id: finalEntityId, name: finalEntityName, type: args.entityType },
4888
+ isNewEntity
4889
+ };
4890
+ }
4294
4891
 
4295
4892
  const getVersionTool = {
4296
4893
  name: "protokoll_get_version",
@@ -5127,6 +5724,307 @@ async function handleDeleteTask(args) {
5127
5724
  }
5128
5725
  }
5129
5726
 
5727
+ const {
5728
+ findUploadedTranscripts,
5729
+ findTranscribingTranscripts,
5730
+ resetTranscriptToUploaded,
5731
+ findTranscriptByUuid
5732
+ } = Transcript;
5733
+ let workerInstance = null;
5734
+ function setWorkerInstance(worker) {
5735
+ workerInstance = worker;
5736
+ }
5737
+ const queueStatusTool = {
5738
+ name: "protokoll_queue_status",
5739
+ description: "Get current upload queue status - pending transcriptions, processing, and recent completions. Shows what audio files are waiting to be transcribed and which are currently being processed.",
5740
+ inputSchema: {
5741
+ type: "object",
5742
+ properties: {}
5743
+ }
5744
+ };
5745
+ const getTranscriptByUuidTool = {
5746
+ name: "protokoll_get_transcript_by_uuid",
5747
+ description: "Get transcript metadata and status by UUID. Accepts either full UUID or 8-character prefix. Useful for checking upload status after receiving UUID from upload endpoint.",
5748
+ inputSchema: {
5749
+ type: "object",
5750
+ properties: {
5751
+ uuid: {
5752
+ type: "string",
5753
+ description: "UUID or 8-character UUID prefix"
5754
+ },
5755
+ includeContent: {
5756
+ type: "boolean",
5757
+ description: "Include transcript content (default: false). Only works for transcripts in initial/enhanced/reviewed status."
5758
+ }
5759
+ },
5760
+ required: ["uuid"]
5761
+ }
5762
+ };
5763
+ const retryTranscriptionTool = {
5764
+ name: "protokoll_retry_transcription",
5765
+ description: "Retry a failed transcription by resetting status from error to uploaded. The transcript will be re-queued for processing.",
5766
+ inputSchema: {
5767
+ type: "object",
5768
+ properties: {
5769
+ uuid: {
5770
+ type: "string",
5771
+ description: "UUID of transcript to retry"
5772
+ }
5773
+ },
5774
+ required: ["uuid"]
5775
+ }
5776
+ };
5777
+ const cancelTranscriptionTool = {
5778
+ name: "protokoll_cancel_transcription",
5779
+ description: "Cancel a pending or processing transcription. Optionally delete the PKL file.",
5780
+ inputSchema: {
5781
+ type: "object",
5782
+ properties: {
5783
+ uuid: {
5784
+ type: "string",
5785
+ description: "UUID of transcript to cancel"
5786
+ },
5787
+ deleteFile: {
5788
+ type: "boolean",
5789
+ description: "Also delete the PKL file (default: false)"
5790
+ }
5791
+ },
5792
+ required: ["uuid"]
5793
+ }
5794
+ };
5795
+ const workerStatusTool = {
5796
+ name: "protokoll_worker_status",
5797
+ description: "Get background transcription worker status and statistics. Shows if worker is running, current task, total processed, and uptime.",
5798
+ inputSchema: {
5799
+ type: "object",
5800
+ properties: {}
5801
+ }
5802
+ };
5803
+ const restartWorkerTool = {
5804
+ name: "protokoll_restart_worker",
5805
+ description: "Restart the background transcription worker. Useful if worker is stuck or needs to reload configuration.",
5806
+ inputSchema: {
5807
+ type: "object",
5808
+ properties: {}
5809
+ }
5810
+ };
5811
+ function getTranscribingStartTime(metadata) {
5812
+ if (!metadata.history || metadata.history.length === 0) {
5813
+ return metadata.date?.toISOString() || "";
5814
+ }
5815
+ const transcribingTransition = metadata.history.filter((h) => h.to === "transcribing").sort((a, b) => b.at.getTime() - a.at.getTime())[0];
5816
+ return transcribingTransition?.at.toISOString() || metadata.date?.toISOString() || "";
5817
+ }
5818
+ function getCompletionTime(metadata) {
5819
+ if (!metadata.history || metadata.history.length === 0) {
5820
+ return "";
5821
+ }
5822
+ const lastTransition = metadata.history.sort((a, b) => b.at.getTime() - a.at.getTime())[0];
5823
+ return lastTransition?.at.toISOString() || "";
5824
+ }
5825
+ async function findRecentTranscripts(searchDirectories, limit) {
5826
+ const results = [];
5827
+ const oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1e3);
5828
+ const { glob } = await import('glob');
5829
+ for (const dir of searchDirectories) {
5830
+ const files = await glob("????????-*.pkl", { cwd: dir, absolute: true });
5831
+ for (const file of files) {
5832
+ try {
5833
+ const transcript = PklTranscript.open(file, { readOnly: true });
5834
+ const metadata = transcript.metadata;
5835
+ const recentlyCompleted = metadata.history?.some(
5836
+ (h) => h.at >= oneDayAgo && ["initial", "enhanced", "reviewed", "error"].includes(h.to)
5837
+ );
5838
+ if (recentlyCompleted) {
5839
+ results.push({
5840
+ uuid: metadata.id,
5841
+ filePath: file,
5842
+ metadata
5843
+ });
5844
+ }
5845
+ await transcript.close();
5846
+ } catch (error) {
5847
+ console.warn(`Failed to open transcript ${file}:`, error);
5848
+ }
5849
+ }
5850
+ }
5851
+ results.sort((a, b) => {
5852
+ const aTime = a.metadata.history?.[a.metadata.history.length - 1]?.at.getTime() || 0;
5853
+ const bTime = b.metadata.history?.[b.metadata.history.length - 1]?.at.getTime() || 0;
5854
+ return bTime - aTime;
5855
+ });
5856
+ return results.slice(0, limit);
5857
+ }
5858
+ async function handleQueueStatus() {
5859
+ const outputDir = getOutputDirectory();
5860
+ const uploaded = await findUploadedTranscripts([outputDir]);
5861
+ const transcribing = await findTranscribingTranscripts([outputDir]);
5862
+ const recent = await findRecentTranscripts([outputDir], 10);
5863
+ return {
5864
+ pending: uploaded.map((t) => ({
5865
+ uuid: t.uuid,
5866
+ filename: t.metadata.audioFile || "unknown",
5867
+ uploadedAt: t.metadata.date?.toISOString() || ""
5868
+ })),
5869
+ processing: transcribing.map((t) => ({
5870
+ uuid: t.uuid,
5871
+ filename: t.metadata.audioFile || "unknown",
5872
+ startedAt: getTranscribingStartTime(t.metadata)
5873
+ })),
5874
+ recent: recent.map((t) => ({
5875
+ uuid: t.uuid,
5876
+ filename: t.metadata.audioFile || t.metadata.title || "unknown",
5877
+ completedAt: getCompletionTime(t.metadata),
5878
+ status: t.metadata.status || "unknown"
5879
+ })),
5880
+ totalPending: uploaded.length
5881
+ };
5882
+ }
5883
+ async function handleGetTranscriptByUuid(args) {
5884
+ try {
5885
+ const outputDir = getOutputDirectory();
5886
+ const filePath = await findTranscriptByUuid(args.uuid, [outputDir]);
5887
+ if (!filePath) {
5888
+ return { found: false, error: `No transcript found for UUID: ${args.uuid}` };
5889
+ }
5890
+ const transcript = PklTranscript.open(filePath, { readOnly: true });
5891
+ const metadata = transcript.metadata;
5892
+ const result = {
5893
+ found: true,
5894
+ uuid: metadata.id,
5895
+ filePath: await sanitizePath(filePath, outputDir),
5896
+ metadata
5897
+ };
5898
+ if (args.includeContent && ["initial", "enhanced", "reviewed"].includes(metadata.status || "")) {
5899
+ result.content = transcript.content || "";
5900
+ }
5901
+ await transcript.close();
5902
+ return result;
5903
+ } catch (error) {
5904
+ return { found: false, error: error instanceof Error ? error.message : String(error) };
5905
+ }
5906
+ }
5907
+ async function handleRetryTranscription(args) {
5908
+ try {
5909
+ const outputDir = getOutputDirectory();
5910
+ const filePath = await findTranscriptByUuid(args.uuid, [outputDir]);
5911
+ if (!filePath) {
5912
+ return {
5913
+ success: false,
5914
+ message: "",
5915
+ error: `No transcript found for UUID: ${args.uuid}`
5916
+ };
5917
+ }
5918
+ const transcript = PklTranscript.open(filePath, { readOnly: true });
5919
+ const metadata = transcript.metadata;
5920
+ await transcript.close();
5921
+ if (metadata.status !== "error") {
5922
+ return {
5923
+ success: false,
5924
+ message: "",
5925
+ error: `Transcript is not in error status (current: ${metadata.status})`
5926
+ };
5927
+ }
5928
+ await resetTranscriptToUploaded(filePath);
5929
+ return {
5930
+ success: true,
5931
+ message: `Transcript ${args.uuid} reset to uploaded status and re-queued`
5932
+ };
5933
+ } catch (error) {
5934
+ return {
5935
+ success: false,
5936
+ message: "",
5937
+ error: error instanceof Error ? error.message : String(error)
5938
+ };
5939
+ }
5940
+ }
5941
+ async function handleCancelTranscription(args) {
5942
+ try {
5943
+ const outputDir = getOutputDirectory();
5944
+ const filePath = await findTranscriptByUuid(args.uuid, [outputDir]);
5945
+ if (!filePath) {
5946
+ return {
5947
+ success: false,
5948
+ message: "",
5949
+ error: `No transcript found for UUID: ${args.uuid}`
5950
+ };
5951
+ }
5952
+ const transcript = PklTranscript.open(filePath, { readOnly: true });
5953
+ const metadata = transcript.metadata;
5954
+ await transcript.close();
5955
+ if (!["uploaded", "transcribing"].includes(metadata.status || "")) {
5956
+ return {
5957
+ success: false,
5958
+ message: "",
5959
+ error: `Cannot cancel transcript in ${metadata.status} status. Only uploaded/transcribing can be cancelled.`
5960
+ };
5961
+ }
5962
+ if (args.deleteFile) {
5963
+ await unlink(filePath);
5964
+ return {
5965
+ success: true,
5966
+ message: `Transcript ${args.uuid} cancelled and file deleted`
5967
+ };
5968
+ } else {
5969
+ const transcriptToUpdate = PklTranscript.open(filePath);
5970
+ transcriptToUpdate.updateMetadata({
5971
+ status: "error",
5972
+ errorDetails: "Cancelled by user"
5973
+ });
5974
+ await transcriptToUpdate.close();
5975
+ return {
5976
+ success: true,
5977
+ message: `Transcript ${args.uuid} cancelled (marked as error)`
5978
+ };
5979
+ }
5980
+ } catch (error) {
5981
+ return {
5982
+ success: false,
5983
+ message: "",
5984
+ error: error instanceof Error ? error.message : String(error)
5985
+ };
5986
+ }
5987
+ }
5988
+ async function handleWorkerStatus() {
5989
+ if (!workerInstance) {
5990
+ return {
5991
+ isRunning: false,
5992
+ totalProcessed: 0,
5993
+ uptime: 0
5994
+ };
5995
+ }
5996
+ return {
5997
+ isRunning: workerInstance.isActive(),
5998
+ currentTask: workerInstance.getCurrentTask(),
5999
+ totalProcessed: workerInstance.getProcessedCount(),
6000
+ lastProcessed: workerInstance.getLastProcessedTime(),
6001
+ uptime: workerInstance.getUptime()
6002
+ };
6003
+ }
6004
+ async function handleRestartWorker() {
6005
+ if (!workerInstance) {
6006
+ return {
6007
+ success: false,
6008
+ message: "",
6009
+ error: "Worker not initialized"
6010
+ };
6011
+ }
6012
+ try {
6013
+ await workerInstance.stop();
6014
+ await workerInstance.start();
6015
+ return {
6016
+ success: true,
6017
+ message: "Worker restarted successfully"
6018
+ };
6019
+ } catch (error) {
6020
+ return {
6021
+ success: false,
6022
+ message: "",
6023
+ error: error instanceof Error ? error.message : String(error)
6024
+ };
6025
+ }
6026
+ }
6027
+
5130
6028
  const tools = [
5131
6029
  // System Information
5132
6030
  getVersionTool,
@@ -5145,6 +6043,7 @@ const tools = [
5145
6043
  listCompaniesTool,
5146
6044
  searchContextTool,
5147
6045
  getEntityTool,
6046
+ predictEntitiesTool,
5148
6047
  // Entity CRUD
5149
6048
  addPersonTool,
5150
6049
  editPersonTool,
@@ -5156,6 +6055,7 @@ const tools = [
5156
6055
  updateTermTool,
5157
6056
  mergeTermsTool,
5158
6057
  addCompanyTool,
6058
+ editCompanyTool,
5159
6059
  deleteEntityTool,
5160
6060
  // Relationship Management
5161
6061
  addRelationshipTool,
@@ -5180,11 +6080,20 @@ const tools = [
5180
6080
  updateTranscriptContentTool,
5181
6081
  updateTranscriptEntityReferencesTool,
5182
6082
  createNoteTool,
6083
+ getEnhancementLogTool,
6084
+ correctToEntityTool,
5183
6085
  // Lifecycle Status & Tasks
5184
6086
  setStatusTool,
5185
6087
  createTaskTool,
5186
6088
  completeTaskTool,
5187
- deleteTaskTool
6089
+ deleteTaskTool,
6090
+ // Queue Management
6091
+ queueStatusTool,
6092
+ getTranscriptByUuidTool,
6093
+ retryTranscriptionTool,
6094
+ cancelTranscriptionTool,
6095
+ workerStatusTool,
6096
+ restartWorkerTool
5188
6097
  ];
5189
6098
  async function handleToolCall(name, args) {
5190
6099
  switch (name) {
@@ -5218,6 +6127,8 @@ async function handleToolCall(name, args) {
5218
6127
  return handleSearchContext(args);
5219
6128
  case "protokoll_get_entity":
5220
6129
  return handleGetEntity(args);
6130
+ case "protokoll_predict_entities":
6131
+ return handlePredictEntities(args);
5221
6132
  // Entity CRUD
5222
6133
  case "protokoll_add_person":
5223
6134
  return handleAddPerson(args);
@@ -5239,6 +6150,8 @@ async function handleToolCall(name, args) {
5239
6150
  return handleMergeTerms(args);
5240
6151
  case "protokoll_add_company":
5241
6152
  return handleAddCompany(args);
6153
+ case "protokoll_edit_company":
6154
+ return handleEditCompany(args);
5242
6155
  case "protokoll_delete_entity":
5243
6156
  return handleDeleteEntity(args);
5244
6157
  // Smart Assistance
@@ -5283,6 +6196,10 @@ async function handleToolCall(name, args) {
5283
6196
  return handleUpdateTranscriptEntityReferences(args);
5284
6197
  case "protokoll_create_note":
5285
6198
  return handleCreateNote(args);
6199
+ case "protokoll_get_enhancement_log":
6200
+ return handleGetEnhancementLog(args);
6201
+ case "protokoll_correct_to_entity":
6202
+ return handleCorrectToEntity(args);
5286
6203
  // Lifecycle Status & Tasks
5287
6204
  case "protokoll_set_status":
5288
6205
  return handleSetStatus(args);
@@ -5292,6 +6209,19 @@ async function handleToolCall(name, args) {
5292
6209
  return handleCompleteTask(args);
5293
6210
  case "protokoll_delete_task":
5294
6211
  return handleDeleteTask(args);
6212
+ // Queue Management
6213
+ case "protokoll_queue_status":
6214
+ return handleQueueStatus();
6215
+ case "protokoll_get_transcript_by_uuid":
6216
+ return handleGetTranscriptByUuid(args);
6217
+ case "protokoll_retry_transcription":
6218
+ return handleRetryTranscription(args);
6219
+ case "protokoll_cancel_transcription":
6220
+ return handleCancelTranscription(args);
6221
+ case "protokoll_worker_status":
6222
+ return handleWorkerStatus();
6223
+ case "protokoll_restart_worker":
6224
+ return handleRestartWorker();
5295
6225
  default:
5296
6226
  throw new Error(`Unknown tool: ${name}`);
5297
6227
  }
@@ -5391,5 +6321,5 @@ async function initializeWorkingDirectoryFromArgsAndConfig() {
5391
6321
  }
5392
6322
  }
5393
6323
 
5394
- export { DEFAULT_CONFIG_FILE as D, handleListResources as a, handleReadResource as b, getPrompt as c, initializeServerConfig as d, getCachedRoots as e, getServerConfig as f, getPrompts as g, handleToolCall as h, initializeWorkingDirectoryFromArgsAndConfig as i, getContext as j, serverConfig$1 as k, loadCardigantimeConfig as l, setRoots as s, tools as t, uri as u };
6324
+ export { DEFAULT_CONFIG_FILE as D, handleListResources as a, handleReadResource as b, getPrompt as c, initializeServerConfig as d, getCachedRoots as e, getServerConfig as f, getPrompts as g, handleToolCall as h, initializeWorkingDirectoryFromArgsAndConfig as i, getContext as j, getOutputDirectory as k, loadCardigantimeConfig as l, setWorkerInstance as m, serverConfig$1 as n, setRoots as s, tools as t, uri as u };
5395
6325
  //# sourceMappingURL=configDiscovery.js.map