@weftlet/toolkit 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/LICENSE +176 -0
  2. package/NOTICE +6 -0
  3. package/README.md +155 -2
  4. package/THIRD_PARTY_NOTICES.md +610 -0
  5. package/dist/application/agent-context.d.ts +23 -0
  6. package/dist/application/agent-context.js +94 -0
  7. package/dist/application/application.d.ts +23 -0
  8. package/dist/application/application.js +91 -0
  9. package/dist/application/hydrator.d.ts +49 -0
  10. package/dist/application/hydrator.js +275 -0
  11. package/dist/application/overlay.d.ts +6 -0
  12. package/dist/application/overlay.js +110 -0
  13. package/dist/application/saved-evidence.d.ts +38 -0
  14. package/dist/application/saved-evidence.js +59 -0
  15. package/dist/application/snapshot-checks.d.ts +16 -0
  16. package/dist/application/snapshot-checks.js +51 -0
  17. package/dist/cli.d.ts +3 -0
  18. package/dist/cli.js +4 -0
  19. package/dist/configuration/cache.d.ts +2 -0
  20. package/dist/configuration/cache.js +10 -0
  21. package/dist/configuration/config.d.ts +79 -0
  22. package/dist/configuration/config.js +165 -0
  23. package/dist/core.d.ts +1 -0
  24. package/dist/core.js +2 -0
  25. package/dist/extraction/codex-auth.d.ts +12 -0
  26. package/dist/extraction/codex-auth.js +74 -0
  27. package/dist/extraction/document.d.ts +5 -0
  28. package/dist/extraction/document.js +54 -0
  29. package/dist/extraction/ontology.d.ts +32 -0
  30. package/dist/extraction/ontology.js +164 -0
  31. package/dist/extraction/providers.d.ts +8 -0
  32. package/dist/extraction/providers.js +58 -0
  33. package/dist/extraction/runtime-evidence.d.ts +2 -0
  34. package/dist/extraction/runtime-evidence.js +84 -0
  35. package/dist/extraction/semantic-citations.d.ts +7 -0
  36. package/dist/extraction/semantic-citations.js +27 -0
  37. package/dist/extraction/semantic-process.d.ts +11 -0
  38. package/dist/extraction/semantic-process.js +68 -0
  39. package/dist/extraction/semantic.d.ts +73 -0
  40. package/dist/extraction/semantic.js +414 -0
  41. package/dist/extraction/static.d.ts +52 -0
  42. package/dist/extraction/static.js +322 -0
  43. package/dist/extraction/telemetry.d.ts +19 -0
  44. package/dist/extraction/telemetry.js +259 -0
  45. package/dist/governance/governance.d.ts +60 -0
  46. package/dist/governance/governance.js +209 -0
  47. package/dist/graph/authority.d.ts +2 -0
  48. package/dist/graph/authority.js +13 -0
  49. package/dist/graph/diagnostics.d.ts +5 -0
  50. package/dist/graph/diagnostics.js +61 -0
  51. package/dist/graph/query.d.ts +16 -0
  52. package/dist/graph/query.js +373 -0
  53. package/dist/graph/rdf.d.ts +26 -0
  54. package/dist/graph/rdf.js +144 -0
  55. package/dist/index.d.ts +11 -0
  56. package/dist/index.js +12 -0
  57. package/dist/infrastructure/module-resolution.d.ts +2 -0
  58. package/dist/infrastructure/module-resolution.js +10 -0
  59. package/dist/infrastructure/process.d.ts +5 -0
  60. package/dist/infrastructure/process.js +27 -0
  61. package/dist/infrastructure/util.d.ts +1 -0
  62. package/dist/infrastructure/util.js +2 -0
  63. package/dist/interfaces/cli.d.ts +4 -0
  64. package/dist/interfaces/cli.js +197 -0
  65. package/dist/interfaces/doctor.d.ts +25 -0
  66. package/dist/interfaces/doctor.js +49 -0
  67. package/dist/interfaces/init.d.ts +24 -0
  68. package/dist/interfaces/init.js +154 -0
  69. package/dist/interfaces/mcp-facade.d.ts +3 -0
  70. package/dist/interfaces/mcp-facade.js +4 -0
  71. package/dist/interfaces/mcp.d.ts +2 -0
  72. package/dist/interfaces/mcp.js +81 -0
  73. package/dist/interfaces/request.d.ts +2 -0
  74. package/dist/interfaces/request.js +59 -0
  75. package/dist/mcp.d.ts +3 -0
  76. package/dist/mcp.js +4 -0
  77. package/dist/repository/committed-tree.d.ts +2 -0
  78. package/dist/repository/committed-tree.js +35 -0
  79. package/dist/repository/git.d.ts +26 -0
  80. package/dist/repository/git.js +163 -0
  81. package/dist/repository/glob.d.ts +2 -0
  82. package/dist/repository/glob.js +46 -0
  83. package/dist/repository/working-content.d.ts +3 -0
  84. package/dist/repository/working-content.js +34 -0
  85. package/dist/storage/atomic-rename.d.ts +2 -0
  86. package/dist/storage/atomic-rename.js +22 -0
  87. package/dist/storage/storage.d.ts +15 -0
  88. package/dist/storage/storage.js +115 -0
  89. package/dist/telemetry.d.ts +1 -0
  90. package/dist/telemetry.js +2 -0
  91. package/dist/visualization/viewer-interaction.d.ts +12 -0
  92. package/dist/visualization/viewer-interaction.js +123 -0
  93. package/dist/visualization/visualization.d.ts +26 -0
  94. package/dist/visualization/visualization.js +491 -0
  95. package/docs/ADR-001-standalone-baseline.md +16 -0
  96. package/docs/ADR-002-saved-evidence.md +21 -0
  97. package/docs/ADR-003-draft-overlays.md +23 -0
  98. package/docs/ADR-004-rdf-query-path.md +37 -0
  99. package/docs/ADR-005-governance-and-optional-oml.md +37 -0
  100. package/docs/ADR-006-provider-boundaries.md +15 -0
  101. package/docs/ADR-007-toolkit-modules.md +53 -0
  102. package/docs/ADR-008-weftlet-packages.md +32 -0
  103. package/docs/CLOUD-ENVIRONMENT.md +56 -0
  104. package/docs/ENVIRONMENT-VALIDATION.md +78 -0
  105. package/docs/MIGRATING-TO-WEFTLET.md +54 -0
  106. package/docs/PROVIDERS.md +121 -0
  107. package/docs/RELEASING.md +144 -0
  108. package/docs/ROADMAP.md +53 -0
  109. package/docs/SOURCE-INVENTORY.md +48 -0
  110. package/docs/VALIDATION.md +490 -0
  111. package/docs/VIEWER.md +36 -0
  112. package/docs/architecture-baseline.json +57 -0
  113. package/docs/architecture-policy.md +41 -0
  114. package/docs/extraction-manifest.json +721 -0
  115. package/docs/licenses/REVIEW.md +16 -0
  116. package/docs/licenses/lru-cache-11.5.3-BlueOak.md +55 -0
  117. package/docs/licenses/negotiate-1.0.1-BSD.txt +22 -0
  118. package/docs/licenses/spark-md5-3.0.2-MIT.txt +7 -0
  119. package/examples/generic-typescript/context-graph.config.json +47 -0
  120. package/examples/generic-typescript/context-graph.oml.config.json +49 -0
  121. package/examples/generic-typescript/docs/search-capability.md +14 -0
  122. package/examples/generic-typescript/ontology/build.gradle +38 -0
  123. package/examples/generic-typescript/ontology/catalog.xml +5 -0
  124. package/examples/generic-typescript/ontology/settings.gradle +1 -0
  125. package/examples/generic-typescript/ontology/src/oml/context-graph.dev/core.oml +99 -0
  126. package/examples/generic-typescript/package.json +6 -0
  127. package/examples/generic-typescript/src/search.ts +11 -0
  128. package/examples/generic-typescript/test/search.test.ts +8 -0
  129. package/examples/generic-typescript/tsconfig.json +10 -0
  130. package/examples/pipeline/context-graph.config.json +49 -0
  131. package/examples/pipeline/docs/admission.md +6 -0
  132. package/examples/pipeline/docs/analysis.md +6 -0
  133. package/examples/pipeline/docs/discovery.md +6 -0
  134. package/examples/pipeline/docs/execution.md +6 -0
  135. package/examples/pipeline/docs/outcomes.md +6 -0
  136. package/examples/pipeline/docs/planning.md +6 -0
  137. package/examples/pipeline/package.json +6 -0
  138. package/examples/pipeline/src/admission.ts +9 -0
  139. package/examples/pipeline/src/analysis.ts +9 -0
  140. package/examples/pipeline/src/contracts/admission.ts +1 -0
  141. package/examples/pipeline/src/contracts/analysis.ts +1 -0
  142. package/examples/pipeline/src/contracts/discovery.ts +1 -0
  143. package/examples/pipeline/src/contracts/execution.ts +1 -0
  144. package/examples/pipeline/src/contracts/outcomes.ts +1 -0
  145. package/examples/pipeline/src/contracts/planning.ts +1 -0
  146. package/examples/pipeline/src/discovery.ts +9 -0
  147. package/examples/pipeline/src/execution.ts +9 -0
  148. package/examples/pipeline/src/outcomes.ts +9 -0
  149. package/examples/pipeline/src/planning.ts +9 -0
  150. package/examples/pipeline/src/queue.ts +12 -0
  151. package/examples/pipeline/test/pipeline.test.ts +17 -0
  152. package/examples/pipeline/tsconfig.json +12 -0
  153. package/package.json +116 -3
  154. package/runtime-check.d.mts +2 -0
  155. package/runtime-check.mjs +12 -0
  156. package/templates/context-graph-development/SKILL.md +37 -0
  157. package/third-party-tools.json +34 -0
