@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,23 @@
1
+ import type { ContextGraphConfig } from "../configuration/config.js";
2
+ import type { ImpactQueryService, ImpactScanRequest, SnapshotStore } from "@weftlet/core";
3
+ import type { GitRepository } from "../repository/git.js";
4
+ import type { ContextGraphHydrator } from "./hydrator.js";
5
+ export interface AgentSemanticScope {
6
+ readonly commitSha: string;
7
+ readonly semanticSources: readonly string[];
8
+ readonly headName: string;
9
+ readonly snapshotSuffix: string;
10
+ }
11
+ export declare class AgentSemanticScopeResolver {
12
+ private readonly config;
13
+ private readonly repository;
14
+ constructor(config: ContextGraphConfig, repository: GitRepository);
15
+ resolve(request: ImpactScanRequest): Promise<AgentSemanticScope>;
16
+ }
17
+ export declare class PreparedImpactQueryService implements ImpactQueryService {
18
+ private readonly store;
19
+ private readonly hydrator;
20
+ private readonly scopeResolver;
21
+ constructor(store: SnapshotStore, hydrator: ContextGraphHydrator, scopeResolver: AgentSemanticScopeResolver);
22
+ scan(request: ImpactScanRequest): Promise<import("@weftlet/core").ContextPack>;
23
+ }
@@ -0,0 +1,94 @@
1
+ // Modified for standalone extraction; see docs/extraction-manifest.json.
2
+ import { basename } from 'node:path';
3
+ import { SnapshotImpactQueryService } from "../graph/query.js";
4
+ import { sha256, stableJson } from "../infrastructure/util.js";
5
+ function normalizeRepositoryPath(path) {
6
+ const normalized = path.replaceAll('\\', '/').replace(/^\.\//, '');
7
+ if (normalized.startsWith('/') || normalized.split('/').includes('..')) {
8
+ throw new Error(`ownerDocument must be a repository-relative path: ${path}`);
9
+ }
10
+ return normalized;
11
+ }
12
+ export class AgentSemanticScopeResolver {
13
+ config;
14
+ repository;
15
+ constructor(config, repository) {
16
+ this.config = config;
17
+ this.repository = repository;
18
+ }
19
+ async resolve(request) {
20
+ const agent = this.config.agentContext;
21
+ if (!agent)
22
+ throw new Error('Agent context preparation is not configured');
23
+ const commitSha = await this.repository.resolveRef('HEAD');
24
+ const available = new Set((await this.repository.listFilesAt(commitSha, this.config.semanticSources)).filter((path) => /\.(?:md|mdx|txt)$/i.test(path)));
25
+ const selected = new Set();
26
+ for (const path of await this.repository.listFilesAt(commitSha, agent.alwaysSemanticSources)) {
27
+ if (available.has(path))
28
+ selected.add(path);
29
+ }
30
+ const ownerDocument = request.ownerDocument
31
+ ? normalizeRepositoryPath(request.ownerDocument)
32
+ : undefined;
33
+ if (ownerDocument) {
34
+ if (!available.has(ownerDocument)) {
35
+ throw new Error(`Owner document is not a configured semantic source: ${ownerDocument}`);
36
+ }
37
+ selected.add(ownerDocument);
38
+ const content = await this.repository.readFileAt(commitSha, ownerDocument);
39
+ if (agent.followDocumentReferences) {
40
+ const references = [...content.matchAll(/\bdocs\/[A-Za-z0-9_./-]+\.md\b/g)]
41
+ .map((match) => match[0])
42
+ .filter((path) => available.has(path));
43
+ for (const path of references.slice(0, agent.maxReferencedDocuments))
44
+ selected.add(path);
45
+ }
46
+ if (agent.includeMatchingEvidence) {
47
+ const ownerSlug = basename(ownerDocument).replace(/\.md$/i, '');
48
+ for (const path of [...available].filter((path) => this.config.evidenceRoots.some((root) => path === root || path.startsWith(`${root.replace(/\/$/, '')}/`)) && path.includes(ownerSlug))) {
49
+ selected.add(path);
50
+ }
51
+ }
52
+ }
53
+ else {
54
+ const terms = [
55
+ request.task,
56
+ ...(request.checklistItems ?? []),
57
+ ...(request.capabilities ?? []),
58
+ ]
59
+ .filter((term) => Boolean(term))
60
+ .slice(0, 8);
61
+ const matches = await this.repository.findTextAt(commitSha, terms, this.config.semanticSources);
62
+ for (const match of matches.slice(0, agent.maxReferencedDocuments))
63
+ selected.add(match.path);
64
+ }
65
+ const semanticSources = [...selected].sort();
66
+ if (semanticSources.length === 0) {
67
+ throw new Error('Agent context scope did not resolve any semantic sources');
68
+ }
69
+ const scopeDigest = sha256(stableJson(semanticSources)).slice(0, 16);
70
+ return {
71
+ commitSha,
72
+ semanticSources,
73
+ headName: `agent-${scopeDigest}`,
74
+ snapshotSuffix: `agent-${scopeDigest}`,
75
+ };
76
+ }
77
+ }
78
+ export class PreparedImpactQueryService {
79
+ store;
80
+ hydrator;
81
+ scopeResolver;
82
+ constructor(store, hydrator, scopeResolver) {
83
+ this.store = store;
84
+ this.hydrator = hydrator;
85
+ this.scopeResolver = scopeResolver;
86
+ }
87
+ async scan(request) {
88
+ if (request.snapshotId) {
89
+ return new SnapshotImpactQueryService(this.store, 'default').scan(request);
90
+ }
91
+ const scope = await this.scopeResolver.resolve(request);
92
+ return new SnapshotImpactQueryService(this.store, scope.headName).scan(request);
93
+ }
94
+ }
@@ -0,0 +1,23 @@
1
+ import { SavedEvidenceQueryService } from "./saved-evidence.js";
2
+ import { AgentSemanticScopeResolver } from "./agent-context.js";
3
+ import type { ContextGraphAdapter, ContextGraphRepository } from "@weftlet/core";
4
+ import { GitRepository } from "../repository/git.js";
5
+ import { ContextGraphHydrator } from "./hydrator.js";
6
+ import { OpenCaesarOntologyCompiler, DirectRdfOntologyCompiler } from "../extraction/ontology.js";
7
+ import { FileSnapshotStore } from "../storage/storage.js";
8
+ import { SnapshotChecks } from "./snapshot-checks.js";
9
+ export declare function loadContextGraphAdapterModule(moduleSpecifier: string | undefined, repository: ContextGraphRepository, repositoryRoot?: string): Promise<ContextGraphAdapter>;
10
+ export declare function createContextGraphApplication(configPath: string): Promise<{
11
+ storageRoot: string;
12
+ repository: GitRepository;
13
+ snapshotStore: FileSnapshotStore;
14
+ ontologyCompiler: OpenCaesarOntologyCompiler | DirectRdfOntologyCompiler;
15
+ hydrator: ContextGraphHydrator;
16
+ queryService: SavedEvidenceQueryService;
17
+ snapshotChecks: SnapshotChecks;
18
+ scopeResolver: AgentSemanticScopeResolver | undefined;
19
+ headName: string;
20
+ config: import("../configuration/config.js").ContextGraphConfig;
21
+ configPath: string;
22
+ repositoryRoot: string;
23
+ }>;
@@ -0,0 +1,91 @@
1
+ // Modified for standalone extraction; see docs/extraction-manifest.json.
2
+ import { SavedEvidenceQueryService } from "./saved-evidence.js";
3
+ import { sha256, stableJson } from "../infrastructure/util.js";
4
+ import { AgentSemanticScopeResolver, PreparedImpactQueryService } from "./agent-context.js";
5
+ import { resolveStorageRoot } from "../configuration/cache.js";
6
+ import { loadConfig } from "../configuration/config.js";
7
+ import { GitRepository } from "../repository/git.js";
8
+ import { ContextGraphHydrator } from "./hydrator.js";
9
+ import { OpenCaesarOntologyCompiler, DirectRdfOntologyCompiler } from "../extraction/ontology.js";
10
+ import { SnapshotImpactQueryService } from "../graph/query.js";
11
+ import { SemanticHydrator } from "../extraction/semantic.js";
12
+ import { createSemanticExtractor } from "../extraction/providers.js";
13
+ import { SemanticArtifactStore, FileSnapshotStore } from "../storage/storage.js";
14
+ import { RepositoryContractExtractor, RepositoryFileExtractor, ScipSymbolExtractor, ScipTypeScriptIndexer, } from "../extraction/static.js";
15
+ import { OtlpJsonRuntimeEvidenceProvider } from "../extraction/telemetry.js";
16
+ import { SnapshotChecks } from "./snapshot-checks.js";
17
+ import { resolveConsumerModule } from "../infrastructure/module-resolution.js";
18
+ const emptyAdapter = {
19
+ factExtractors: [],
20
+ invariantEvaluators: [],
21
+ };
22
+ export async function loadContextGraphAdapterModule(moduleSpecifier, repository, repositoryRoot = process.cwd()) {
23
+ if (!moduleSpecifier)
24
+ return emptyAdapter;
25
+ let candidate;
26
+ try {
27
+ candidate = (await import(resolveConsumerModule(moduleSpecifier, repositoryRoot)));
28
+ }
29
+ catch (error) {
30
+ throw new Error(`Unable to load context graph adapter ${moduleSpecifier}`, { cause: error });
31
+ }
32
+ if (typeof candidate.createContextGraphAdapter !== 'function') {
33
+ throw new Error(`Context graph adapter ${moduleSpecifier} must export createContextGraphAdapter(repository)`);
34
+ }
35
+ const adapter = candidate.createContextGraphAdapter(repository);
36
+ if (!Array.isArray(adapter.factExtractors) || !Array.isArray(adapter.invariantEvaluators)) {
37
+ throw new Error(`Context graph adapter ${moduleSpecifier} returned an invalid adapter`);
38
+ }
39
+ return adapter;
40
+ }
41
+ export async function createContextGraphApplication(configPath) {
42
+ const loaded = await loadConfig(configPath);
43
+ const { config, repositoryRoot } = loaded;
44
+ const storageRoot = resolveStorageRoot(repositoryRoot, config);
45
+ const repository = new GitRepository(repositoryRoot);
46
+ const adapter = await loadContextGraphAdapterModule(config.adapter, repository, repositoryRoot);
47
+ const snapshotStore = new FileSnapshotStore(storageRoot);
48
+ const artifactStore = new SemanticArtifactStore(storageRoot);
49
+ const semanticExtractor = createSemanticExtractor(config.semantic, repositoryRoot);
50
+ const semanticHydrator = new SemanticHydrator(config.semantic, artifactStore, semanticExtractor);
51
+ const staticIndexer = new ScipTypeScriptIndexer(config.scip, storageRoot);
52
+ const ontologyCompiler = config.ontology.backend === 'opencaesar' ? new OpenCaesarOntologyCompiler(config.ontology, repositoryRoot, storageRoot) : new DirectRdfOntologyCompiler(storageRoot);
53
+ const runtimeEvidenceProvider = new OtlpJsonRuntimeEvidenceProvider(config.runtimeEvidence, config.runtimeEvidencePolicy);
54
+ const extractorFactory = (scip) => [
55
+ new RepositoryFileExtractor(repository, config.codeRoots, scip.digest),
56
+ new RepositoryContractExtractor(repository, config.contractPatterns, config.contractConsumerRoots ?? config.codeRoots, config.contractAliases),
57
+ new ScipSymbolExtractor(repository, scip),
58
+ ...adapter.factExtractors,
59
+ ];
60
+ const hydrator = new ContextGraphHydrator({
61
+ config,
62
+ repository,
63
+ snapshotStore,
64
+ semanticHydrator,
65
+ staticIndexer,
66
+ ontologyCompiler,
67
+ runtimeEvidenceProvider,
68
+ extractorFactory,
69
+ invariantEvaluators: adapter.invariantEvaluators,
70
+ });
71
+ const headName = 'default';
72
+ const scopeResolver = config.agentContext
73
+ ? new AgentSemanticScopeResolver(config, repository)
74
+ : undefined;
75
+ const rawQueryService = scopeResolver
76
+ ? new PreparedImpactQueryService(snapshotStore, hydrator, scopeResolver)
77
+ : new SnapshotImpactQueryService(snapshotStore, headName);
78
+ const queryService = new SavedEvidenceQueryService(rawQueryService, repository, sha256(stableJson(config)));
79
+ return {
80
+ ...loaded,
81
+ storageRoot,
82
+ repository,
83
+ snapshotStore,
84
+ ontologyCompiler,
85
+ hydrator,
86
+ queryService,
87
+ snapshotChecks: new SnapshotChecks(snapshotStore, repository, hydrator, scopeResolver, sha256(stableJson(config))),
88
+ scopeResolver,
89
+ headName,
90
+ };
91
+ }
@@ -0,0 +1,49 @@
1
+ import type { ContextGraphConfig } from "../configuration/config.js";
2
+ import type { FactExtractor, GraphSnapshot, InvariantEvaluator, RuntimeTraceReference, RuntimeEvidenceProvider, SnapshotStore } from "@weftlet/core";
3
+ import type { GitRepository } from "../repository/git.js";
4
+ import type { OntologyCompiler } from "../extraction/ontology.js";
5
+ import type { SemanticHydrator } from "../extraction/semantic.js";
6
+ import type { ScipIndexResult, StaticIndexer } from "../extraction/static.js";
7
+ export interface HydrationOptions {
8
+ readonly signal?: AbortSignal;
9
+ readonly onProgress?: (event: {
10
+ phase: string;
11
+ completed?: number;
12
+ total?: number;
13
+ }) => void;
14
+ readonly ref: string;
15
+ readonly headName: string;
16
+ readonly forceSemantic?: boolean;
17
+ readonly snapshotSuffix?: string;
18
+ readonly requireClean?: boolean;
19
+ readonly semanticSources?: readonly string[];
20
+ readonly runtimeEvidenceRevision?: RuntimeEvidenceRevision;
21
+ }
22
+ export interface RuntimeEvidenceRevision {
23
+ readonly commitSha: string;
24
+ readonly digest: string;
25
+ readonly references: readonly RuntimeTraceReference[];
26
+ }
27
+ export interface HydrationResult {
28
+ readonly snapshot: GraphSnapshot;
29
+ readonly semanticExtracted: number;
30
+ readonly semanticReused: number;
31
+ }
32
+ export interface HydratorDependencies {
33
+ readonly config: ContextGraphConfig;
34
+ readonly repository: GitRepository;
35
+ readonly snapshotStore: SnapshotStore;
36
+ readonly semanticHydrator: SemanticHydrator;
37
+ readonly staticIndexer: StaticIndexer;
38
+ readonly ontologyCompiler: OntologyCompiler;
39
+ readonly runtimeEvidenceProvider: RuntimeEvidenceProvider;
40
+ readonly extractorFactory: (scip: ScipIndexResult) => readonly FactExtractor[];
41
+ readonly invariantEvaluators: readonly InvariantEvaluator[];
42
+ }
43
+ export declare class ContextGraphHydrator {
44
+ private readonly dependencies;
45
+ constructor(dependencies: HydratorDependencies);
46
+ collectRuntimeEvidence(commitSha: string): Promise<RuntimeEvidenceRevision>;
47
+ hydrate(options: HydrationOptions): Promise<HydrationResult>;
48
+ compareClean(options: Omit<HydrationOptions, 'snapshotSuffix'>): Promise<HydrationResult>;
49
+ }
@@ -0,0 +1,275 @@
1
+ import { contractPatternRoots } from "../repository/glob.js";
2
+ import { sha256, stableJson } from "../infrastructure/util.js";
3
+ import { linkSemanticDocuments } from "../extraction/document.js";
4
+ import { runtimeEvidenceFacts } from "../extraction/runtime-evidence.js";
5
+ import { matchesRepositoryGlob } from "../repository/glob.js";
6
+ import { RdfEvidenceGraph } from "../graph/rdf.js";
7
+ async function concurrentMap(values, concurrency, worker) {
8
+ const results = new Array(values.length);
9
+ let cursor = 0;
10
+ let failure;
11
+ let failed = false;
12
+ await Promise.all(Array.from({ length: Math.max(1, Math.min(concurrency, values.length)) }, async () => {
13
+ while (!failed && cursor < values.length) {
14
+ const index = cursor++;
15
+ try {
16
+ results[index] = await worker(values[index], index);
17
+ }
18
+ catch (error) {
19
+ failed = true;
20
+ failure ??= error;
21
+ }
22
+ }
23
+ }));
24
+ if (failed)
25
+ throw failure;
26
+ return results;
27
+ }
28
+ export class ContextGraphHydrator {
29
+ dependencies;
30
+ constructor(dependencies) {
31
+ this.dependencies = dependencies;
32
+ }
33
+ async collectRuntimeEvidence(commitSha) {
34
+ const { config, repository } = this.dependencies;
35
+ const context = {
36
+ repositoryRoot: repository.root,
37
+ repositoryId: config.repositoryId,
38
+ ref: commitSha,
39
+ commitSha,
40
+ snapshotId: commitSha,
41
+ changedPaths: [],
42
+ deletedPaths: [],
43
+ renamedPaths: {},
44
+ };
45
+ const references = [...(await this.dependencies.runtimeEvidenceProvider.collect(context))]
46
+ .filter((evidence) => evidence.accepted)
47
+ .sort((left, right) => stableJson(left).localeCompare(stableJson(right)));
48
+ return {
49
+ commitSha,
50
+ digest: sha256(stableJson(references)),
51
+ references,
52
+ };
53
+ }
54
+ async hydrate(options) {
55
+ options.signal?.throwIfAborted();
56
+ options.onProgress?.({ phase: 'resolve-committed-sources' });
57
+ const { config, repository, snapshotStore } = this.dependencies;
58
+ const commitSha = await repository.resolveRef(options.ref);
59
+ if (options.requireClean === true)
60
+ await repository.requireExactCleanCommit(commitSha);
61
+ await this.dependencies.ontologyCompiler.checkReady?.();
62
+ const prior = await snapshotStore.readHead(options.headName);
63
+ const baseSha = prior?.manifest.commitSha === commitSha
64
+ ? prior.manifest.baseSha
65
+ : (prior?.manifest.commitSha ?? (await repository.firstParent(commitSha)));
66
+ const selectedSemanticSources = options.semanticSources ?? config.semanticSources;
67
+ const allRoots = [
68
+ ...new Set([
69
+ ...selectedSemanticSources,
70
+ ...config.codeRoots,
71
+ ...config.evidenceRoots,
72
+ ...contractPatternRoots(config.contractPatterns),
73
+ ]),
74
+ ];
75
+ const delta = await repository.delta(baseSha, commitSha, allRoots);
76
+ const forceRevision = options.forceSemantic
77
+ ? `${commitSha}:${new Date().toISOString()}:${process.pid}`
78
+ : undefined;
79
+ const baseSuffix = options.snapshotSuffix ??
80
+ (forceRevision ? `semantic-${sha256(forceRevision).slice(0, 12)}` : undefined);
81
+ const runtimeRevision = options.runtimeEvidenceRevision ?? (await this.collectRuntimeEvidence(commitSha));
82
+ if (runtimeRevision.commitSha !== commitSha) {
83
+ throw new Error('Runtime evidence revision does not match the hydration commit');
84
+ }
85
+ const runtimeSuffix = config.runtimeEvidence.length > 0
86
+ ? `runtime-${runtimeRevision.digest.slice(0, 12)}`
87
+ : undefined;
88
+ const configurationDigest = sha256(stableJson(config));
89
+ const scopeDigest = sha256(stableJson(selectedSemanticSources)).slice(0, 12);
90
+ const effectiveSuffix = ['graph-v2', configurationDigest.slice(0, 16), scopeDigest, baseSuffix, runtimeSuffix].filter(Boolean).join('-');
91
+ const snapshotId = effectiveSuffix ? `${commitSha}-${effectiveSuffix}` : commitSha;
92
+ const context = {
93
+ repositoryRoot: repository.root,
94
+ repositoryId: config.repositoryId,
95
+ ref: options.ref,
96
+ commitSha,
97
+ baseSha,
98
+ snapshotId,
99
+ changedPaths: delta.changedPaths,
100
+ deletedPaths: delta.deletedPaths,
101
+ renamedPaths: delta.renamedPaths,
102
+ semanticPaths: selectedSemanticSources,
103
+ };
104
+ const sources = await repository.semanticSources(context, selectedSemanticSources);
105
+ if (sources.length > (config.semantic.maxDocuments ?? 8) ||
106
+ sources.some((source) => Buffer.byteLength(source.content) > (config.semantic.maxSourceBytes ?? 65_536))) {
107
+ throw new Error('Semantic source budget exceeded before extraction; narrow scope or explicitly review configured limits');
108
+ }
109
+ const ids = new Set();
110
+ for (const source of sources) {
111
+ if (ids.has(source.stableSemanticId)) {
112
+ throw new Error(`Duplicate stable semantic ID: ${source.stableSemanticId}`);
113
+ }
114
+ ids.add(source.stableSemanticId);
115
+ }
116
+ let semanticExtracted = 0;
117
+ let semanticReused = 0;
118
+ const controller = new AbortController();
119
+ const signal = AbortSignal.any([controller.signal, ...(options.signal ? [options.signal] : [])]);
120
+ const hydrated = await concurrentMap(sources, config.semantic.concurrency, async (source) => {
121
+ let result;
122
+ try {
123
+ result = await this.dependencies.semanticHydrator.hydrate(source, context, forceRevision, { signal });
124
+ }
125
+ catch (error) {
126
+ controller.abort();
127
+ throw error;
128
+ }
129
+ if (result.reused)
130
+ semanticReused += 1;
131
+ else
132
+ semanticExtracted += 1;
133
+ options.onProgress?.({ phase: result.reused ? 'semantic-cache-hit' : 'semantic-extracted',
134
+ completed: semanticReused + semanticExtracted, total: sources.length });
135
+ return { source, ...result };
136
+ });
137
+ const artifacts = hydrated.map((result) => result.artifact);
138
+ const diagnostics = hydrated.flatMap(({ source, artifact }) => (artifact.diagnostics ?? []).map((item) => ({
139
+ ...item,
140
+ id: sha256(stableJson({ artifact: artifact.key, diagnostic: item.id, path: source.path })),
141
+ provenance: item.provenance.map((span) => ({
142
+ ...span,
143
+ path: source.path,
144
+ digest: source.digest,
145
+ commitSha,
146
+ })),
147
+ })));
148
+ const semanticFacts = hydrated.flatMap(({ source, artifact }) => artifact.facts.map((fact) => ({
149
+ ...fact,
150
+ id: sha256(stableJson({ artifact: artifact.key, fact: fact.id, path: source.path })),
151
+ provenance: {
152
+ ...fact.provenance,
153
+ path: source.path,
154
+ digest: source.digest,
155
+ commitSha,
156
+ },
157
+ snapshotId,
158
+ authority: 'inferred',
159
+ extractionReview: 'unreviewed',
160
+ sourceAuthority: (config.approvedIntentSources?.some((pattern) => matchesRepositoryGlob(source.path, pattern)) ? 'declared' : 'inferred'),
161
+ })));
162
+ options.signal?.throwIfAborted();
163
+ options.onProgress?.({ phase: 'index-typescript' });
164
+ const scip = await this.dependencies.staticIndexer.index(context);
165
+ const extractorFacts = (await Promise.all(this.dependencies.extractorFactory(scip).map((extractor) => extractor.extract(context)))).flat();
166
+ const trackedPaths = await repository.listAllFilesAt(commitSha);
167
+ const tracked = new Set(trackedPaths);
168
+ for (const fact of semanticFacts) {
169
+ for (const node of [fact.subject, fact.object]) {
170
+ const path = node.id.startsWith('component:file:') ? node.id.slice('component:file:'.length) : undefined;
171
+ if (path && !tracked.has(path))
172
+ diagnostics.push({
173
+ id: sha256(stableJson({ fact: fact.id, missing: path })),
174
+ kind: 'implementationGaps',
175
+ reason: `Cited implementation path ${path} is absent from the committed repository.`,
176
+ relatedNodeIds: [node.id], provenance: [fact.provenance], evidenceScope: 'snapshot-query',
177
+ });
178
+ }
179
+ }
180
+ const documentFacts = linkSemanticDocuments(context, hydrated, trackedPaths);
181
+ options.signal?.throwIfAborted();
182
+ options.onProgress?.({ phase: 'compile-semantic-rdf' });
183
+ const ontology = await this.dependencies.ontologyCompiler.compile(snapshotId, artifacts, context);
184
+ const runtimeEvidence = runtimeRevision.references;
185
+ const runtimeFacts = runtimeEvidenceFacts(context, runtimeEvidence);
186
+ const facts = [...semanticFacts, ...documentFacts, ...extractorFacts, ...runtimeFacts].sort((left, right) => left.id.localeCompare(right.id));
187
+ const invariants = (await Promise.all(this.dependencies.invariantEvaluators.map((evaluator) => evaluator.evaluate(snapshotId, facts)))).flat();
188
+ const failures = invariants.filter((invariant) => invariant.status === 'fail');
189
+ if (failures.length > 0) {
190
+ throw new Error(`Invariant validation failed: ${failures.map((failure) => failure.invariantId).join(', ')}`);
191
+ }
192
+ const unresolved = [
193
+ ...new Set([
194
+ ...artifacts.flatMap((artifact) => artifact.unresolvedMappings),
195
+ ...invariants
196
+ .filter((invariant) => invariant.status === 'unknown')
197
+ .map((invariant) => invariant.message),
198
+ ]),
199
+ ].sort();
200
+ const logical = {
201
+ repositoryId: config.repositoryId,
202
+ commitSha,
203
+ ontologyVersion: config.semantic.ontologyVersion,
204
+ semanticArtifactKeys: artifacts.map((artifact) => artifact.key).sort(),
205
+ scipIndexDigest: scip.digest,
206
+ rdfDigest: ontology.digest,
207
+ facts: facts.map(({ snapshotId: _snapshotId, ...fact }) => fact),
208
+ invariants,
209
+ runtimeEvidence,
210
+ unresolved,
211
+ diagnostics,
212
+ semanticSources: selectedSemanticSources,
213
+ };
214
+ const contentDigest = sha256(stableJson(logical));
215
+ const snapshot = {
216
+ manifest: {
217
+ schemaVersion: 1,
218
+ repositoryId: config.repositoryId,
219
+ ref: options.ref,
220
+ commitSha,
221
+ baseSha,
222
+ snapshotId,
223
+ configurationDigest,
224
+ scope: selectedSemanticSources,
225
+ ontologyVersion: config.semantic.ontologyVersion,
226
+ extractorVersions: {
227
+ assembly: 'standalone-graph-v2',
228
+ semantic: config.semantic.extractorVersion,
229
+ scip: scip.version,
230
+ ontology: config.ontology.toolVersion,
231
+ ...Object.fromEntries(this.dependencies
232
+ .extractorFactory(scip)
233
+ .map((extractor) => [extractor.identity.id, extractor.identity.version])),
234
+ },
235
+ semanticModel: config.semantic.model,
236
+ semanticPromptVersion: config.semantic.promptVersion,
237
+ generatedAt: new Date().toISOString(),
238
+ contentDigest,
239
+ runtimeEvidenceDigest: runtimeRevision.digest,
240
+ semanticArtifactKeys: artifacts.map((artifact) => artifact.key).sort(),
241
+ scipIndexDigest: scip.digest,
242
+ rdfDigest: ontology.digest,
243
+ },
244
+ facts,
245
+ invariants,
246
+ runtimeEvidence,
247
+ unresolved,
248
+ diagnostics,
249
+ };
250
+ options.signal?.throwIfAborted();
251
+ options.onProgress?.({ phase: 'validate-shacl' });
252
+ const validation = await new RdfEvidenceGraph(snapshot).validate();
253
+ if (!validation.conforms) {
254
+ throw new Error(`Graph extraction failed SHACL validation: ${JSON.stringify(validation.issues)}`);
255
+ }
256
+ options.onProgress?.({ phase: 'publish-snapshot' });
257
+ await snapshotStore.write(snapshot);
258
+ await snapshotStore.updateHead(options.headName, snapshotId);
259
+ return { snapshot, semanticExtracted, semanticReused };
260
+ }
261
+ async compareClean(options) {
262
+ const current = await this.dependencies.snapshotStore.readHead(options.headName);
263
+ if (!current)
264
+ throw new Error('No incremental snapshot exists to compare');
265
+ const clean = await this.hydrate({
266
+ ...options,
267
+ headName: `${options.headName}-clean`,
268
+ snapshotSuffix: `clean-${Date.now()}`,
269
+ });
270
+ if (clean.snapshot.manifest.contentDigest !== current.manifest.contentDigest) {
271
+ throw new Error(`Clean hydration drift: ${current.manifest.contentDigest} != ${clean.snapshot.manifest.contentDigest}`);
272
+ }
273
+ return clean;
274
+ }
275
+ }
@@ -0,0 +1,6 @@
1
+ import type { ContextGraphConfig } from "../configuration/config.js";
2
+ import type { GraphSnapshot } from "@weftlet/core";
3
+ import { GitRepository } from "../repository/git.js";
4
+ import { FileSnapshotStore } from "../storage/storage.js";
5
+ /** Conservative code overlay: reindex implementation; invalidate changed prose, never synthesize intent. */
6
+ export declare function buildWorkingOverlay(repository: GitRepository, config: ContextGraphConfig, store: FileSnapshotStore, storageRoot: string, baseSnapshotId: string, agent?: string): Promise<GraphSnapshot>;