@redaksjon/protokoll 1.0.29 → 1.0.30-dev.20260317191035.81f637e
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/engineLogging.js +156 -58
- package/dist/engineLogging.js.map +1 -1
- package/dist/mcp/server-hono.js +11 -30
- package/dist/mcp/server-hono.js.map +1 -1
- package/package.json +1 -1
package/dist/engineLogging.js
CHANGED
|
@@ -208,7 +208,7 @@ function isProtokolUri(uri) {
|
|
|
208
208
|
return uri.startsWith(`${SCHEME}://`);
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
const VERSION = "1.0.
|
|
211
|
+
const VERSION = "1.0.30-dev.20260317191035.81f637e (working/81f637e 2026-03-17 12:10:15 -0700) linux arm64 v24.14.0";
|
|
212
212
|
const PROGRAM_NAME = "protokoll";
|
|
213
213
|
const DATE_FORMAT_YEAR_MONTH_DAY_HOURS_MINUTES_SECONDS = "YYYY-M-D-HHmmss";
|
|
214
214
|
const DEFAULT_AUDIO_EXTENSIONS = ["mp3", "mp4", "mpeg", "mpga", "m4a", "wav", "webm", "qta"];
|
|
@@ -4470,6 +4470,131 @@ async function getContextInstance(contextDirectory) {
|
|
|
4470
4470
|
}
|
|
4471
4471
|
return createToolContext(contextDirectory);
|
|
4472
4472
|
}
|
|
4473
|
+
function normalizeProjectId(value) {
|
|
4474
|
+
return typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
4475
|
+
}
|
|
4476
|
+
function createAllowedProjectSet(allowedProjectIds) {
|
|
4477
|
+
return new Set(
|
|
4478
|
+
(allowedProjectIds || []).map((projectId) => normalizeProjectId(projectId)).filter((projectId) => projectId.length > 0)
|
|
4479
|
+
);
|
|
4480
|
+
}
|
|
4481
|
+
function isProjectInScope(projectId, allowedProjectIds) {
|
|
4482
|
+
const normalized = normalizeProjectId(projectId);
|
|
4483
|
+
return normalized.length > 0 && allowedProjectIds.has(normalized);
|
|
4484
|
+
}
|
|
4485
|
+
function hasScopedProjectReference(projectIds, allowedProjectIds) {
|
|
4486
|
+
return (projectIds || []).some((projectId) => isProjectInScope(projectId, allowedProjectIds));
|
|
4487
|
+
}
|
|
4488
|
+
async function loadProjects(context) {
|
|
4489
|
+
const projects = context.getAllProjects();
|
|
4490
|
+
if (projects.length > 0) {
|
|
4491
|
+
return projects;
|
|
4492
|
+
}
|
|
4493
|
+
const gcsProjects = await listContextEntitiesFromGcs("project");
|
|
4494
|
+
return gcsProjects.map((project) => ({
|
|
4495
|
+
id: String(project.id || ""),
|
|
4496
|
+
name: String(project.name || ""),
|
|
4497
|
+
type: "project",
|
|
4498
|
+
active: project.active !== false,
|
|
4499
|
+
routing: typeof project.routing === "object" && project.routing !== null ? project.routing : void 0,
|
|
4500
|
+
classification: typeof project.classification === "object" && project.classification !== null ? project.classification : void 0
|
|
4501
|
+
})).filter((project) => project.id.length > 0 && project.name.length > 0).map((project) => ({
|
|
4502
|
+
...project,
|
|
4503
|
+
routing: {
|
|
4504
|
+
destination: project.routing?.destination,
|
|
4505
|
+
structure: project.routing?.structure
|
|
4506
|
+
},
|
|
4507
|
+
classification: {
|
|
4508
|
+
context_type: project.classification?.context_type,
|
|
4509
|
+
explicit_phrases: project.classification?.explicit_phrases,
|
|
4510
|
+
associated_people: project.classification?.associated_people,
|
|
4511
|
+
associated_companies: project.classification?.associated_companies
|
|
4512
|
+
}
|
|
4513
|
+
}));
|
|
4514
|
+
}
|
|
4515
|
+
async function loadPeople(context) {
|
|
4516
|
+
const people = context.getAllPeople();
|
|
4517
|
+
if (people.length > 0) {
|
|
4518
|
+
return people;
|
|
4519
|
+
}
|
|
4520
|
+
const gcsPeople = await listContextEntitiesFromGcs("person");
|
|
4521
|
+
return gcsPeople.map((person) => ({
|
|
4522
|
+
id: String(person.id || ""),
|
|
4523
|
+
name: String(person.name || ""),
|
|
4524
|
+
type: "person",
|
|
4525
|
+
company: typeof person.company === "string" ? person.company : void 0,
|
|
4526
|
+
role: typeof person.role === "string" ? person.role : void 0,
|
|
4527
|
+
sounds_like: Array.isArray(person.sounds_like) ? person.sounds_like : void 0
|
|
4528
|
+
})).filter((person) => person.id.length > 0 && person.name.length > 0);
|
|
4529
|
+
}
|
|
4530
|
+
async function loadTerms(context) {
|
|
4531
|
+
const terms = context.getAllTerms();
|
|
4532
|
+
if (terms.length > 0) {
|
|
4533
|
+
return terms;
|
|
4534
|
+
}
|
|
4535
|
+
const gcsTerms = await listContextEntitiesFromGcs("term");
|
|
4536
|
+
return gcsTerms.map((term) => ({
|
|
4537
|
+
id: String(term.id || ""),
|
|
4538
|
+
name: String(term.name || ""),
|
|
4539
|
+
type: "term",
|
|
4540
|
+
expansion: typeof term.expansion === "string" ? term.expansion : void 0,
|
|
4541
|
+
domain: typeof term.domain === "string" ? term.domain : void 0,
|
|
4542
|
+
sounds_like: Array.isArray(term.sounds_like) ? term.sounds_like : void 0,
|
|
4543
|
+
projects: Array.isArray(term.projects) ? term.projects.filter((value) => typeof value === "string") : void 0
|
|
4544
|
+
})).filter((term) => term.id.length > 0 && term.name.length > 0);
|
|
4545
|
+
}
|
|
4546
|
+
async function loadCompanies(context) {
|
|
4547
|
+
const companies = context.getAllCompanies();
|
|
4548
|
+
if (companies.length > 0) {
|
|
4549
|
+
return companies;
|
|
4550
|
+
}
|
|
4551
|
+
const gcsCompanies = await listContextEntitiesFromGcs("company");
|
|
4552
|
+
return gcsCompanies.map((company) => ({
|
|
4553
|
+
id: String(company.id || ""),
|
|
4554
|
+
name: String(company.name || ""),
|
|
4555
|
+
type: "company",
|
|
4556
|
+
fullName: typeof company.fullName === "string" ? company.fullName : void 0,
|
|
4557
|
+
industry: typeof company.industry === "string" ? company.industry : void 0,
|
|
4558
|
+
sounds_like: Array.isArray(company.sounds_like) ? company.sounds_like : void 0
|
|
4559
|
+
})).filter((company) => company.id.length > 0 && company.name.length > 0);
|
|
4560
|
+
}
|
|
4561
|
+
async function buildProjectScopeState(context, allowedProjectIds) {
|
|
4562
|
+
const allowedProjectSet = createAllowedProjectSet(allowedProjectIds);
|
|
4563
|
+
if (allowedProjectSet.size === 0) {
|
|
4564
|
+
return null;
|
|
4565
|
+
}
|
|
4566
|
+
const projects = (await loadProjects(context)).filter((project) => isProjectInScope(project.id, allowedProjectSet));
|
|
4567
|
+
const associatedPeople = /* @__PURE__ */ new Set();
|
|
4568
|
+
const associatedCompanies = /* @__PURE__ */ new Set();
|
|
4569
|
+
for (const project of projects) {
|
|
4570
|
+
for (const personId of project.classification?.associated_people || []) {
|
|
4571
|
+
associatedPeople.add(personId);
|
|
4572
|
+
}
|
|
4573
|
+
for (const companyId of project.classification?.associated_companies || []) {
|
|
4574
|
+
associatedCompanies.add(companyId);
|
|
4575
|
+
}
|
|
4576
|
+
}
|
|
4577
|
+
return {
|
|
4578
|
+
allowedProjectIds: allowedProjectSet,
|
|
4579
|
+
projects,
|
|
4580
|
+
associatedPeople,
|
|
4581
|
+
associatedCompanies
|
|
4582
|
+
};
|
|
4583
|
+
}
|
|
4584
|
+
function isEntityVisibleInProjectScope(entity, scope) {
|
|
4585
|
+
switch (entity.type) {
|
|
4586
|
+
case "project":
|
|
4587
|
+
return isProjectInScope(entity.id, scope.allowedProjectIds);
|
|
4588
|
+
case "person":
|
|
4589
|
+
return scope.associatedPeople.has(entity.id);
|
|
4590
|
+
case "company":
|
|
4591
|
+
return scope.associatedCompanies.has(entity.id);
|
|
4592
|
+
case "term":
|
|
4593
|
+
return hasScopedProjectReference(entity.projects, scope.allowedProjectIds);
|
|
4594
|
+
default:
|
|
4595
|
+
return false;
|
|
4596
|
+
}
|
|
4597
|
+
}
|
|
4473
4598
|
const contextStatusTool = {
|
|
4474
4599
|
name: "protokoll_context_status",
|
|
4475
4600
|
description: "Get the status of the Protokoll context system. Shows discovered .protokoll directories, entity counts, and configuration status. Use this to understand what context is available for transcription enhancement.",
|
|
@@ -4672,8 +4797,13 @@ const predictEntitiesTool = {
|
|
|
4672
4797
|
};
|
|
4673
4798
|
async function handleContextStatus(args) {
|
|
4674
4799
|
const context = await getContextInstance(args.contextDirectory);
|
|
4800
|
+
const scope = await buildProjectScopeState(context, args.allowedProjectIds);
|
|
4675
4801
|
const dirs = context.getDiscoveredDirs();
|
|
4676
4802
|
const config = context.getConfig();
|
|
4803
|
+
const projects = scope?.projects ?? await loadProjects(context);
|
|
4804
|
+
const people = scope ? (await loadPeople(context)).filter((person) => scope.associatedPeople.has(person.id)) : await loadPeople(context);
|
|
4805
|
+
const terms = scope ? (await loadTerms(context)).filter((term) => hasScopedProjectReference(term.projects, scope.allowedProjectIds)) : await loadTerms(context);
|
|
4806
|
+
const companies = scope ? (await loadCompanies(context)).filter((company) => scope.associatedCompanies.has(company.id)) : await loadCompanies(context);
|
|
4677
4807
|
return {
|
|
4678
4808
|
hasContext: context.hasContext(),
|
|
4679
4809
|
discoveredDirectories: dirs.map((d) => ({
|
|
@@ -4682,11 +4812,11 @@ async function handleContextStatus(args) {
|
|
|
4682
4812
|
isPrimary: d.level === 0
|
|
4683
4813
|
})),
|
|
4684
4814
|
entityCounts: {
|
|
4685
|
-
projects:
|
|
4686
|
-
people:
|
|
4687
|
-
terms:
|
|
4688
|
-
companies:
|
|
4689
|
-
ignored: context.getAllIgnored().length
|
|
4815
|
+
projects: projects.length,
|
|
4816
|
+
people: people.length,
|
|
4817
|
+
terms: terms.length,
|
|
4818
|
+
companies: companies.length,
|
|
4819
|
+
ignored: scope ? 0 : context.getAllIgnored().length
|
|
4690
4820
|
},
|
|
4691
4821
|
config: {
|
|
4692
4822
|
outputDirectory: config.outputDirectory,
|
|
@@ -4697,27 +4827,8 @@ async function handleContextStatus(args) {
|
|
|
4697
4827
|
}
|
|
4698
4828
|
async function handleListProjects(args) {
|
|
4699
4829
|
const context = await getContextInstance(args.contextDirectory);
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
const gcsProjects = await listContextEntitiesFromGcs("project");
|
|
4703
|
-
projects = gcsProjects.map((project) => ({
|
|
4704
|
-
id: String(project.id || ""),
|
|
4705
|
-
name: String(project.name || ""),
|
|
4706
|
-
active: project.active !== false,
|
|
4707
|
-
routing: typeof project.routing === "object" && project.routing !== null ? project.routing : void 0,
|
|
4708
|
-
classification: typeof project.classification === "object" && project.classification !== null ? project.classification : void 0
|
|
4709
|
-
})).filter((project) => project.id.length > 0 && project.name.length > 0).map((project) => ({
|
|
4710
|
-
...project,
|
|
4711
|
-
routing: {
|
|
4712
|
-
destination: project.routing?.destination,
|
|
4713
|
-
structure: project.routing?.structure
|
|
4714
|
-
},
|
|
4715
|
-
classification: {
|
|
4716
|
-
context_type: project.classification?.context_type,
|
|
4717
|
-
explicit_phrases: project.classification?.explicit_phrases
|
|
4718
|
-
}
|
|
4719
|
-
}));
|
|
4720
|
-
}
|
|
4830
|
+
const scope = await buildProjectScopeState(context, args.allowedProjectIds);
|
|
4831
|
+
let projects = scope?.projects ?? await loadProjects(context);
|
|
4721
4832
|
if (!args.includeInactive) {
|
|
4722
4833
|
projects = projects.filter((p) => p.active !== false);
|
|
4723
4834
|
}
|
|
@@ -4749,16 +4860,10 @@ async function handleListProjects(args) {
|
|
|
4749
4860
|
}
|
|
4750
4861
|
async function handleListPeople(args) {
|
|
4751
4862
|
const context = await getContextInstance(args.contextDirectory);
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
people =
|
|
4756
|
-
id: String(person.id || ""),
|
|
4757
|
-
name: String(person.name || ""),
|
|
4758
|
-
company: typeof person.company === "string" ? person.company : void 0,
|
|
4759
|
-
role: typeof person.role === "string" ? person.role : void 0,
|
|
4760
|
-
sounds_like: Array.isArray(person.sounds_like) ? person.sounds_like : void 0
|
|
4761
|
-
})).filter((person) => person.id.length > 0 && person.name.length > 0);
|
|
4863
|
+
const scope = await buildProjectScopeState(context, args.allowedProjectIds);
|
|
4864
|
+
let people = await loadPeople(context);
|
|
4865
|
+
if (scope) {
|
|
4866
|
+
people = people.filter((person) => scope.associatedPeople.has(person.id));
|
|
4762
4867
|
}
|
|
4763
4868
|
if (args.search) {
|
|
4764
4869
|
const searchLower = args.search.toLowerCase();
|
|
@@ -4786,16 +4891,10 @@ async function handleListPeople(args) {
|
|
|
4786
4891
|
}
|
|
4787
4892
|
async function handleListTerms(args) {
|
|
4788
4893
|
const context = await getContextInstance(args.contextDirectory);
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
|
|
4792
|
-
terms =
|
|
4793
|
-
id: String(term.id || ""),
|
|
4794
|
-
name: String(term.name || ""),
|
|
4795
|
-
expansion: typeof term.expansion === "string" ? term.expansion : void 0,
|
|
4796
|
-
domain: typeof term.domain === "string" ? term.domain : void 0,
|
|
4797
|
-
sounds_like: Array.isArray(term.sounds_like) ? term.sounds_like : void 0
|
|
4798
|
-
})).filter((term) => term.id.length > 0 && term.name.length > 0);
|
|
4894
|
+
const scope = await buildProjectScopeState(context, args.allowedProjectIds);
|
|
4895
|
+
let terms = await loadTerms(context);
|
|
4896
|
+
if (scope) {
|
|
4897
|
+
terms = terms.filter((term) => hasScopedProjectReference(term.projects, scope.allowedProjectIds));
|
|
4799
4898
|
}
|
|
4800
4899
|
if (args.search) {
|
|
4801
4900
|
const searchLower = args.search.toLowerCase();
|
|
@@ -4823,16 +4922,10 @@ async function handleListTerms(args) {
|
|
|
4823
4922
|
}
|
|
4824
4923
|
async function handleListCompanies(args) {
|
|
4825
4924
|
const context = await getContextInstance(args.contextDirectory);
|
|
4826
|
-
|
|
4827
|
-
|
|
4828
|
-
|
|
4829
|
-
companies =
|
|
4830
|
-
id: String(company.id || ""),
|
|
4831
|
-
name: String(company.name || ""),
|
|
4832
|
-
fullName: typeof company.fullName === "string" ? company.fullName : void 0,
|
|
4833
|
-
industry: typeof company.industry === "string" ? company.industry : void 0,
|
|
4834
|
-
sounds_like: Array.isArray(company.sounds_like) ? company.sounds_like : void 0
|
|
4835
|
-
})).filter((company) => company.id.length > 0 && company.name.length > 0);
|
|
4925
|
+
const scope = await buildProjectScopeState(context, args.allowedProjectIds);
|
|
4926
|
+
let companies = await loadCompanies(context);
|
|
4927
|
+
if (scope) {
|
|
4928
|
+
companies = companies.filter((company) => scope.associatedCompanies.has(company.id));
|
|
4836
4929
|
}
|
|
4837
4930
|
if (args.search) {
|
|
4838
4931
|
const searchLower = args.search.toLowerCase();
|
|
@@ -4860,7 +4953,8 @@ async function handleListCompanies(args) {
|
|
|
4860
4953
|
}
|
|
4861
4954
|
async function handleSearchContext(args) {
|
|
4862
4955
|
const context = await getContextInstance(args.contextDirectory);
|
|
4863
|
-
const
|
|
4956
|
+
const scope = await buildProjectScopeState(context, args.allowedProjectIds);
|
|
4957
|
+
const results = scope ? context.search(args.query).filter((entity) => isEntityVisibleInProjectScope(entity, scope)) : context.search(args.query);
|
|
4864
4958
|
const total = results.length;
|
|
4865
4959
|
const limit = args.limit ?? 50;
|
|
4866
4960
|
const offset = args.offset ?? 0;
|
|
@@ -4876,6 +4970,7 @@ async function handleSearchContext(args) {
|
|
|
4876
4970
|
}
|
|
4877
4971
|
async function handleGetEntity(args) {
|
|
4878
4972
|
const context = await getContextInstance(args.contextDirectory);
|
|
4973
|
+
const scope = await buildProjectScopeState(context, args.allowedProjectIds);
|
|
4879
4974
|
let entity;
|
|
4880
4975
|
switch (args.entityType) {
|
|
4881
4976
|
case "project":
|
|
@@ -4896,6 +4991,9 @@ async function handleGetEntity(args) {
|
|
|
4896
4991
|
default:
|
|
4897
4992
|
throw new Error(`Unknown entity type: ${args.entityType}`);
|
|
4898
4993
|
}
|
|
4994
|
+
if (scope && !isEntityVisibleInProjectScope(entity, scope)) {
|
|
4995
|
+
throw new Error(`Project-scoped key cannot access ${args.entityType} "${args.entityId}".`);
|
|
4996
|
+
}
|
|
4899
4997
|
const filePath = context.getEntityFilePath(entity);
|
|
4900
4998
|
return {
|
|
4901
4999
|
...formatEntity(entity),
|