@@ -0,0 +1,54 @@
1
+ import { sha256, stableJson } from "../infrastructure/util.js";
2
+ const identity = { id: 'document-linker', version: '1.0.0' };
3
+ const repositoryPathPattern = /\b[A-Za-z0-9_.-]+(?:\/[A-Za-z0-9_.-]+)+/g;
4
+ function documentNode(path) {
5
+ return { id: `document:${path}`, kind: 'Document', label: path };
6
+ }
7
+ export function linkSemanticDocuments(context, hydrated, trackedPaths = []) {
8
+ const facts = [];
9
+ const makeFact = (source, subject, predicate, object) => ({
10
+ id: sha256(stableJson({ source: source.path, subject: subject.id, predicate, object: object.id })),
11
+ subject,
12
+ predicate,
13
+ object,
14
+ provenance: {
15
+ path: source.path,
16
+ startLine: 1,
17
+ endLine: Math.max(1, source.content.split('\n').length),
18
+ digest: source.digest,
19
+ commitSha: context.commitSha,
20
+ },
21
+ extractor: identity,
22
+ confidence: 1,
23
+ authority: 'inferred',
24
+ extractionReview: predicate === 'contains' ? 'unreviewed' : 'deterministic',
25
+ snapshotId: context.snapshotId,
26
+ });
27
+ for (const { source, artifact } of hydrated) {
28
+ const owner = documentNode(source.path);
29
+ const nodes = new Map(artifact.facts.flatMap((fact) => [fact.subject, fact.object]).map((node) => [node.id, node]));
30
+ for (const node of nodes.values())
31
+ facts.push(makeFact(source, owner, 'contains', node));
32
+ const references = [
33
+ ...new Set((source.content.match(repositoryPathPattern) ?? []).map((path) => path.replace(/[.,;:]+$/, ''))),
34
+ ].sort();
35
+ const resolvedReferences = new Set();
36
+ for (const path of references) {
37
+ if (trackedPaths.includes(path) || /\.(?:md|mdx|txt)$/i.test(path)) {
38
+ resolvedReferences.add(path);
39
+ continue;
40
+ }
41
+ for (const trackedPath of trackedPaths) {
42
+ if (trackedPath.startsWith(`${path}/`))
43
+ resolvedReferences.add(trackedPath);
44
+ }
45
+ }
46
+ for (const path of [...resolvedReferences].sort()) {
47
+ const target = /\.(?:md|mdx|txt)$/i.test(path)
48
+ ? documentNode(path)
49
+ : { id: `component:file:${path}`, kind: 'Component', label: path };
50
+ facts.push(makeFact(source, owner, 'references', target));
51
+ }
52
+ }
53
+ return facts;
54
+ }
@@ -0,0 +1,32 @@
1
+ import type { ContextGraphConfig } from "../configuration/config.js";
2
+ import type { SemanticArtifact, ExtractionContext } from "@weftlet/core";
3
+ import type { GitRepository } from "../repository/git.js";
4
+ export interface OntologyCompileResult {
5
+ readonly root: string;
6
+ readonly rdfFiles: readonly string[];
7
+ readonly digest: string;
8
+ }
9
+ export interface OntologyCompiler {
10
+ checkReady?(): Promise<void>;
11
+ compile(snapshotId: string, artifacts: readonly SemanticArtifact[], context?: ExtractionContext): Promise<OntologyCompileResult>;
12
+ }
13
+ type DockerProbe = (cwd: string) => Promise<string>;
14
+ export declare function requireLinuxDocker(cwd: string, probe?: DockerProbe): Promise<void>;
15
+ export declare function dockerHostUserArguments(): readonly string[];
16
+ export declare function compileOntologyAtExactCheckout(repository: GitRepository, compiler: OntologyCompiler, ref: string): Promise<OntologyCompileResult>;
17
+ export declare function renderGeneratedOntologyRoot(artifacts: readonly SemanticArtifact[], usedVocabularyIris?: readonly string[], includedDescriptionIris?: readonly string[]): string;
18
+ export declare class OpenCaesarOntologyCompiler implements OntologyCompiler {
19
+ private readonly config;
20
+ private readonly repositoryRoot;
21
+ private readonly storageRoot;
22
+ constructor(config: ContextGraphConfig['ontology'], repositoryRoot: string, storageRoot: string);
23
+ checkReady(): Promise<void>;
24
+ compile(snapshotId: string, artifacts: readonly SemanticArtifact[], context?: ExtractionContext): Promise<OntologyCompileResult>;
25
+ }
26
+ /** Default compiler preserves asserted semantics without Java, Docker, or an OWL reasoner. */
27
+ export declare class DirectRdfOntologyCompiler implements OntologyCompiler {
28
+ private readonly storageRoot;
29
+ constructor(storageRoot: string);
30
+ compile(snapshotId: string, artifacts: readonly SemanticArtifact[]): Promise<OntologyCompileResult>;
31
+ }
32
+ export {};
@@ -0,0 +1,164 @@
1
+ // Modified for standalone extraction; see docs/extraction-manifest.json.
2
+ import { randomUUID } from 'node:crypto';
3
+ import { withCommittedTree } from "../repository/committed-tree.js";
4
+ import { DataFactory, Store, Writer } from 'n3';
5
+ import { CG, nodeIri } from "../graph/rdf.js";
6
+ import { cp, mkdir, readdir, readFile, rm, writeFile } from 'node:fs/promises';
7
+ import { execFile } from 'node:child_process';
8
+ import { promisify } from 'node:util';
9
+ import { dirname, join, relative, resolve, sep } from 'node:path';
10
+ import { runProcess } from "../infrastructure/process.js";
11
+ import { sha256, stableJson } from "../infrastructure/util.js";
12
+ const probeDocker = async (cwd) => {
13
+ const { stdout } = await promisify(execFile)('docker', ['info', '--format', '{{.OSType}}'], {
14
+ cwd,
15
+ encoding: 'utf8',
16
+ timeout: 10_000,
17
+ maxBuffer: 64 * 1024,
18
+ windowsHide: true,
19
+ });
20
+ return stdout;
21
+ };
22
+ export async function requireLinuxDocker(cwd, probe = probeDocker) {
23
+ try {
24
+ if ((await probe(cwd)).trim() !== 'linux')
25
+ throw new Error('Linux engine required');
26
+ }
27
+ catch (cause) {
28
+ throw new Error('Context graph Docker preflight failed: a responsive Linux Docker engine is required for openCAESAR. Start Docker Desktop (Linux containers) or repair the selected Docker context, then retry.', { cause });
29
+ }
30
+ }
31
+ export function dockerHostUserArguments() {
32
+ if (process.platform === 'win32' || !process.getuid || !process.getgid)
33
+ return [];
34
+ return [
35
+ '--user',
36
+ `${process.getuid()}:${process.getgid()}`,
37
+ '--env',
38
+ 'GRADLE_USER_HOME=/workspace/.gradle',
39
+ ];
40
+ }
41
+ export async function compileOntologyAtExactCheckout(repository, compiler, ref) {
42
+ const commitSha = await repository.resolveRef(ref);
43
+ await repository.requireExactCleanCommit(commitSha);
44
+ return compiler.compile(commitSha, []);
45
+ }
46
+ export function renderGeneratedOntologyRoot(artifacts, usedVocabularyIris = [], includedDescriptionIris = []) {
47
+ const generatedImports = artifacts
48
+ .filter((artifact) => artifact.oml.trim())
49
+ .sort((left, right) => left.key.localeCompare(right.key))
50
+ .map((artifact) => ` includes <https://context-graph.dev/generated/${artifact.key}#>`);
51
+ const vocabularyImports = ['https://context-graph.dev/core#', ...usedVocabularyIris]
52
+ .filter((iri, index, values) => values.indexOf(iri) === index)
53
+ .map((iri) => ` uses <${iri}>`);
54
+ const staticImports = [...includedDescriptionIris].sort().map((iri) => ` includes <${iri}>`);
55
+ return [
56
+ 'description bundle <https://context-graph.dev/generated/snapshot#> as snapshot {',
57
+ ...vocabularyImports,
58
+ ...staticImports,
59
+ ...generatedImports,
60
+ '}',
61
+ ].join('\n');
62
+ }
63
+ async function listRdfFiles(root) {
64
+ const files = [];
65
+ async function visit(path) {
66
+ for (const entry of await readdir(path, { withFileTypes: true })) {
67
+ const child = join(path, entry.name);
68
+ if (entry.isDirectory())
69
+ await visit(child);
70
+ else if (/\.(ttl|nt|rdf|owl)$/i.test(entry.name))
71
+ files.push(child);
72
+ }
73
+ }
74
+ await visit(root);
75
+ return files.sort();
76
+ }
77
+ export class OpenCaesarOntologyCompiler {
78
+ config;
79
+ repositoryRoot;
80
+ storageRoot;
81
+ constructor(config, repositoryRoot, storageRoot) {
82
+ this.config = config;
83
+ this.repositoryRoot = repositoryRoot;
84
+ this.storageRoot = storageRoot;
85
+ }
86
+ checkReady() {
87
+ return requireLinuxDocker(this.repositoryRoot);
88
+ }
89
+ async compile(snapshotId, artifacts, context) {
90
+ if (context) {
91
+ return withCommittedTree(context.repositoryRoot, context.commitSha, (root) => new OpenCaesarOntologyCompiler(this.config, root, this.storageRoot).compile(snapshotId, artifacts));
92
+ }
93
+ await this.checkReady();
94
+ if (!this.config.projectPath || !this.config.containerImage) {
95
+ throw new Error('Optional openCAESAR requires projectPath and containerImage');
96
+ }
97
+ const source = resolve(this.repositoryRoot, this.config.projectPath);
98
+ const work = join(this.storageRoot, 'work', `ontology-${snapshotId}-${randomUUID()}`);
99
+ await rm(work, { recursive: true, force: true });
100
+ await mkdir(dirname(work), { recursive: true });
101
+ const sourceBuild = join(source, 'build');
102
+ await cp(source, work, {
103
+ recursive: true,
104
+ filter: (path) => path !== sourceBuild && !path.startsWith(`${sourceBuild}${sep}`),
105
+ });
106
+ const generatedRoot = join(work, 'src', 'oml', 'context-graph.dev', 'generated');
107
+ await mkdir(generatedRoot, { recursive: true });
108
+ for (const artifact of artifacts) {
109
+ if (!artifact.oml.trim())
110
+ continue;
111
+ await writeFile(join(generatedRoot, `${artifact.key}.oml`), `${artifact.oml.trim()}\n`, 'utf8');
112
+ }
113
+ await writeFile(join(generatedRoot, 'snapshot.oml'), `${renderGeneratedOntologyRoot(artifacts, this.config.usedVocabularyIris, this.config.includedDescriptionIris)}\n`, 'utf8');
114
+ const dockerPath = work.replace(/\\/g, '/');
115
+ await runProcess('docker', [
116
+ 'run',
117
+ '--rm',
118
+ ...dockerHostUserArguments(),
119
+ '-v',
120
+ `${dockerPath}:/workspace`,
121
+ '-w',
122
+ '/workspace',
123
+ this.config.containerImage,
124
+ 'gradle',
125
+ '--no-daemon',
126
+ 'clean',
127
+ 'oml2owl',
128
+ ], this.repositoryRoot);
129
+ const rdfRoot = join(work, 'build', 'rdf');
130
+ const rdfFiles = await listRdfFiles(rdfRoot);
131
+ if (rdfFiles.length === 0)
132
+ throw new Error('openCAESAR produced no RDF files');
133
+ const digestParts = await Promise.all(rdfFiles.map(async (path) => ({
134
+ path: relative(rdfRoot, path),
135
+ content: await readFile(path, 'utf8'),
136
+ })));
137
+ return { root: rdfRoot, rdfFiles, digest: sha256(stableJson(digestParts)) };
138
+ }
139
+ }
140
+ /** Default compiler preserves asserted semantics without Java, Docker, or an OWL reasoner. */
141
+ export class DirectRdfOntologyCompiler {
142
+ storageRoot;
143
+ constructor(storageRoot) {
144
+ this.storageRoot = storageRoot;
145
+ }
146
+ async compile(snapshotId, artifacts) {
147
+ const { namedNode } = DataFactory;
148
+ const dataset = new Store();
149
+ for (const artifact of [...artifacts].sort((a, b) => a.key.localeCompare(b.key))) {
150
+ for (const fact of artifact.facts) {
151
+ dataset.addQuad(namedNode(nodeIri(fact.subject.id)), namedNode(CG + fact.predicate), namedNode(nodeIri(fact.object.id)));
152
+ }
153
+ }
154
+ const writer = new Writer({ format: 'N-Triples' });
155
+ writer.addQuads(dataset.getQuads(null, null, null, null));
156
+ const text = await new Promise((accept, reject) => writer.end((error, value) => error ? reject(error) : accept(value)));
157
+ const content = text.split('\n').filter(Boolean).sort().join('\n') + '\n';
158
+ const root = join(this.storageRoot, 'work', `rdf-${snapshotId}-${randomUUID()}`);
159
+ await mkdir(root, { recursive: true });
160
+ const path = join(root, 'semantic.nt');
161
+ await writeFile(path, content);
162
+ return { root, rdfFiles: [path], digest: sha256(content) };
163
+ }
164
+ }
@@ -0,0 +1,8 @@
1
+ import type { ContextGraphConfig } from "../configuration/config.js";
2
+ import { type SemanticExtractor, type SemanticRunOptions } from "./semantic.js";
3
+ export interface SemanticProviderModule {
4
+ /** Trusted local code. Providers must honor abort signals and never log private inputs. */
5
+ createSemanticExtractor(config: ContextGraphConfig['semantic'], options?: SemanticRunOptions): SemanticExtractor | Promise<SemanticExtractor>;
6
+ }
7
+ /** Lazy loading ensures a missing provider cannot disable saved-evidence queries. */
8
+ export declare function createSemanticExtractor(config: ContextGraphConfig['semantic'], repositoryRoot: string): SemanticExtractor;
@@ -0,0 +1,58 @@
1
+ import { CodexCliSemanticExtractor, SemanticProviderError } from "./semantic.js";
2
+ import { sha256, stableJson } from "../infrastructure/util.js";
3
+ import { resolveConsumerModule } from "../infrastructure/module-resolution.js";
4
+ /** Lazy loading ensures a missing provider cannot disable saved-evidence queries. */
5
+ export function createSemanticExtractor(config, repositoryRoot) {
6
+ if (config.provider === 'codex-cli')
7
+ return new CodexCliSemanticExtractor(config);
8
+ const modulePath = config.providerModule;
9
+ const identity = `${config.providerIdentity}:${sha256(stableJson(config))}:contract-v2`;
10
+ let extractor;
11
+ return {
12
+ identity,
13
+ async extract(source, context, options = {}) {
14
+ const deadline = new AbortController();
15
+ const timer = setTimeout(() => deadline.abort(new SemanticProviderError('timeout', 'Semantic module execution timed out')), options.timeoutMs ?? config.timeoutMs ?? 120_000);
16
+ const signal = AbortSignal.any([deadline.signal,
17
+ ...(options.signal ? [options.signal] : [])]);
18
+ const abortError = () => deadline.signal.aborted ? deadline.signal.reason :
19
+ new SemanticProviderError('cancelled', 'Semantic module execution cancelled');
20
+ const checkpoint = () => { if (signal.aborted)
21
+ throw abortError(); };
22
+ let onAbort = () => { };
23
+ try {
24
+ return await Promise.race([
25
+ new Promise((_resolve, reject) => {
26
+ onAbort = () => reject(abortError());
27
+ signal.addEventListener('abort', onAbort, { once: true });
28
+ if (signal.aborted)
29
+ onAbort();
30
+ }),
31
+ Promise.resolve().then(async () => {
32
+ checkpoint();
33
+ if (!extractor) {
34
+ const module = await import(resolveConsumerModule(modulePath, repositoryRoot));
35
+ checkpoint();
36
+ if (typeof module.createSemanticExtractor !== 'function')
37
+ throw new Error('Provider module must export createSemanticExtractor(config)');
38
+ const candidate = await module.createSemanticExtractor(config, { ...options, signal });
39
+ checkpoint();
40
+ if (candidate?.identity !== config.providerIdentity || typeof candidate.extract !== 'function') {
41
+ throw new Error('Provider identity/contract does not match configuration');
42
+ }
43
+ extractor = candidate;
44
+ }
45
+ checkpoint();
46
+ const result = await extractor.extract(source, context, { ...options, signal });
47
+ checkpoint();
48
+ return result;
49
+ }),
50
+ ]);
51
+ }
52
+ finally {
53
+ clearTimeout(timer);
54
+ signal.removeEventListener('abort', onAbort);
55
+ }
56
+ },
57
+ };
58
+ }
@@ -0,0 +1,2 @@
1
+ import type { ExtractionContext, GraphFact, RuntimeTraceReference } from "@weftlet/core";
2
+ export declare function runtimeEvidenceFacts(context: ExtractionContext, references: readonly RuntimeTraceReference[]): readonly GraphFact[];
@@ -0,0 +1,84 @@
1
+ import { sha256, stableJson } from "../infrastructure/util.js";
2
+ const extractor = { id: 'otlp-runtime-evidence', version: '1.0.0' };
3
+ function graphId(prefix, value) {
4
+ const normalized = value
5
+ .trim()
6
+ .toLowerCase()
7
+ .replace(/[^a-z0-9._:-]+/g, '-')
8
+ .replace(/^-+|-+$/g, '');
9
+ return `${prefix}:${normalized || 'unknown'}`;
10
+ }
11
+ function capabilityNode(value) {
12
+ const canonical = value.replace(/^(?:[^:]+:)?capability:/, '');
13
+ return {
14
+ id: graphId('capability', canonical),
15
+ kind: 'Capability',
16
+ label: canonical,
17
+ attributes: { evidenceLayer: 'observed' },
18
+ };
19
+ }
20
+ export function runtimeEvidenceFacts(context, references) {
21
+ const facts = [];
22
+ for (const reference of references) {
23
+ if (!reference.accepted || !reference.capability)
24
+ continue;
25
+ const service = {
26
+ id: graphId('component:runtime-service', reference.serviceName),
27
+ kind: 'Component',
28
+ label: reference.serviceName,
29
+ attributes: {
30
+ evidenceLayer: 'observed',
31
+ serviceVersion: reference.serviceVersion,
32
+ ...(reference.environment ? { environment: reference.environment } : {}),
33
+ },
34
+ };
35
+ const capability = capabilityNode(reference.capability);
36
+ const evidence = {
37
+ id: `evidence:runtime:${reference.traceId}:${reference.spanId}`,
38
+ kind: 'Evidence',
39
+ label: `Runtime trace ${reference.traceId.slice(0, 12)}`,
40
+ attributes: {
41
+ evidenceLayer: 'observed',
42
+ traceId: reference.traceId,
43
+ ...(reference.observedAt ? { observedAt: reference.observedAt } : {}),
44
+ },
45
+ };
46
+ const workflow = reference.operation
47
+ ? {
48
+ id: graphId('workflow:runtime-operation', reference.operation),
49
+ kind: 'Workflow',
50
+ label: reference.operation,
51
+ attributes: { evidenceLayer: 'observed' },
52
+ }
53
+ : undefined;
54
+ const provenance = {
55
+ path: reference.sourcePath,
56
+ startLine: 1,
57
+ endLine: 1,
58
+ digest: reference.sourceDigest,
59
+ commitSha: context.commitSha,
60
+ };
61
+ const relationships = [
62
+ { subject: service, predicate: 'realizes', object: capability },
63
+ { subject: capability, predicate: 'verifiedBy', object: evidence },
64
+ ...(workflow
65
+ ? [
66
+ { subject: workflow, predicate: 'realizes', object: capability },
67
+ { subject: workflow, predicate: 'routesThrough', object: service },
68
+ { subject: workflow, predicate: 'verifiedBy', object: evidence },
69
+ ]
70
+ : []),
71
+ ];
72
+ for (const relationship of relationships) {
73
+ facts.push({
74
+ id: sha256(stableJson({ reference, relationship })),
75
+ ...relationship,
76
+ provenance,
77
+ extractor,
78
+ confidence: 1,
79
+ snapshotId: context.snapshotId,
80
+ });
81
+ }
82
+ }
83
+ return facts;
84
+ }
@@ -0,0 +1,7 @@
1
+ /** Display line numbers without changing the source bytes used for provenance. */
2
+ export declare function numberedSemanticSource(content: string): string;
3
+ export declare function semanticCitationSchema(lineCount: number): object;
4
+ export declare function assertSemanticCitation(citation: {
5
+ readonly startLine: number;
6
+ readonly endLine: number;
7
+ }, path: string, lineCount: number, location: string): void;
@@ -0,0 +1,27 @@
1
+ /** Display line numbers without changing the source bytes used for provenance. */
2
+ export function numberedSemanticSource(content) {
3
+ return content
4
+ .split('\n')
5
+ .map((line, index) => `${index + 1}|${line.replace(/\r$/, '')}`)
6
+ .join('\n');
7
+ }
8
+ export function semanticCitationSchema(lineCount) {
9
+ return {
10
+ type: 'object',
11
+ additionalProperties: false,
12
+ required: ['startLine', 'endLine'],
13
+ properties: {
14
+ startLine: { type: 'integer', minimum: 1, maximum: lineCount },
15
+ endLine: { type: 'integer', minimum: 1, maximum: lineCount },
16
+ },
17
+ };
18
+ }
19
+ export function assertSemanticCitation(citation, path, lineCount, location) {
20
+ if (!Number.isInteger(citation.startLine) ||
21
+ !Number.isInteger(citation.endLine) ||
22
+ citation.startLine < 1 ||
23
+ citation.endLine < citation.startLine ||
24
+ citation.endLine > lineCount) {
25
+ throw new Error(`Invalid source citation for ${path}: ${location} cites ${citation.startLine}-${citation.endLine}; expected integer lines 1-${lineCount} with startLine <= endLine`);
26
+ }
27
+ }
@@ -0,0 +1,11 @@
1
+ export interface SemanticRunOptions {
2
+ readonly signal?: AbortSignal;
3
+ readonly timeoutMs?: number;
4
+ }
5
+ export declare class SemanticProviderError extends Error {
6
+ readonly code: 'timeout' | 'cancelled' | 'unavailable' | 'exit' | 'invalid-output';
7
+ readonly retryable: boolean;
8
+ constructor(code: 'timeout' | 'cancelled' | 'unavailable' | 'exit' | 'invalid-output', message: string, retryable?: boolean);
9
+ }
10
+ /** Intentionally never forwards provider stderr, prompts or environment values. */
11
+ export declare function runSemanticProcess(command: string, args: readonly string[], cwd: string, prompt: string, environment: Record<string, string | undefined>, options?: SemanticRunOptions): Promise<void>;
@@ -0,0 +1,68 @@
1
+ import { spawn } from 'node:child_process';
2
+ export class SemanticProviderError extends Error {
3
+ code;
4
+ retryable;
5
+ constructor(code, message, retryable = false) {
6
+ super(message);
7
+ this.code = code;
8
+ this.retryable = retryable;
9
+ this.name = 'SemanticProviderError';
10
+ }
11
+ }
12
+ /** Intentionally never forwards provider stderr, prompts or environment values. */
13
+ export function runSemanticProcess(command, args, cwd, prompt, environment, options = {}) {
14
+ if (options.signal?.aborted) {
15
+ return Promise.reject(new SemanticProviderError('cancelled', 'Semantic extraction cancelled'));
16
+ }
17
+ return new Promise((resolve, reject) => {
18
+ const child = spawn(command, [...args], {
19
+ cwd, env: environment, stdio: ['pipe', 'ignore', 'ignore'],
20
+ windowsHide: true, detached: process.platform !== 'win32',
21
+ });
22
+ let failure;
23
+ let killTimer;
24
+ const kill = (signal) => {
25
+ try {
26
+ if (process.platform !== 'win32' && child.pid)
27
+ process.kill(-child.pid, signal);
28
+ else
29
+ child.kill(signal);
30
+ }
31
+ catch { /* The process may have already exited. */ }
32
+ };
33
+ const stop = (code) => {
34
+ if (failure)
35
+ return;
36
+ failure = new SemanticProviderError(code, `Semantic extraction ${code}`);
37
+ kill('SIGTERM');
38
+ killTimer = setTimeout(() => kill('SIGKILL'), 1000);
39
+ killTimer.unref();
40
+ };
41
+ const cancel = () => stop('cancelled');
42
+ options.signal?.addEventListener('abort', cancel, { once: true });
43
+ const timer = setTimeout(() => stop('timeout'), options.timeoutMs ?? 120_000);
44
+ const cleanup = () => {
45
+ clearTimeout(timer);
46
+ if (killTimer)
47
+ clearTimeout(killTimer);
48
+ options.signal?.removeEventListener('abort', cancel);
49
+ };
50
+ child.once('error', () => {
51
+ cleanup();
52
+ reject(new SemanticProviderError('unavailable', 'Semantic provider executable could not start'));
53
+ });
54
+ child.once('close', (code) => {
55
+ cleanup();
56
+ if (failure)
57
+ reject(failure);
58
+ else if (code === 0)
59
+ resolve();
60
+ else
61
+ reject(new SemanticProviderError('exit', `Semantic provider exited with status ${code}`, code === 75));
62
+ });
63
+ child.stdin.on('error', () => { });
64
+ child.stdin.end(prompt);
65
+ if (options.signal?.aborted)
66
+ cancel();
67
+ });
68
+ }
@@ -0,0 +1,73 @@
1
+ import { type CodexLoginProbe, type SemanticCommandEnvironment } from './codex-auth.js';
2
+ export { semanticCommandEnvironment } from './codex-auth.js';
3
+ export type { SemanticCommandEnvironment } from './codex-auth.js';
4
+ import { type SemanticRunOptions } from "./semantic-process.js";
5
+ export { SemanticProviderError } from "./semantic-process.js";
6
+ export type { SemanticRunOptions } from "./semantic-process.js";
7
+ import type { ExtractionContext, GraphNodeKind, GraphPredicate, SemanticArtifact, SemanticSource, DiagnosticKind } from "@weftlet/core";
8
+ import type { ContextGraphConfig } from "../configuration/config.js";
9
+ import type { SemanticArtifactStore } from "../storage/storage.js";
10
+ export interface ExtractedAssertion {
11
+ readonly subject: {
12
+ readonly id: string;
13
+ readonly kind: GraphNodeKind;
14
+ readonly label: string;
15
+ };
16
+ readonly predicate: GraphPredicate;
17
+ readonly object: {
18
+ readonly id: string;
19
+ readonly kind: GraphNodeKind;
20
+ readonly label: string;
21
+ };
22
+ readonly citation: {
23
+ readonly startLine: number;
24
+ readonly endLine: number;
25
+ };
26
+ readonly confidence: number;
27
+ }
28
+ export interface SemanticOutput {
29
+ readonly assertions: readonly ExtractedAssertion[];
30
+ readonly oml: string;
31
+ readonly unresolvedMappings?: readonly string[];
32
+ readonly diagnostics?: readonly {
33
+ readonly kind: Exclude<DiagnosticKind, 'runtimeGaps' | 'drift'>;
34
+ readonly reason: string;
35
+ readonly citation: {
36
+ readonly startLine: number;
37
+ readonly endLine: number;
38
+ };
39
+ readonly relatedNodeIds: readonly string[];
40
+ }[];
41
+ }
42
+ export interface SemanticExtractionResult {
43
+ readonly parsed: SemanticOutput;
44
+ readonly rawModelOutput: string;
45
+ }
46
+ export interface SemanticExtractor {
47
+ readonly identity: string;
48
+ extract(source: SemanticSource, context: ExtractionContext, options?: SemanticRunOptions): Promise<SemanticExtractionResult>;
49
+ }
50
+ export interface SemanticCommandRunner {
51
+ run(command: string, args: readonly string[], cwd: string, prompt: string, environment: SemanticCommandEnvironment, options?: SemanticRunOptions): Promise<void>;
52
+ }
53
+ export declare function semanticOutputSchema(lineCount: number): object;
54
+ /** Runtime validation is shared by every provider; schema-constrained output is not trusted blindly. */
55
+ export declare function assertSemanticOutput(value: unknown, source: SemanticSource): asserts value is SemanticOutput;
56
+ export declare class CodexCliSemanticExtractor implements SemanticExtractor {
57
+ private readonly config;
58
+ private readonly runner;
59
+ private readonly loginProbe;
60
+ readonly identity: string;
61
+ constructor(config: ContextGraphConfig['semantic'], runner?: SemanticCommandRunner, loginProbe?: CodexLoginProbe);
62
+ extract(source: SemanticSource, context: ExtractionContext, options?: SemanticRunOptions): Promise<SemanticExtractionResult>;
63
+ }
64
+ export declare class SemanticHydrator {
65
+ private readonly config;
66
+ private readonly store;
67
+ private readonly extractor;
68
+ constructor(config: ContextGraphConfig['semantic'], store: SemanticArtifactStore, extractor: SemanticExtractor);
69
+ hydrate(source: SemanticSource, context: ExtractionContext, forceRevision?: string, options?: SemanticRunOptions): Promise<{
70
+ artifact: SemanticArtifact;
71
+ reused: boolean;
72
+ }>;
73
+ }