@redaksjon/protokoll 1.0.0 → 1.0.2
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/dist/main.js +3 -2
- package/dist/main.js.map +1 -1
- package/dist/mcp/prompts/batch_transcription.md +50 -1
- package/dist/mcp/prompts/edit_entity.md +50 -1
- package/dist/mcp/prompts/enrich_entity.md +95 -2
- package/dist/mcp/prompts/find_and_analyze.md +127 -0
- package/dist/mcp/prompts/review_transcript.md +39 -1
- package/dist/mcp/server.js +41 -8
- package/dist/mcp/server.js.map +1 -1
- package/dist/term-assist.js +4 -2
- package/dist/term-assist.js.map +1 -1
- package/dist/term-context.js +4 -2
- package/dist/term-context.js.map +1 -1
- package/dist/transcript.js +335 -288
- package/dist/transcript.js.map +1 -1
- package/docs/mcp-tools/get-version.md +57 -0
- package/package.json +4 -2
package/dist/transcript.js
CHANGED
|
@@ -2,23 +2,26 @@ import * as readline from 'readline';
|
|
|
2
2
|
import { spawn } from 'child_process';
|
|
3
3
|
import * as path from 'node:path';
|
|
4
4
|
import path__default from 'node:path';
|
|
5
|
-
import * as fs$
|
|
5
|
+
import * as fs$2 from 'fs/promises';
|
|
6
6
|
import OpenAI$1, { OpenAI } from 'openai';
|
|
7
7
|
import ffmpeg from 'fluent-ffmpeg';
|
|
8
8
|
import * as os from 'node:os';
|
|
9
9
|
import os__default from 'node:os';
|
|
10
|
+
import { IterationStrategyFactory, ToolRegistry, ConversationBuilder } from '@riotprompt/riotprompt';
|
|
11
|
+
import { z } from 'zod';
|
|
10
12
|
import * as fs from 'node:fs';
|
|
13
|
+
import { existsSync, statSync } from 'node:fs';
|
|
11
14
|
import { glob } from 'glob';
|
|
12
15
|
import crypto from 'node:crypto';
|
|
13
|
-
import * as fs$
|
|
16
|
+
import * as fs$1 from 'node:fs/promises';
|
|
14
17
|
import { htmlToText } from 'html-to-text';
|
|
15
18
|
import { Command } from 'commander';
|
|
19
|
+
import { discoverOvercontext, discoverContextRoot } from '@theunwalked/overcontext';
|
|
20
|
+
import { redaksjonPluralNames, redaksjonSchemas } from '@redaksjon/context';
|
|
16
21
|
import * as yaml from 'js-yaml';
|
|
17
|
-
import { existsSync, statSync } from 'fs';
|
|
18
22
|
import winston from 'winston';
|
|
19
|
-
import { IterationStrategyFactory } from '@riotprompt/riotprompt';
|
|
20
23
|
|
|
21
|
-
const VERSION = "1.0.
|
|
24
|
+
const VERSION = "1.0.2 (HEAD/bcca7ab T:v1.0.2 2026-01-28 09:24:52 -0800) linux x64 v24.13.0";
|
|
22
25
|
const PROGRAM_NAME = "protokoll";
|
|
23
26
|
const DEFAULT_DIFF = true;
|
|
24
27
|
const DEFAULT_LOG = false;
|
|
@@ -242,216 +245,168 @@ const create$w = (params) => {
|
|
|
242
245
|
};
|
|
243
246
|
};
|
|
244
247
|
|
|
245
|
-
const
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
const isChildProject = (projectA, projectB) => {
|
|
249
|
-
return projectA.relationships?.parent === projectB.id;
|
|
250
|
-
};
|
|
251
|
-
const areSiblingProjects = (projectA, projectB) => {
|
|
252
|
-
const aSiblings = projectA.relationships?.siblings || [];
|
|
253
|
-
const bSiblings = projectB.relationships?.siblings || [];
|
|
254
|
-
return aSiblings.includes(projectB.id) || bSiblings.includes(projectA.id);
|
|
255
|
-
};
|
|
256
|
-
const getProjectRelationshipDistance = (projectA, projectB) => {
|
|
257
|
-
if (projectA.id === projectB.id) return 0;
|
|
258
|
-
if (isParentProject(projectA, projectB) || isChildProject(projectA, projectB)) return 1;
|
|
259
|
-
if (areSiblingProjects(projectA, projectB)) return 2;
|
|
260
|
-
if (projectA.relationships?.parent && projectB.relationships?.parent && projectA.relationships.parent === projectB.relationships.parent) {
|
|
261
|
-
return 2;
|
|
262
|
-
}
|
|
263
|
-
return -1;
|
|
248
|
+
const protokollDiscoveryOptions = {
|
|
249
|
+
contextDirName: ".protokoll/context",
|
|
250
|
+
maxLevels: 10
|
|
264
251
|
};
|
|
265
252
|
|
|
266
|
-
const DIRECTORY_TO_TYPE = {
|
|
267
|
-
"people": "person",
|
|
268
|
-
"projects": "project",
|
|
269
|
-
"companies": "company",
|
|
270
|
-
"terms": "term",
|
|
271
|
-
"ignored": "ignored"
|
|
272
|
-
};
|
|
273
253
|
const TYPE_TO_DIRECTORY = {
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
254
|
+
person: "people",
|
|
255
|
+
project: "projects",
|
|
256
|
+
company: "companies",
|
|
257
|
+
term: "terms",
|
|
258
|
+
ignored: "ignored"
|
|
279
259
|
};
|
|
280
260
|
const create$v = () => {
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
if (parsed && parsed.id) {
|
|
300
|
-
entities.get(entityType)?.set(parsed.id, {
|
|
301
|
-
...parsed,
|
|
302
|
-
type: entityType
|
|
303
|
-
});
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
} catch {
|
|
307
|
-
}
|
|
261
|
+
const cache = /* @__PURE__ */ new Map();
|
|
262
|
+
let api;
|
|
263
|
+
let loadedContextDirs = [];
|
|
264
|
+
const initCache = () => {
|
|
265
|
+
cache.set("person", /* @__PURE__ */ new Map());
|
|
266
|
+
cache.set("project", /* @__PURE__ */ new Map());
|
|
267
|
+
cache.set("company", /* @__PURE__ */ new Map());
|
|
268
|
+
cache.set("term", /* @__PURE__ */ new Map());
|
|
269
|
+
cache.set("ignored", /* @__PURE__ */ new Map());
|
|
270
|
+
};
|
|
271
|
+
initCache();
|
|
272
|
+
return {
|
|
273
|
+
async load(contextDirs) {
|
|
274
|
+
initCache();
|
|
275
|
+
loadedContextDirs = contextDirs;
|
|
276
|
+
if (contextDirs.length === 0) {
|
|
277
|
+
api = void 0;
|
|
278
|
+
return;
|
|
308
279
|
}
|
|
309
|
-
}
|
|
310
|
-
};
|
|
311
|
-
const save = async (entity, targetDir) => {
|
|
312
|
-
const dirName = TYPE_TO_DIRECTORY[entity.type];
|
|
313
|
-
const dirPath = path.join(targetDir, "context", dirName);
|
|
314
|
-
await fs$1.mkdir(dirPath, { recursive: true });
|
|
315
|
-
const filePath = path.join(dirPath, `${entity.id}.yaml`);
|
|
316
|
-
const { type: _entityType, ...entityWithoutType } = entity;
|
|
317
|
-
const content = yaml.dump(entityWithoutType, { lineWidth: -1 });
|
|
318
|
-
await fs$1.writeFile(filePath, content, "utf-8");
|
|
319
|
-
entities.get(entity.type)?.set(entity.id, entity);
|
|
320
|
-
};
|
|
321
|
-
const deleteEntity = async (type, id, targetDir) => {
|
|
322
|
-
const dirName = TYPE_TO_DIRECTORY[type];
|
|
323
|
-
const possiblePaths = [
|
|
324
|
-
path.join(targetDir, dirName, `${id}.yaml`),
|
|
325
|
-
path.join(targetDir, dirName, `${id}.yml`),
|
|
326
|
-
path.join(targetDir, "context", dirName, `${id}.yaml`),
|
|
327
|
-
path.join(targetDir, "context", dirName, `${id}.yml`)
|
|
328
|
-
];
|
|
329
|
-
for (const filePath of possiblePaths) {
|
|
330
280
|
try {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
path.join(contextDir, dirName, `${id}.yml`)
|
|
345
|
-
];
|
|
346
|
-
for (const filePath of possiblePaths) {
|
|
347
|
-
if (existsSync(filePath)) {
|
|
348
|
-
const stat = statSync(filePath);
|
|
349
|
-
if (stat.isFile()) {
|
|
350
|
-
return filePath;
|
|
281
|
+
const lastContextDir = contextDirs[contextDirs.length - 1];
|
|
282
|
+
const protokollDir = lastContextDir.replace(/\/context$/, "");
|
|
283
|
+
const startDir = protokollDir.replace(/\/\.protokoll$/, "");
|
|
284
|
+
api = await discoverOvercontext({
|
|
285
|
+
schemas: redaksjonSchemas,
|
|
286
|
+
pluralNames: redaksjonPluralNames,
|
|
287
|
+
startDir,
|
|
288
|
+
...protokollDiscoveryOptions
|
|
289
|
+
});
|
|
290
|
+
for (const type of ["person", "project", "company", "term", "ignored"]) {
|
|
291
|
+
const entities = await api.getAll(type);
|
|
292
|
+
for (const entity of entities) {
|
|
293
|
+
cache.get(type)?.set(entity.id, entity);
|
|
351
294
|
}
|
|
352
295
|
}
|
|
296
|
+
} catch (error) {
|
|
297
|
+
if (error instanceof Error && error.message.includes("No context directory found")) {
|
|
298
|
+
api = void 0;
|
|
299
|
+
} else {
|
|
300
|
+
throw error;
|
|
301
|
+
}
|
|
353
302
|
}
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
const getAll = (type) => {
|
|
361
|
-
return Array.from(entities.get(type)?.values() ?? []);
|
|
362
|
-
};
|
|
363
|
-
const search = (query) => {
|
|
364
|
-
const normalizedQuery = query.toLowerCase();
|
|
365
|
-
const results = [];
|
|
366
|
-
const seen = /* @__PURE__ */ new Set();
|
|
367
|
-
for (const entityMap of entities.values()) {
|
|
368
|
-
for (const entity of entityMap.values()) {
|
|
369
|
-
let matched = false;
|
|
370
|
-
if (entity.name.toLowerCase().includes(normalizedQuery)) {
|
|
371
|
-
matched = true;
|
|
303
|
+
},
|
|
304
|
+
async save(entity, _targetDir) {
|
|
305
|
+
if (!api) {
|
|
306
|
+
const existing = cache.get(entity.type)?.get(entity.id);
|
|
307
|
+
if (existing) {
|
|
308
|
+
throw new Error(`Entity with id "${entity.id}" already exists`);
|
|
372
309
|
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
310
|
+
cache.get(entity.type)?.set(entity.id, entity);
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
const saved = await api.upsert(entity.type, entity);
|
|
314
|
+
cache.get(entity.type)?.set(saved.id, saved);
|
|
315
|
+
},
|
|
316
|
+
async delete(type, id, _targetDir) {
|
|
317
|
+
if (!api) return false;
|
|
318
|
+
const deleted = await api.delete(type, id);
|
|
319
|
+
if (deleted) {
|
|
320
|
+
cache.get(type)?.delete(id);
|
|
321
|
+
}
|
|
322
|
+
return deleted;
|
|
323
|
+
},
|
|
324
|
+
get(type, id) {
|
|
325
|
+
return cache.get(type)?.get(id);
|
|
326
|
+
},
|
|
327
|
+
getAll(type) {
|
|
328
|
+
return Array.from(cache.get(type)?.values() ?? []);
|
|
329
|
+
},
|
|
330
|
+
search(query) {
|
|
331
|
+
const normalizedQuery = query.toLowerCase();
|
|
332
|
+
const results = [];
|
|
333
|
+
const seen = /* @__PURE__ */ new Set();
|
|
334
|
+
for (const entityMap of cache.values()) {
|
|
335
|
+
for (const entity of entityMap.values()) {
|
|
336
|
+
if (seen.has(entity.id)) continue;
|
|
337
|
+
if (entity.name.toLowerCase().includes(normalizedQuery)) {
|
|
338
|
+
results.push(entity);
|
|
339
|
+
seen.add(entity.id);
|
|
340
|
+
continue;
|
|
378
341
|
}
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
if (variants?.some((v) => v.toLowerCase() === normalizedQuery)) {
|
|
384
|
-
matched = true;
|
|
342
|
+
const sounds = entity.sounds_like;
|
|
343
|
+
if (sounds?.some((s) => s.toLowerCase().includes(normalizedQuery))) {
|
|
344
|
+
results.push(entity);
|
|
345
|
+
seen.add(entity.id);
|
|
385
346
|
}
|
|
386
347
|
}
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
348
|
+
}
|
|
349
|
+
return results;
|
|
350
|
+
},
|
|
351
|
+
findBySoundsLike(phonetic) {
|
|
352
|
+
const normalized = phonetic.toLowerCase().trim();
|
|
353
|
+
for (const entityMap of cache.values()) {
|
|
354
|
+
for (const entity of entityMap.values()) {
|
|
355
|
+
const sounds = entity.sounds_like;
|
|
356
|
+
if (sounds?.some((s) => s.toLowerCase() === normalized)) {
|
|
357
|
+
return entity;
|
|
358
|
+
}
|
|
390
359
|
}
|
|
391
360
|
}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
361
|
+
return void 0;
|
|
362
|
+
},
|
|
363
|
+
clear() {
|
|
364
|
+
initCache();
|
|
365
|
+
api = void 0;
|
|
366
|
+
},
|
|
367
|
+
getEntityFilePath(type, id, contextDirs) {
|
|
368
|
+
const dirName = TYPE_TO_DIRECTORY[type];
|
|
369
|
+
const dirsToSearch = contextDirs.length > 0 ? contextDirs : loadedContextDirs;
|
|
370
|
+
for (const contextDir of [...dirsToSearch].reverse()) {
|
|
371
|
+
const possiblePaths = [
|
|
372
|
+
path.join(contextDir, dirName, `${id}.yaml`),
|
|
373
|
+
path.join(contextDir, dirName, `${id}.yml`)
|
|
374
|
+
];
|
|
375
|
+
for (const filePath of possiblePaths) {
|
|
376
|
+
if (existsSync(filePath)) {
|
|
377
|
+
const stat = statSync(filePath);
|
|
378
|
+
if (stat.isFile()) {
|
|
379
|
+
return filePath;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
403
382
|
}
|
|
404
383
|
}
|
|
405
|
-
|
|
406
|
-
return void 0;
|
|
407
|
-
};
|
|
408
|
-
const clear = () => {
|
|
409
|
-
for (const entityMap of entities.values()) {
|
|
410
|
-
entityMap.clear();
|
|
384
|
+
return void 0;
|
|
411
385
|
}
|
|
412
386
|
};
|
|
413
|
-
return { load, save, delete: deleteEntity, get, getAll, search, findBySoundsLike, clear, getEntityFilePath };
|
|
414
387
|
};
|
|
415
388
|
|
|
416
389
|
const discoverConfigDirectories = async (options) => {
|
|
417
|
-
const {
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
while (level < maxLevels) {
|
|
427
|
-
const realPath = path.resolve(currentDir);
|
|
428
|
-
if (visited.has(realPath)) break;
|
|
429
|
-
visited.add(realPath);
|
|
430
|
-
const configDirPath = path.join(currentDir, configDirName);
|
|
431
|
-
try {
|
|
432
|
-
const stat = await fs$1.stat(configDirPath);
|
|
433
|
-
if (stat.isDirectory()) {
|
|
434
|
-
discovered.push({ path: configDirPath, level });
|
|
435
|
-
}
|
|
436
|
-
} catch {
|
|
437
|
-
}
|
|
438
|
-
const parentDir = path.dirname(currentDir);
|
|
439
|
-
if (parentDir === currentDir) break;
|
|
440
|
-
currentDir = parentDir;
|
|
441
|
-
level++;
|
|
442
|
-
}
|
|
443
|
-
return discovered;
|
|
390
|
+
const contextRoot = await discoverContextRoot({
|
|
391
|
+
startDir: options.startingDir || process.cwd(),
|
|
392
|
+
contextDirName: options.configDirName,
|
|
393
|
+
maxLevels: options.maxLevels || 10
|
|
394
|
+
});
|
|
395
|
+
return contextRoot.directories.map((dir) => ({
|
|
396
|
+
path: dir.path,
|
|
397
|
+
level: dir.level
|
|
398
|
+
}));
|
|
444
399
|
};
|
|
445
400
|
const loadHierarchicalConfig = async (options) => {
|
|
446
|
-
const
|
|
447
|
-
if (
|
|
401
|
+
const discovered = await discoverConfigDirectories(options);
|
|
402
|
+
if (discovered.length === 0) {
|
|
448
403
|
return {
|
|
449
404
|
config: {},
|
|
450
405
|
discoveredDirs: [],
|
|
451
406
|
contextDirs: []
|
|
452
407
|
};
|
|
453
408
|
}
|
|
454
|
-
const sortedDirs = [...
|
|
409
|
+
const sortedDirs = [...discovered].sort((a, b) => b.level - a.level);
|
|
455
410
|
const configs = [];
|
|
456
411
|
const contextDirs = [];
|
|
457
412
|
for (const dir of sortedDirs) {
|
|
@@ -474,41 +429,36 @@ const loadHierarchicalConfig = async (options) => {
|
|
|
474
429
|
}
|
|
475
430
|
}
|
|
476
431
|
const mergedConfig = configs.reduce(
|
|
477
|
-
(acc, curr) =>
|
|
432
|
+
(acc, curr) => ({ ...acc, ...curr }),
|
|
478
433
|
{}
|
|
479
434
|
);
|
|
480
435
|
return {
|
|
481
436
|
config: mergedConfig,
|
|
482
|
-
discoveredDirs,
|
|
437
|
+
discoveredDirs: discovered,
|
|
483
438
|
contextDirs
|
|
484
439
|
};
|
|
485
440
|
};
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
const
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
);
|
|
505
|
-
} else {
|
|
506
|
-
result[key] = sourceVal;
|
|
507
|
-
}
|
|
508
|
-
}
|
|
441
|
+
|
|
442
|
+
const isParentProject = (projectA, projectB) => {
|
|
443
|
+
return projectB.relationships?.parent === projectA.id;
|
|
444
|
+
};
|
|
445
|
+
const isChildProject = (projectA, projectB) => {
|
|
446
|
+
return projectA.relationships?.parent === projectB.id;
|
|
447
|
+
};
|
|
448
|
+
const areSiblingProjects = (projectA, projectB) => {
|
|
449
|
+
const aSiblings = projectA.relationships?.siblings || [];
|
|
450
|
+
const bSiblings = projectB.relationships?.siblings || [];
|
|
451
|
+
return aSiblings.includes(projectB.id) || bSiblings.includes(projectA.id);
|
|
452
|
+
};
|
|
453
|
+
const getProjectRelationshipDistance = (projectA, projectB) => {
|
|
454
|
+
if (projectA.id === projectB.id) return 0;
|
|
455
|
+
if (isParentProject(projectA, projectB) || isChildProject(projectA, projectB)) return 1;
|
|
456
|
+
if (areSiblingProjects(projectA, projectB)) return 2;
|
|
457
|
+
if (projectA.relationships?.parent && projectB.relationships?.parent && projectA.relationships.parent === projectB.relationships.parent) {
|
|
458
|
+
return 2;
|
|
509
459
|
}
|
|
510
|
-
return
|
|
511
|
-
}
|
|
460
|
+
return -1;
|
|
461
|
+
};
|
|
512
462
|
|
|
513
463
|
const getSmartAssistanceConfig = (config) => {
|
|
514
464
|
const smartConfig = config.smartAssistance;
|
|
@@ -576,10 +526,6 @@ const create$u = async (options = {}) => {
|
|
|
576
526
|
},
|
|
577
527
|
search: (query) => storage.search(query),
|
|
578
528
|
findBySoundsLike: (phonetic) => storage.findBySoundsLike(phonetic),
|
|
579
|
-
/**
|
|
580
|
-
* Context-aware search that prefers entities related to context project.
|
|
581
|
-
* Still returns standard search results if no context provided.
|
|
582
|
-
*/
|
|
583
529
|
searchWithContext: (query, contextProjectId) => {
|
|
584
530
|
const results = storage.search(query);
|
|
585
531
|
if (!contextProjectId) {
|
|
@@ -607,10 +553,6 @@ const create$u = async (options = {}) => {
|
|
|
607
553
|
});
|
|
608
554
|
return scoredResults.sort((a, b) => b.score - a.score).map((r) => r.entity);
|
|
609
555
|
},
|
|
610
|
-
/**
|
|
611
|
-
* Get all projects related to a given project within maxDistance
|
|
612
|
-
* Distance: 0 = same, 1 = parent/child, 2 = siblings/cousins
|
|
613
|
-
*/
|
|
614
556
|
getRelatedProjects: (projectId, maxDistance = 2) => {
|
|
615
557
|
const project = storage.get("project", projectId);
|
|
616
558
|
if (!project) return [];
|
|
@@ -1170,7 +1112,7 @@ const create$p = () => {
|
|
|
1170
1112
|
error: `Unsupported file type: ${ext}. Supported: ${supportedExtensions.join(", ")}`
|
|
1171
1113
|
};
|
|
1172
1114
|
}
|
|
1173
|
-
let content = await fs$
|
|
1115
|
+
let content = await fs$1.readFile(filePath, "utf-8");
|
|
1174
1116
|
if (content.length > MAX_CONTENT_LENGTH) {
|
|
1175
1117
|
content = content.substring(0, MAX_CONTENT_LENGTH) + "\n\n[Content truncated...]";
|
|
1176
1118
|
}
|
|
@@ -1192,7 +1134,7 @@ const create$p = () => {
|
|
|
1192
1134
|
const fetchDirectory = async (dirPath) => {
|
|
1193
1135
|
logger.debug("Reading directory: %s", dirPath);
|
|
1194
1136
|
try {
|
|
1195
|
-
const files = await fs$
|
|
1137
|
+
const files = await fs$1.readdir(dirPath);
|
|
1196
1138
|
const priorityFiles = [
|
|
1197
1139
|
"README.md",
|
|
1198
1140
|
"readme.md",
|
|
@@ -1251,7 +1193,7 @@ const create$p = () => {
|
|
|
1251
1193
|
return await fetchUrl(source);
|
|
1252
1194
|
}
|
|
1253
1195
|
const resolvedPath = path.resolve(source);
|
|
1254
|
-
const stat = await fs$
|
|
1196
|
+
const stat = await fs$1.stat(resolvedPath);
|
|
1255
1197
|
if (stat.isDirectory()) {
|
|
1256
1198
|
return await fetchDirectory(resolvedPath);
|
|
1257
1199
|
} else {
|
|
@@ -2443,9 +2385,9 @@ const create$l = (config) => {
|
|
|
2443
2385
|
};
|
|
2444
2386
|
};
|
|
2445
2387
|
const ensureDirectories = async (paths) => {
|
|
2446
|
-
await fs$
|
|
2447
|
-
await fs$
|
|
2448
|
-
await fs$
|
|
2388
|
+
await fs$2.mkdir(path.dirname(paths.intermediate.transcript), { recursive: true });
|
|
2389
|
+
await fs$2.mkdir(path.dirname(paths.final), { recursive: true });
|
|
2390
|
+
await fs$2.mkdir(path.dirname(paths.rawTranscript), { recursive: true });
|
|
2449
2391
|
logger.debug("Ensured output directories", {
|
|
2450
2392
|
intermediate: path.dirname(paths.intermediate.transcript),
|
|
2451
2393
|
final: path.dirname(paths.final),
|
|
@@ -2458,7 +2400,7 @@ const create$l = (config) => {
|
|
|
2458
2400
|
throw new Error(`Invalid intermediate type: ${type}`);
|
|
2459
2401
|
}
|
|
2460
2402
|
const contentStr = typeof content === "string" ? content : JSON.stringify(content, null, 2);
|
|
2461
|
-
await fs$
|
|
2403
|
+
await fs$2.writeFile(filePath, contentStr, "utf-8");
|
|
2462
2404
|
logger.debug("Wrote intermediate file", { type, path: filePath });
|
|
2463
2405
|
return filePath;
|
|
2464
2406
|
};
|
|
@@ -2472,7 +2414,7 @@ const create$l = (config) => {
|
|
|
2472
2414
|
finalContent = finalContent + entitySection;
|
|
2473
2415
|
}
|
|
2474
2416
|
}
|
|
2475
|
-
await fs$
|
|
2417
|
+
await fs$2.writeFile(paths.final, finalContent, "utf-8");
|
|
2476
2418
|
logger.info("Wrote final transcript", { path: paths.final });
|
|
2477
2419
|
return paths.final;
|
|
2478
2420
|
};
|
|
@@ -2484,7 +2426,7 @@ const create$l = (config) => {
|
|
|
2484
2426
|
for (const [type, filePath] of Object.entries(paths.intermediate)) {
|
|
2485
2427
|
if (filePath) {
|
|
2486
2428
|
try {
|
|
2487
|
-
await fs$
|
|
2429
|
+
await fs$2.unlink(filePath);
|
|
2488
2430
|
logger.debug("Removed intermediate file", { type, path: filePath });
|
|
2489
2431
|
} catch {
|
|
2490
2432
|
}
|
|
@@ -2493,7 +2435,7 @@ const create$l = (config) => {
|
|
|
2493
2435
|
};
|
|
2494
2436
|
const writeRawTranscript = async (paths, data) => {
|
|
2495
2437
|
const filePath = paths.rawTranscript;
|
|
2496
|
-
await fs$
|
|
2438
|
+
await fs$2.writeFile(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
2497
2439
|
logger.debug("Wrote raw transcript to .transcript/", { path: filePath });
|
|
2498
2440
|
return filePath;
|
|
2499
2441
|
};
|
|
@@ -2502,7 +2444,7 @@ const create$l = (config) => {
|
|
|
2502
2444
|
const finalBasename = path.basename(finalOutputPath, path.extname(finalOutputPath));
|
|
2503
2445
|
const rawTranscriptPath = path.join(finalDir, ".transcript", `${finalBasename}.json`);
|
|
2504
2446
|
try {
|
|
2505
|
-
const content = await fs$
|
|
2447
|
+
const content = await fs$2.readFile(rawTranscriptPath, "utf-8");
|
|
2506
2448
|
return JSON.parse(content);
|
|
2507
2449
|
} catch (error) {
|
|
2508
2450
|
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
@@ -2928,7 +2870,7 @@ const create$i = (config) => {
|
|
|
2928
2870
|
};
|
|
2929
2871
|
const save = async (report, path) => {
|
|
2930
2872
|
const content = formatMarkdown(report) ;
|
|
2931
|
-
await fs$
|
|
2873
|
+
await fs$2.writeFile(path, content, "utf-8");
|
|
2932
2874
|
logger.info("Saved reflection report", { path });
|
|
2933
2875
|
};
|
|
2934
2876
|
return {
|
|
@@ -3913,6 +3855,17 @@ const create$7 = (_ctx) => ({
|
|
|
3913
3855
|
}
|
|
3914
3856
|
});
|
|
3915
3857
|
|
|
3858
|
+
const toRiotTool = (tool, category) => ({
|
|
3859
|
+
name: tool.name,
|
|
3860
|
+
description: tool.description,
|
|
3861
|
+
parameters: tool.parameters,
|
|
3862
|
+
category,
|
|
3863
|
+
cost: "cheap",
|
|
3864
|
+
execute: async (params) => {
|
|
3865
|
+
const result = await tool.execute(params);
|
|
3866
|
+
return result;
|
|
3867
|
+
}
|
|
3868
|
+
});
|
|
3916
3869
|
const create$6 = (ctx) => {
|
|
3917
3870
|
const tools = [
|
|
3918
3871
|
create$b(ctx),
|
|
@@ -3922,13 +3875,19 @@ const create$6 = (ctx) => {
|
|
|
3922
3875
|
create$7()
|
|
3923
3876
|
];
|
|
3924
3877
|
const toolMap = new Map(tools.map((t) => [t.name, t]));
|
|
3878
|
+
const riotRegistry = ToolRegistry.create();
|
|
3879
|
+
riotRegistry.register(toRiotTool(tools[0], "lookup"));
|
|
3880
|
+
riotRegistry.register(toRiotTool(tools[1], "lookup"));
|
|
3881
|
+
riotRegistry.register(toRiotTool(tools[2], "verification"));
|
|
3882
|
+
riotRegistry.register(toRiotTool(tools[3], "routing"));
|
|
3883
|
+
riotRegistry.register(toRiotTool(tools[4], "storage"));
|
|
3925
3884
|
return {
|
|
3926
3885
|
getTools: () => tools,
|
|
3927
|
-
//
|
|
3928
|
-
getToolDefinitions: () =>
|
|
3929
|
-
name:
|
|
3930
|
-
description:
|
|
3931
|
-
parameters:
|
|
3886
|
+
// Use RiotPrompt's OpenAI format export
|
|
3887
|
+
getToolDefinitions: () => riotRegistry.toOpenAIFormat().map((t) => ({
|
|
3888
|
+
name: t.function.name,
|
|
3889
|
+
description: t.function.description,
|
|
3890
|
+
parameters: t.function.parameters
|
|
3932
3891
|
})),
|
|
3933
3892
|
executeTool: async (name, args) => {
|
|
3934
3893
|
const tool = toolMap.get(name);
|
|
@@ -3939,20 +3898,36 @@ const create$6 = (ctx) => {
|
|
|
3939
3898
|
};
|
|
3940
3899
|
}
|
|
3941
3900
|
return tool.execute(args);
|
|
3942
|
-
}
|
|
3901
|
+
},
|
|
3902
|
+
getRiotRegistry: () => riotRegistry
|
|
3943
3903
|
};
|
|
3944
3904
|
};
|
|
3945
3905
|
|
|
3906
|
+
const toRiotToolCalls = (toolCalls) => {
|
|
3907
|
+
return toolCalls.map((tc) => ({
|
|
3908
|
+
id: tc.id,
|
|
3909
|
+
type: "function",
|
|
3910
|
+
function: {
|
|
3911
|
+
name: tc.name,
|
|
3912
|
+
arguments: JSON.stringify(tc.arguments)
|
|
3913
|
+
}
|
|
3914
|
+
}));
|
|
3915
|
+
};
|
|
3946
3916
|
const cleanResponseContent = (content) => {
|
|
3947
3917
|
let cleaned = content.replace(/^(?:Using tools?|Let me|I'll|I will|Now I'll|First,?\s*I(?:'ll| will)).*?[\r\n]+/gim, "");
|
|
3948
|
-
cleaned = cleaned.replace(/\{"tool":\s*"[^"]+",\s*"input":\s*\{[^}]*\}\}/g, "");
|
|
3918
|
+
cleaned = cleaned.replace(/\{"tool":\s*"[^"]+",\s*"(?:args|input)":\s*\{[^}]*\}\}/g, "");
|
|
3949
3919
|
cleaned = cleaned.replace(/\b\w+_\w+\(\{[^}]*\}\)/g, "");
|
|
3920
|
+
cleaned = cleaned.replace(/^.*\s+to=\w+\.\w+.*$/gm, "");
|
|
3921
|
+
const spamPattern = /^.*[\u4E00-\u9FFF].*(app|官网|彩票|中彩票).*$/gm;
|
|
3922
|
+
cleaned = cleaned.replace(spamPattern, "");
|
|
3923
|
+
const corruptionStartPattern = /^[\u0530-\u058F\u0E00-\u0E7F\u0A80-\u0AFF\u0C00-\u0C7F].*$/gm;
|
|
3924
|
+
cleaned = cleaned.replace(corruptionStartPattern, "");
|
|
3950
3925
|
const lines = cleaned.split("\n");
|
|
3951
3926
|
let startIndex = 0;
|
|
3952
3927
|
for (let i = 0; i < lines.length; i++) {
|
|
3953
3928
|
const line = lines[i].trim();
|
|
3954
3929
|
if (line === "") continue;
|
|
3955
|
-
const isCommentary = /^(checking|verifying|looking|searching|analyzing|processing|determining|using|calling|executing|I'm|I am|Let me)/i.test(line) || line.includes("tool") || line.includes('{"') || line.includes("reasoning");
|
|
3930
|
+
const isCommentary = /^(checking|verifying|looking|searching|analyzing|processing|determining|using|calling|executing|I'm|I am|Let me)/i.test(line) || line.includes("tool") || line.includes('{"') || line.includes("reasoning") || line.includes("undefined");
|
|
3956
3931
|
if (!isCommentary) {
|
|
3957
3932
|
startIndex = i;
|
|
3958
3933
|
break;
|
|
@@ -3961,6 +3936,7 @@ const cleanResponseContent = (content) => {
|
|
|
3961
3936
|
if (startIndex > 0) {
|
|
3962
3937
|
cleaned = lines.slice(startIndex).join("\n");
|
|
3963
3938
|
}
|
|
3939
|
+
cleaned = cleaned.replace(/\n{3,}/g, "\n\n");
|
|
3964
3940
|
return cleaned.trim();
|
|
3965
3941
|
};
|
|
3966
3942
|
const create$5 = (reasoning, ctx) => {
|
|
@@ -3986,7 +3962,20 @@ const create$5 = (reasoning, ctx) => {
|
|
|
3986
3962
|
let iterations = 0;
|
|
3987
3963
|
let totalTokens = 0;
|
|
3988
3964
|
const maxIterations = 15;
|
|
3989
|
-
const
|
|
3965
|
+
const conversation = ConversationBuilder.create({ model: "gpt-4o" }).withTokenBudget({
|
|
3966
|
+
max: 1e5,
|
|
3967
|
+
// 100k token context window
|
|
3968
|
+
reserveForResponse: 4e3,
|
|
3969
|
+
// Reserve 4k tokens for response
|
|
3970
|
+
strategy: "summarize",
|
|
3971
|
+
// Summarize old messages if budget exceeded
|
|
3972
|
+
onBudgetExceeded: "compress",
|
|
3973
|
+
// Automatically compress when exceeded
|
|
3974
|
+
preserveSystem: true,
|
|
3975
|
+
// Always keep system messages
|
|
3976
|
+
preserveRecent: 5
|
|
3977
|
+
// Keep last 5 messages
|
|
3978
|
+
});
|
|
3990
3979
|
const systemPrompt = `You are an intelligent transcription assistant. Your job is to:
|
|
3991
3980
|
1. Analyze the transcript for names, projects, and companies
|
|
3992
3981
|
2. Use the available tools to verify spellings and gather context
|
|
@@ -4015,7 +4004,7 @@ Available tools:
|
|
|
4015
4004
|
- verify_spelling: Ask user about unknown terms (if interactive mode)
|
|
4016
4005
|
- route_note: Determine where to file this note
|
|
4017
4006
|
- store_context: Remember new information for future use`;
|
|
4018
|
-
|
|
4007
|
+
conversation.addSystemMessage(systemPrompt);
|
|
4019
4008
|
const initialPrompt = `Here is the raw transcript to process:
|
|
4020
4009
|
|
|
4021
4010
|
--- BEGIN TRANSCRIPT ---
|
|
@@ -4030,7 +4019,7 @@ Please:
|
|
|
4030
4019
|
|
|
4031
4020
|
CRITICAL: Your response must contain ONLY the transcript text - no commentary, no explanations, no tool information.
|
|
4032
4021
|
Remember: preserve ALL content, only fix transcription errors.`;
|
|
4033
|
-
|
|
4022
|
+
conversation.addUserMessage(initialPrompt);
|
|
4034
4023
|
try {
|
|
4035
4024
|
logger.debug("Starting agentic transcription - analyzing for names and routing...");
|
|
4036
4025
|
let response = await reasoning.complete({
|
|
@@ -4042,15 +4031,14 @@ Remember: preserve ALL content, only fix transcription errors.`;
|
|
|
4042
4031
|
if (response.usage) {
|
|
4043
4032
|
totalTokens += response.usage.totalTokens;
|
|
4044
4033
|
}
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
});
|
|
4034
|
+
if (response.toolCalls && response.toolCalls.length > 0) {
|
|
4035
|
+
conversation.addAssistantWithToolCalls(
|
|
4036
|
+
response.content,
|
|
4037
|
+
toRiotToolCalls(response.toolCalls)
|
|
4038
|
+
);
|
|
4039
|
+
} else {
|
|
4040
|
+
conversation.addAssistantMessage(response.content);
|
|
4041
|
+
}
|
|
4054
4042
|
while (response.toolCalls && response.toolCalls.length > 0 && iterations < maxIterations) {
|
|
4055
4043
|
iterations++;
|
|
4056
4044
|
logger.debug("Iteration %d: Processing %d tool calls...", iterations, response.toolCalls.length);
|
|
@@ -4534,11 +4522,7 @@ ${termName}: ${wizardResult.termDescription}`.trim() : linkedProject.description
|
|
|
4534
4522
|
}
|
|
4535
4523
|
}
|
|
4536
4524
|
for (const tr of toolResults) {
|
|
4537
|
-
|
|
4538
|
-
role: "tool",
|
|
4539
|
-
tool_call_id: tr.id,
|
|
4540
|
-
content: tr.result
|
|
4541
|
-
});
|
|
4525
|
+
conversation.addToolResult(tr.id, tr.result, tr.name);
|
|
4542
4526
|
}
|
|
4543
4527
|
const continuationPrompt = `Tool results received. Here's a reminder of your task:
|
|
4544
4528
|
|
|
@@ -4554,7 +4538,7 @@ When you're done with tool calls, output the COMPLETE corrected transcript as Ma
|
|
|
4554
4538
|
Do NOT summarize - include ALL original content with corrections applied.
|
|
4555
4539
|
|
|
4556
4540
|
CRITICAL REMINDER: Your response must contain ONLY the transcript text. Do NOT include any commentary, explanations, or processing notes - those will leak into the user-facing document.`;
|
|
4557
|
-
|
|
4541
|
+
conversation.addUserMessage(continuationPrompt);
|
|
4558
4542
|
response = await reasoning.complete({
|
|
4559
4543
|
systemPrompt,
|
|
4560
4544
|
prompt: continuationPrompt,
|
|
@@ -4563,24 +4547,38 @@ CRITICAL REMINDER: Your response must contain ONLY the transcript text. Do NOT i
|
|
|
4563
4547
|
if (response.usage) {
|
|
4564
4548
|
totalTokens += response.usage.totalTokens;
|
|
4565
4549
|
}
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
});
|
|
4550
|
+
if (response.toolCalls && response.toolCalls.length > 0) {
|
|
4551
|
+
conversation.addAssistantWithToolCalls(
|
|
4552
|
+
response.content,
|
|
4553
|
+
toRiotToolCalls(response.toolCalls)
|
|
4554
|
+
);
|
|
4555
|
+
} else {
|
|
4556
|
+
conversation.addAssistantMessage(response.content);
|
|
4557
|
+
}
|
|
4575
4558
|
}
|
|
4576
4559
|
if (response.content && response.content.length > 50) {
|
|
4577
4560
|
const cleanedContent = cleanResponseContent(response.content);
|
|
4578
4561
|
if (cleanedContent !== response.content) {
|
|
4562
|
+
const removedChars = response.content.length - cleanedContent.length;
|
|
4579
4563
|
logger.warn(
|
|
4580
|
-
"Removed leaked internal processing from response (%d -> %d chars)",
|
|
4564
|
+
"Removed leaked internal processing from response (%d -> %d chars, removed %d chars)",
|
|
4581
4565
|
response.content.length,
|
|
4582
|
-
cleanedContent.length
|
|
4566
|
+
cleanedContent.length,
|
|
4567
|
+
removedChars
|
|
4583
4568
|
);
|
|
4569
|
+
const corruptionRatio = removedChars / response.content.length;
|
|
4570
|
+
const hasSuspiciousUnicode = /[\u0530-\u058F\u0E00-\u0E7F\u4E00-\u9FFF\u0A80-\u0AFF\u0C00-\u0C7F]/.test(response.content);
|
|
4571
|
+
if (corruptionRatio > 0.1 || hasSuspiciousUnicode) {
|
|
4572
|
+
logger.error(
|
|
4573
|
+
"SEVERE CORRUPTION DETECTED in LLM response (%.1f%% removed, suspicious unicode: %s)",
|
|
4574
|
+
corruptionRatio * 100,
|
|
4575
|
+
hasSuspiciousUnicode
|
|
4576
|
+
);
|
|
4577
|
+
logger.error(
|
|
4578
|
+
"Raw response preview (first 500 chars): %s",
|
|
4579
|
+
response.content.substring(0, 500).replace(/\n/g, "\\n")
|
|
4580
|
+
);
|
|
4581
|
+
}
|
|
4584
4582
|
}
|
|
4585
4583
|
state.correctedText = cleanedContent;
|
|
4586
4584
|
state.confidence = 0.9;
|
|
@@ -4607,11 +4605,26 @@ CRITICAL: Your response must contain ONLY the corrected transcript text - absolu
|
|
|
4607
4605
|
}
|
|
4608
4606
|
const cleanedFinalContent = cleanResponseContent(finalResponse.content || transcriptText);
|
|
4609
4607
|
if (cleanedFinalContent !== finalResponse.content) {
|
|
4608
|
+
const removedChars = (finalResponse.content?.length || 0) - cleanedFinalContent.length;
|
|
4610
4609
|
logger.warn(
|
|
4611
|
-
"Removed leaked internal processing from final response (%d -> %d chars)",
|
|
4610
|
+
"Removed leaked internal processing from final response (%d -> %d chars, removed %d chars)",
|
|
4612
4611
|
finalResponse.content?.length || 0,
|
|
4613
|
-
cleanedFinalContent.length
|
|
4612
|
+
cleanedFinalContent.length,
|
|
4613
|
+
removedChars
|
|
4614
4614
|
);
|
|
4615
|
+
const corruptionRatio = removedChars / (finalResponse.content?.length || 1);
|
|
4616
|
+
const hasSuspiciousUnicode = /[\u0530-\u058F\u0E00-\u0E7F\u4E00-\u9FFF\u0A80-\u0AFF\u0C00-\u0C7F]/.test(finalResponse.content || "");
|
|
4617
|
+
if (corruptionRatio > 0.1 || hasSuspiciousUnicode) {
|
|
4618
|
+
logger.error(
|
|
4619
|
+
"SEVERE CORRUPTION DETECTED in final LLM response (%.1f%% removed, suspicious unicode: %s)",
|
|
4620
|
+
corruptionRatio * 100,
|
|
4621
|
+
hasSuspiciousUnicode
|
|
4622
|
+
);
|
|
4623
|
+
logger.error(
|
|
4624
|
+
"Raw response preview (first 500 chars): %s",
|
|
4625
|
+
(finalResponse.content || "").substring(0, 500).replace(/\n/g, "\\n")
|
|
4626
|
+
);
|
|
4627
|
+
}
|
|
4615
4628
|
}
|
|
4616
4629
|
state.correctedText = cleanedFinalContent;
|
|
4617
4630
|
state.confidence = 0.8;
|
|
@@ -4633,6 +4646,40 @@ CRITICAL: Your response must contain ONLY the corrected transcript text - absolu
|
|
|
4633
4646
|
return { process };
|
|
4634
4647
|
};
|
|
4635
4648
|
|
|
4649
|
+
z.object({
|
|
4650
|
+
original: z.string().describe("Original text from transcript"),
|
|
4651
|
+
corrected: z.string().describe("Corrected spelling/name"),
|
|
4652
|
+
type: z.enum(["person", "project", "term", "company"]).describe("Entity type"),
|
|
4653
|
+
confidence: z.number().min(0).max(1).describe("Confidence in correction")
|
|
4654
|
+
});
|
|
4655
|
+
z.object({
|
|
4656
|
+
projectId: z.string().optional().describe("Matched project ID"),
|
|
4657
|
+
destination: z.object({
|
|
4658
|
+
path: z.string().describe("File destination path"),
|
|
4659
|
+
structure: z.enum(["none", "year", "month", "day"]).default("month")
|
|
4660
|
+
}),
|
|
4661
|
+
confidence: z.number().min(0).max(1).describe("Confidence in routing"),
|
|
4662
|
+
signals: z.array(z.object({
|
|
4663
|
+
type: z.enum(["explicit_phrase", "associated_person", "associated_company", "topic", "context_type"]),
|
|
4664
|
+
value: z.string(),
|
|
4665
|
+
weight: z.number()
|
|
4666
|
+
})).optional(),
|
|
4667
|
+
reasoning: z.string().optional().describe("Why this destination was chosen")
|
|
4668
|
+
});
|
|
4669
|
+
z.object({
|
|
4670
|
+
people: z.array(z.string()).describe("IDs of people mentioned"),
|
|
4671
|
+
projects: z.array(z.string()).describe("IDs of projects mentioned"),
|
|
4672
|
+
terms: z.array(z.string()).describe("IDs of terms mentioned"),
|
|
4673
|
+
companies: z.array(z.string()).describe("IDs of companies mentioned")
|
|
4674
|
+
});
|
|
4675
|
+
z.object({
|
|
4676
|
+
success: z.boolean(),
|
|
4677
|
+
data: z.any().optional(),
|
|
4678
|
+
error: z.string().optional(),
|
|
4679
|
+
needsUserInput: z.boolean().optional(),
|
|
4680
|
+
userPrompt: z.string().optional()
|
|
4681
|
+
});
|
|
4682
|
+
|
|
4636
4683
|
const create$4 = (reasoning, toolContext) => {
|
|
4637
4684
|
const executor = create$5(reasoning, toolContext);
|
|
4638
4685
|
return {
|
|
@@ -5301,7 +5348,7 @@ const projectAssist = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.definePrope
|
|
|
5301
5348
|
|
|
5302
5349
|
const print$1 = (text) => process.stdout.write(text + "\n");
|
|
5303
5350
|
const parseTranscript = async (filePath) => {
|
|
5304
|
-
const rawText = await fs$
|
|
5351
|
+
const rawText = await fs$2.readFile(filePath, "utf-8");
|
|
5305
5352
|
const lines = rawText.split("\n");
|
|
5306
5353
|
const result = {
|
|
5307
5354
|
filePath,
|
|
@@ -5727,7 +5774,7 @@ const executeAction = async (file, options) => {
|
|
|
5727
5774
|
}
|
|
5728
5775
|
for (const filePath of filePaths) {
|
|
5729
5776
|
try {
|
|
5730
|
-
await fs$
|
|
5777
|
+
await fs$2.access(filePath);
|
|
5731
5778
|
} catch {
|
|
5732
5779
|
print$1(`Error: File not found: ${filePath}`);
|
|
5733
5780
|
process.exit(1);
|
|
@@ -5771,15 +5818,15 @@ Custom title: ${options.title}`);
|
|
|
5771
5818
|
print$1("...");
|
|
5772
5819
|
}
|
|
5773
5820
|
} else {
|
|
5774
|
-
await fs$
|
|
5775
|
-
await fs$
|
|
5821
|
+
await fs$2.mkdir(path.dirname(result.outputPath), { recursive: true });
|
|
5822
|
+
await fs$2.writeFile(result.outputPath, result.content, "utf-8");
|
|
5776
5823
|
print$1(`Combined transcript created: ${result.outputPath}`);
|
|
5777
5824
|
if (options.verbose) {
|
|
5778
5825
|
print$1("\nDeleting source files...");
|
|
5779
5826
|
}
|
|
5780
5827
|
for (const fp of filePaths) {
|
|
5781
5828
|
try {
|
|
5782
|
-
await fs$
|
|
5829
|
+
await fs$2.unlink(fp);
|
|
5783
5830
|
if (options.verbose) {
|
|
5784
5831
|
print$1(` Deleted: ${fp}`);
|
|
5785
5832
|
}
|
|
@@ -5799,7 +5846,7 @@ Custom title: ${options.title}`);
|
|
|
5799
5846
|
process.exit(1);
|
|
5800
5847
|
}
|
|
5801
5848
|
try {
|
|
5802
|
-
await fs$
|
|
5849
|
+
await fs$2.access(file);
|
|
5803
5850
|
} catch {
|
|
5804
5851
|
print$1(`Error: File not found: ${file}`);
|
|
5805
5852
|
process.exit(1);
|
|
@@ -5839,10 +5886,10 @@ Custom title: ${options.title}`);
|
|
|
5839
5886
|
print$1("...");
|
|
5840
5887
|
}
|
|
5841
5888
|
} else {
|
|
5842
|
-
await fs$
|
|
5843
|
-
await fs$
|
|
5889
|
+
await fs$2.mkdir(path.dirname(result.outputPath), { recursive: true });
|
|
5890
|
+
await fs$2.writeFile(result.outputPath, result.content, "utf-8");
|
|
5844
5891
|
if (isRename) {
|
|
5845
|
-
await fs$
|
|
5892
|
+
await fs$2.unlink(file);
|
|
5846
5893
|
print$1(`Transcript updated and renamed:`);
|
|
5847
5894
|
print$1(` From: ${file}`);
|
|
5848
5895
|
print$1(` To: ${result.outputPath}`);
|
|
@@ -6417,11 +6464,11 @@ const applyChanges = async (feedbackCtx) => {
|
|
|
6417
6464
|
moved = true;
|
|
6418
6465
|
}
|
|
6419
6466
|
}
|
|
6420
|
-
await fs$
|
|
6467
|
+
await fs$2.mkdir(path.dirname(newPath), { recursive: true });
|
|
6421
6468
|
if (!feedbackCtx.dryRun) {
|
|
6422
|
-
await fs$
|
|
6469
|
+
await fs$2.writeFile(newPath, feedbackCtx.transcriptContent, "utf-8");
|
|
6423
6470
|
if (newPath !== feedbackCtx.transcriptPath) {
|
|
6424
|
-
await fs$
|
|
6471
|
+
await fs$2.unlink(feedbackCtx.transcriptPath);
|
|
6425
6472
|
}
|
|
6426
6473
|
}
|
|
6427
6474
|
logger.info("Applied %d changes to transcript", feedbackCtx.changes.length);
|
|
@@ -6429,12 +6476,12 @@ const applyChanges = async (feedbackCtx) => {
|
|
|
6429
6476
|
};
|
|
6430
6477
|
const runFeedback = async (transcriptPath, options) => {
|
|
6431
6478
|
try {
|
|
6432
|
-
await fs$
|
|
6479
|
+
await fs$2.access(transcriptPath);
|
|
6433
6480
|
} catch {
|
|
6434
6481
|
print(`Error: File not found: ${transcriptPath}`);
|
|
6435
6482
|
process.exit(1);
|
|
6436
6483
|
}
|
|
6437
|
-
const transcriptContent = await fs$
|
|
6484
|
+
const transcriptContent = await fs$2.readFile(transcriptPath, "utf-8");
|
|
6438
6485
|
const context = await create$u();
|
|
6439
6486
|
const reasoning = create$c({ model: options.model || DEFAULT_MODEL });
|
|
6440
6487
|
const feedbackCtx = {
|
|
@@ -6559,7 +6606,7 @@ const getRawTranscriptPath = (finalPath) => {
|
|
|
6559
6606
|
const readRawTranscript = async (finalPath) => {
|
|
6560
6607
|
const rawPath = getRawTranscriptPath(finalPath);
|
|
6561
6608
|
try {
|
|
6562
|
-
const content = await fs$
|
|
6609
|
+
const content = await fs$2.readFile(rawPath, "utf-8");
|
|
6563
6610
|
return JSON.parse(content);
|
|
6564
6611
|
} catch (error) {
|
|
6565
6612
|
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
@@ -6570,7 +6617,7 @@ const readRawTranscript = async (finalPath) => {
|
|
|
6570
6617
|
};
|
|
6571
6618
|
const readFinalTranscript = async (finalPath) => {
|
|
6572
6619
|
try {
|
|
6573
|
-
return await fs$
|
|
6620
|
+
return await fs$2.readFile(finalPath, "utf-8");
|
|
6574
6621
|
} catch (error) {
|
|
6575
6622
|
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
6576
6623
|
return null;
|
|
@@ -6729,7 +6776,7 @@ const listTranscripts = async (options) => {
|
|
|
6729
6776
|
if (endDate && dateTime && dateTime.date > endDate) continue;
|
|
6730
6777
|
let stats;
|
|
6731
6778
|
try {
|
|
6732
|
-
stats = await fs$
|
|
6779
|
+
stats = await fs$2.stat(filePath);
|
|
6733
6780
|
if (!stats.isFile()) {
|
|
6734
6781
|
continue;
|
|
6735
6782
|
}
|
|
@@ -6738,7 +6785,7 @@ const listTranscripts = async (options) => {
|
|
|
6738
6785
|
}
|
|
6739
6786
|
let content;
|
|
6740
6787
|
try {
|
|
6741
|
-
content = await fs$
|
|
6788
|
+
content = await fs$2.readFile(filePath, "utf-8");
|
|
6742
6789
|
} catch {
|
|
6743
6790
|
continue;
|
|
6744
6791
|
}
|