@interf/compiler 0.33.0 → 0.50.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.
- package/README.md +122 -226
- package/dist/cli/commands/agents.js +1 -32
- package/dist/cli/commands/benchmark.d.ts +2 -3
- package/dist/cli/commands/benchmark.js +1 -31
- package/dist/cli/commands/build-plan.js +26 -50
- package/dist/cli/commands/build.d.ts +2 -3
- package/dist/cli/commands/build.js +1 -31
- package/dist/cli/commands/graphs.js +177 -32
- package/dist/cli/commands/mcp.d.ts +1 -0
- package/dist/cli/commands/mcp.js +223 -126
- package/dist/cli/commands/project.js +10 -36
- package/dist/cli/commands/reset.d.ts +2 -3
- package/dist/cli/commands/reset.js +1 -22
- package/dist/cli/commands/runs.js +86 -33
- package/dist/cli/commands/status.js +3 -24
- package/dist/cli/commands/traces.js +1 -29
- package/dist/cli/commands/wizard.js +17 -29
- package/dist/cli/lib/http-client.d.ts +39 -0
- package/dist/cli/lib/http-client.js +73 -0
- package/dist/packages/build-plans/authoring/brief.d.ts +25 -4
- package/dist/packages/build-plans/authoring/build-plan-authoring.d.ts +42 -1
- package/dist/packages/build-plans/authoring/build-plan-authoring.js +470 -63
- package/dist/packages/build-plans/authoring/build-plan-edit-session.d.ts +9 -0
- package/dist/packages/build-plans/authoring/build-plan-edit-session.js +27 -10
- package/dist/packages/build-plans/authoring/build-plan-improvement.js +62 -8
- package/dist/packages/build-plans/authoring/lib/build-plan-edit-utils.d.ts +1 -0
- package/dist/packages/build-plans/package/build-plan-definitions.d.ts +0 -1
- package/dist/packages/build-plans/package/build-plan-definitions.js +5 -3
- package/dist/packages/build-plans/package/build-plan-stage-runner.d.ts +1 -0
- package/dist/packages/build-plans/package/build-plan-stage-runner.js +2 -1
- package/dist/packages/build-plans/package/builtin-build-plan.d.ts +2 -2
- package/dist/packages/build-plans/package/builtin-build-plan.js +3 -3
- package/dist/packages/build-plans/package/context-interface.d.ts +3 -0
- package/dist/packages/build-plans/package/context-interface.js +5 -5
- package/dist/packages/build-plans/package/interf-build-plan-package.js +22 -22
- package/dist/packages/build-plans/package/local-build-plans.d.ts +10 -5
- package/dist/packages/build-plans/package/local-build-plans.js +57 -32
- package/dist/packages/contracts/index.d.ts +4 -3
- package/dist/packages/contracts/index.js +2 -1
- package/dist/packages/contracts/lib/context-graph-layer.d.ts +161 -0
- package/dist/packages/contracts/lib/context-graph-layer.js +216 -0
- package/dist/packages/contracts/lib/project-paths.d.ts +7 -0
- package/dist/packages/contracts/lib/project-paths.js +9 -0
- package/dist/packages/contracts/lib/project-schema.d.ts +264 -1
- package/dist/packages/contracts/lib/project-schema.js +38 -13
- package/dist/packages/contracts/lib/schema.d.ts +556 -23
- package/dist/packages/contracts/lib/schema.js +279 -18
- package/dist/packages/contracts/utils/filesystem.d.ts +1 -0
- package/dist/packages/contracts/utils/filesystem.js +29 -1
- package/dist/packages/projects/lib/schema.d.ts +6 -8
- package/dist/packages/projects/lib/schema.js +3 -1
- package/dist/packages/projects/source-config.d.ts +0 -5
- package/dist/packages/projects/source-config.js +9 -22
- package/dist/packages/runtime/actions/fields.d.ts +4 -0
- package/dist/packages/runtime/actions/form-builders.js +79 -31
- package/dist/packages/runtime/actions/form-validators.js +9 -3
- package/dist/packages/runtime/actions/helpers.js +3 -3
- package/dist/packages/runtime/actions/registry.d.ts +1 -1
- package/dist/packages/runtime/actions/registry.js +1 -1
- package/dist/packages/runtime/actions/requests.d.ts +1 -1
- package/dist/packages/runtime/actions/requests.js +12 -6
- package/dist/packages/runtime/actions/schemas.d.ts +7 -0
- package/dist/packages/runtime/actions/schemas.js +1 -0
- package/dist/packages/runtime/agent-handoff.js +8 -7
- package/dist/packages/runtime/agents/lib/execution-profile.d.ts +14 -0
- package/dist/packages/runtime/agents/lib/execution-profile.js +23 -0
- package/dist/packages/runtime/agents/lib/execution.js +14 -8
- package/dist/packages/runtime/agents/lib/executors.d.ts +1 -0
- package/dist/packages/runtime/agents/lib/executors.js +11 -2
- package/dist/packages/runtime/agents/lib/logs.d.ts +10 -0
- package/dist/packages/runtime/agents/lib/logs.js +32 -8
- package/dist/packages/runtime/agents/lib/preflight.js +4 -1
- package/dist/packages/runtime/agents/lib/render.d.ts +18 -0
- package/dist/packages/runtime/agents/lib/render.js +44 -18
- package/dist/packages/runtime/agents/lib/shell-templates.js +105 -63
- package/dist/packages/runtime/agents/lib/shells.d.ts +29 -0
- package/dist/packages/runtime/agents/lib/shells.js +158 -32
- package/dist/packages/runtime/agents/lib/source-context-scan.d.ts +10 -0
- package/dist/packages/runtime/agents/lib/source-context-scan.js +388 -0
- package/dist/packages/runtime/agents/lib/status.js +1 -14
- package/dist/packages/runtime/agents/lib/string-utils.d.ts +16 -0
- package/dist/packages/runtime/agents/lib/string-utils.js +36 -0
- package/dist/packages/runtime/agents/lib/types.d.ts +1 -0
- package/dist/packages/runtime/agents/providers/codex.js +2 -0
- package/dist/packages/runtime/agents/role-executors.js +2 -1
- package/dist/packages/runtime/auth/session-store.js +11 -3
- package/dist/packages/runtime/benchmark-question-draft.d.ts +3 -0
- package/dist/packages/runtime/benchmark-question-draft.js +57 -28
- package/dist/packages/runtime/build/artifact-status.d.ts +1 -1
- package/dist/packages/runtime/build/artifact-status.js +1 -1
- package/dist/packages/runtime/build/build-evidence.d.ts +2 -1
- package/dist/packages/runtime/build/build-evidence.js +11 -5
- package/dist/packages/runtime/build/build-pipeline.js +89 -5
- package/dist/packages/runtime/build/build-stage-plan.js +3 -1
- package/dist/packages/runtime/build/build-stage-runner.js +169 -32
- package/dist/packages/runtime/build/build-target.d.ts +3 -0
- package/dist/packages/runtime/build/build-target.js +25 -1
- package/dist/packages/runtime/build/check-evaluator.d.ts +1 -1
- package/dist/packages/runtime/build/check-evaluator.js +655 -4
- package/dist/packages/runtime/build/context-graph-paths.d.ts +13 -0
- package/dist/packages/runtime/build/context-graph-paths.js +27 -0
- package/dist/packages/runtime/build/index.d.ts +2 -2
- package/dist/packages/runtime/build/index.js +2 -2
- package/dist/packages/runtime/build/inspect-map.d.ts +10 -0
- package/dist/packages/runtime/build/inspect-map.js +270 -0
- package/dist/packages/runtime/build/lib/schema.d.ts +246 -53
- package/dist/packages/runtime/build/lib/schema.js +173 -15
- package/dist/packages/runtime/build/native-entrypoint.d.ts +2 -0
- package/dist/packages/runtime/build/native-entrypoint.js +286 -0
- package/dist/packages/runtime/build/runtime-contracts.js +9 -3
- package/dist/packages/runtime/build/runtime-log-paths.d.ts +3 -0
- package/dist/packages/runtime/build/runtime-log-paths.js +16 -0
- package/dist/packages/runtime/build/runtime-prompt.js +6 -4
- package/dist/packages/runtime/build/runtime-runs.js +63 -10
- package/dist/packages/runtime/build/runtime-types.d.ts +4 -1
- package/dist/packages/runtime/build/runtime.d.ts +3 -1
- package/dist/packages/runtime/build/runtime.js +3 -1
- package/dist/packages/runtime/build/source-files.js +11 -2
- package/dist/packages/runtime/build/source-inventory.d.ts +1 -0
- package/dist/packages/runtime/build/source-inventory.js +246 -7
- package/dist/packages/runtime/build/source-manifest.d.ts +11 -0
- package/dist/packages/runtime/build/source-manifest.js +30 -2
- package/dist/packages/runtime/build/stage-evidence.js +80 -11
- package/dist/packages/runtime/build/stage-manifest.d.ts +45 -0
- package/dist/packages/runtime/build/stage-manifest.js +1125 -0
- package/dist/packages/runtime/build/stage-reuse.js +12 -0
- package/dist/packages/runtime/build/stage-session.d.ts +81 -0
- package/dist/packages/runtime/build/stage-session.js +308 -0
- package/dist/packages/runtime/build/state-io.js +10 -11
- package/dist/packages/runtime/build/state-view.js +1 -1
- package/dist/packages/runtime/build/state.d.ts +1 -1
- package/dist/packages/runtime/build/state.js +1 -1
- package/dist/packages/runtime/build/summary-coverage-index.d.ts +21 -0
- package/dist/packages/runtime/build/summary-coverage-index.js +189 -0
- package/dist/packages/runtime/build/traces.js +3 -3
- package/dist/packages/runtime/build/validate-context-graph.d.ts +1 -1
- package/dist/packages/runtime/build/validate-context-graph.js +5 -5
- package/dist/packages/runtime/build/validate.d.ts +1 -1
- package/dist/packages/runtime/build/validate.js +1 -1
- package/dist/packages/runtime/client.d.ts +3 -3
- package/dist/packages/runtime/client.js +8 -13
- package/dist/packages/runtime/context-checks.js +13 -0
- package/dist/packages/runtime/context-graph-scaffold.js +2 -1
- package/dist/packages/runtime/context-graph-semantic-graph.d.ts +9 -0
- package/dist/packages/runtime/context-graph-semantic-graph.js +416 -0
- package/dist/packages/runtime/execution/lib/schema.d.ts +34 -31
- package/dist/packages/runtime/index.d.ts +2 -2
- package/dist/packages/runtime/index.js +1 -1
- package/dist/packages/runtime/native-run-handlers.d.ts +38 -0
- package/dist/packages/runtime/native-run-handlers.js +52 -33
- package/dist/packages/runtime/plan-artifact-contract.js +1 -1
- package/dist/packages/runtime/project-source-state.d.ts +4 -4
- package/dist/packages/runtime/project-source-state.js +5 -2
- package/dist/packages/runtime/project-store.d.ts +5 -0
- package/dist/packages/runtime/project-store.js +30 -3
- package/dist/packages/runtime/requested-artifacts.js +1 -1
- package/dist/packages/runtime/run-observability.js +9 -4
- package/dist/packages/runtime/runtime-action-proposals.js +3 -3
- package/dist/packages/runtime/runtime-build-plans.js +47 -3
- package/dist/packages/runtime/runtime-build-runs.js +9 -16
- package/dist/packages/runtime/runtime-caches.d.ts +26 -0
- package/dist/packages/runtime/runtime-caches.js +47 -0
- package/dist/packages/runtime/runtime-jobs.js +6 -6
- package/dist/packages/runtime/runtime-project-mutations.js +1 -0
- package/dist/packages/runtime/runtime-project-reads.d.ts +4 -1
- package/dist/packages/runtime/runtime-project-reads.js +229 -36
- package/dist/packages/runtime/runtime-proposal-helpers.js +6 -6
- package/dist/packages/runtime/runtime-resource-builders.d.ts +4 -2
- package/dist/packages/runtime/runtime-resource-builders.js +16 -14
- package/dist/packages/runtime/runtime-status.d.ts +14 -0
- package/dist/packages/runtime/runtime-status.js +15 -0
- package/dist/packages/runtime/runtime-verify-runs.js +6 -5
- package/dist/packages/runtime/runtime.d.ts +439 -22
- package/dist/packages/runtime/runtime.js +16 -2
- package/dist/packages/runtime/schemas/actions.d.ts +24 -0
- package/dist/packages/runtime/schemas/agents.d.ts +28 -0
- package/dist/packages/runtime/schemas/agents.js +33 -0
- package/dist/packages/runtime/schemas/build-plans.d.ts +181 -8
- package/dist/packages/runtime/schemas/build-plans.js +36 -2
- package/dist/packages/runtime/schemas/context-graphs.d.ts +1522 -0
- package/dist/packages/runtime/schemas/context-graphs.js +110 -0
- package/dist/packages/runtime/schemas/files.d.ts +7 -347
- package/dist/packages/runtime/schemas/files.js +1 -24
- package/dist/packages/runtime/schemas/index.d.ts +1 -0
- package/dist/packages/runtime/schemas/index.js +1 -0
- package/dist/packages/runtime/schemas/jobs.js +4 -0
- package/dist/packages/runtime/schemas/projects.d.ts +48 -21
- package/dist/packages/runtime/schemas/projects.js +34 -10
- package/dist/packages/runtime/schemas/runs.d.ts +1009 -240
- package/dist/packages/runtime/schemas/runs.js +17 -0
- package/dist/packages/runtime/service/openapi.js +1 -0
- package/dist/packages/runtime/service/operations.d.ts +1666 -145
- package/dist/packages/runtime/service/operations.js +147 -17
- package/dist/packages/runtime/service/routes.d.ts +11 -3
- package/dist/packages/runtime/service/routes.js +11 -3
- package/dist/packages/runtime/service/server-app-boot.js +2 -2
- package/dist/packages/runtime/service/server-helpers.d.ts +11 -0
- package/dist/packages/runtime/service/server-helpers.js +19 -0
- package/dist/packages/runtime/service/server-routes-action-proposals.js +4 -2
- package/dist/packages/runtime/service/server-routes-agents.js +19 -85
- package/dist/packages/runtime/service/server-routes-build-plans.js +14 -11
- package/dist/packages/runtime/service/server-routes-project-context.js +102 -7
- package/dist/packages/runtime/service/server-routes-project-jobs.js +19 -12
- package/dist/packages/runtime/service/server-routes-project-runs.js +5 -2
- package/dist/packages/runtime/service/server-routes-projects.js +6 -2
- package/dist/packages/runtime/service/server-routes-runs.js +11 -4
- package/dist/packages/runtime/verify/lib/schema.js +12 -0
- package/dist/packages/runtime/verify/test-file-guard.d.ts +2 -0
- package/dist/packages/runtime/verify/test-file-guard.js +29 -0
- package/dist/packages/runtime/verify/verify-execution.d.ts +7 -0
- package/dist/packages/runtime/verify/verify-execution.js +109 -35
- package/dist/packages/runtime/verify/verify-paths.d.ts +1 -0
- package/dist/packages/runtime/verify/verify-paths.js +4 -0
- package/dist/packages/runtime/verify/verify-specs.js +49 -39
- package/dist/packages/runtime/wire-schemas.d.ts +1 -1
- package/dist/packages/runtime/wire-schemas.js +1 -1
- package/package.json +2 -8
- package/public-repo/CONTRIBUTING.md +10 -3
- package/public-repo/README.md +122 -226
- package/public-repo/build-plans/interf-default/README.md +15 -12
- package/public-repo/build-plans/interf-default/build/stages/entrypoint/SKILL.md +74 -0
- package/public-repo/build-plans/interf-default/build/stages/knowledge/SKILL.md +95 -0
- package/public-repo/build-plans/interf-default/build/stages/summarize/SKILL.md +38 -5
- package/public-repo/build-plans/interf-default/build-plan.json +27 -23
- package/public-repo/build-plans/interf-default/build-plan.schema.json +24 -20
- package/public-repo/build-plans/interf-default/use/query/SKILL.md +8 -7
- package/public-repo/openapi/local-service.openapi.json +11637 -4213
- package/public-repo/skills/interf/SKILL.md +174 -134
- package/dist/packages/runtime/build/runtime-paths.d.ts +0 -8
- package/dist/packages/runtime/build/runtime-paths.js +0 -26
- package/dist/packages/runtime/build/state-paths.d.ts +0 -7
- package/dist/packages/runtime/build/state-paths.js +0 -22
- package/public-repo/build-plans/interf-default/build/stages/shape/SKILL.md +0 -34
- package/public-repo/build-plans/interf-default/build/stages/structure/SKILL.md +0 -28
|
@@ -7,9 +7,11 @@ import { readJsonFileUnchecked, readJsonFileWithSchema } from "../../contracts/u
|
|
|
7
7
|
import { isMarkdownFile } from "../../contracts/utils/file-types.js";
|
|
8
8
|
import { BuildPlanRuntimeApiSchema, BuildPlanPurposeSchema, BuildPlanStageArtifactReadAccessSchema, BuildPlanStageArtifactWriteAccessSchema, } from "../../runtime/build/lib/schema.js";
|
|
9
9
|
import { RuntimeContractTypeSchema, InterfIdPattern, } from "../../contracts/lib/schema.js";
|
|
10
|
+
import { CANONICAL_LAYER_DIRS, } from "../../contracts/lib/context-graph-layer.js";
|
|
10
11
|
import { asProjectDataDir, projectBuildPlansRoot, } from "../../contracts/lib/project-paths.js";
|
|
11
12
|
import { CONTEXT_INTERFACE_FILE, ContextInterfaceSchema, contextInterfaceExists, contextInterfaceFilePath, listContextInterfaceArtifacts, readContextInterface, BuildPlanInputSpecSchema, writeContextInterface, } from "./context-interface.js";
|
|
12
13
|
import { BuildPlanAuthoringBriefSchema, } from "../authoring/brief.js";
|
|
14
|
+
import { DEFAULT_BUILD_PLAN_ID } from "../build-plan-resolution.js";
|
|
13
15
|
import { PACKAGE_ROOT } from "./lib/package-root.js";
|
|
14
16
|
const LocalBuildPlanStageDefinitionSchema = z.object({
|
|
15
17
|
id: z.string().regex(InterfIdPattern),
|
|
@@ -73,16 +75,20 @@ export function builtinBuildPlanPackagePath(buildPlanId) {
|
|
|
73
75
|
export function buildPlanDefinitionPath(projectDataDir, id) {
|
|
74
76
|
return join(buildPlanRootPath(projectDataDir), id);
|
|
75
77
|
}
|
|
78
|
+
// The single, readable list of which package-relative docs `collectStarterDocs`
|
|
79
|
+
// and `buildPlanPackageCopyPaths` treat as portable starter docs: the package
|
|
80
|
+
// README plus the three authoring-doc trees. A relative path qualifies when it
|
|
81
|
+
// equals or lives under one of these entries.
|
|
82
|
+
const SUPPORTED_STARTER_DOC_PATHS = [
|
|
83
|
+
"README.md",
|
|
84
|
+
"improve/",
|
|
85
|
+
"use/query/",
|
|
86
|
+
"build/stages/",
|
|
87
|
+
];
|
|
76
88
|
function isSupportedBuildPlanStarterDocPath(relativePath) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return true;
|
|
81
|
-
if (relativePath.startsWith("use/query/"))
|
|
82
|
-
return true;
|
|
83
|
-
if (relativePath.startsWith("build/stages/"))
|
|
84
|
-
return true;
|
|
85
|
-
return false;
|
|
89
|
+
return SUPPORTED_STARTER_DOC_PATHS.some((supported) => supported.endsWith("/")
|
|
90
|
+
? relativePath.startsWith(supported)
|
|
91
|
+
: relativePath === supported);
|
|
86
92
|
}
|
|
87
93
|
function collectStarterDocs(dirPath) {
|
|
88
94
|
return listFilesRecursive(dirPath, isMarkdownFile)
|
|
@@ -92,7 +98,11 @@ function collectStarterDocs(dirPath) {
|
|
|
92
98
|
relativePath,
|
|
93
99
|
content: readFileSync(join(dirPath, relativePath), "utf8"),
|
|
94
100
|
}))
|
|
95
|
-
|
|
101
|
+
// Codepoint order, not locale order: starter-doc ordering must be
|
|
102
|
+
// deterministic across machines (full vs small ICU, LANG/LC_ALL). With
|
|
103
|
+
// localeCompare, "README.md" sorts before lowercase paths in some locales
|
|
104
|
+
// and after in others, which made this collection environment-dependent.
|
|
105
|
+
.sort((a, b) => (a.relativePath < b.relativePath ? -1 : a.relativePath > b.relativePath ? 1 : 0));
|
|
96
106
|
}
|
|
97
107
|
function buildPlanPackageCopyPaths(dirPath) {
|
|
98
108
|
return [
|
|
@@ -188,7 +198,7 @@ export function resolveBuildPlanPackageSourcePath(projectDataDir, buildPlanId) {
|
|
|
188
198
|
return null;
|
|
189
199
|
}
|
|
190
200
|
export function seedLocalDefaultBuildPlan(options) {
|
|
191
|
-
const buildPlanId =
|
|
201
|
+
const buildPlanId = DEFAULT_BUILD_PLAN_ID;
|
|
192
202
|
const targetPath = buildPlanDefinitionPath(options.projectDataDir, buildPlanId);
|
|
193
203
|
if (existsSync(join(targetPath, "build-plan.json"))) {
|
|
194
204
|
return { buildPlanId, targetPath, alreadyExisted: true };
|
|
@@ -201,7 +211,7 @@ export function seedLocalDefaultBuildPlan(options) {
|
|
|
201
211
|
patchBuildPlanPackageMetadata(targetPath, {
|
|
202
212
|
id: buildPlanId,
|
|
203
213
|
label: "Built-in Interf Build Plan",
|
|
204
|
-
hint: "Built-in file-processing Build Plan: summarize source-grounded evidence,
|
|
214
|
+
hint: "Built-in file-processing Build Plan: summarize source-grounded evidence, build task-aware knowledge, and shape the Context Graph around the Project intent and coverage metrics.",
|
|
205
215
|
});
|
|
206
216
|
return { buildPlanId, targetPath, alreadyExisted: false };
|
|
207
217
|
}
|
|
@@ -392,7 +402,10 @@ export function validateBuildPlanPackage(dirPath) {
|
|
|
392
402
|
const longer = a.length <= b.length ? b : a;
|
|
393
403
|
return shorter.every((part, index) => longer[index] === part);
|
|
394
404
|
};
|
|
395
|
-
|
|
405
|
+
// Canonical required layer dirs come from the central layer model. Package
|
|
406
|
+
// validation is a strict-declaration context (it mirrors authoring), so it
|
|
407
|
+
// matches the exact lowercase dir name a Build Plan must declare.
|
|
408
|
+
const requiredLayerPaths = new Set(CANONICAL_LAYER_DIRS);
|
|
396
409
|
const isRequiredLayerArtifact = (artifact) => artifact.kind === "directory" && requiredLayerPaths.has(normalizedPathKey(artifact.path));
|
|
397
410
|
const allowsRequiredLayerContainment = (artifact, existingArtifact) => {
|
|
398
411
|
const artifactPath = normalizedPathKey(artifact.path);
|
|
@@ -405,58 +418,58 @@ export function validateBuildPlanPackage(dirPath) {
|
|
|
405
418
|
};
|
|
406
419
|
for (const artifact of schemaArtifacts) {
|
|
407
420
|
if (seenArtifactIds.has(artifact.id)) {
|
|
408
|
-
errors.push(`build-plan.schema.json repeats
|
|
421
|
+
errors.push(`build-plan.schema.json repeats requested output id "${artifact.id}".`);
|
|
409
422
|
}
|
|
410
423
|
seenArtifactIds.add(artifact.id);
|
|
411
424
|
const pathKey = normalizedPathKey(artifact.path);
|
|
412
425
|
const existingPathOwner = seenArtifactsByPath.get(pathKey);
|
|
413
426
|
if (existingPathOwner) {
|
|
414
|
-
errors.push(`build-plan.schema.json repeats
|
|
427
|
+
errors.push(`build-plan.schema.json repeats requested output path "${artifact.path}".`);
|
|
415
428
|
}
|
|
416
429
|
for (const existingArtifact of seenArtifactsByPath.values()) {
|
|
417
430
|
if (normalizedPathKey(existingArtifact.path) === pathKey)
|
|
418
431
|
continue;
|
|
419
432
|
if (hasOverlappingPath(artifact.path, existingArtifact.path) &&
|
|
420
433
|
!allowsRequiredLayerContainment(artifact, existingArtifact)) {
|
|
421
|
-
errors.push(`build-plan.schema.json
|
|
434
|
+
errors.push(`build-plan.schema.json requested outputs "${artifact.id}" and "${existingArtifact.id}" overlap on path "${artifact.path}" / "${existingArtifact.path}".`);
|
|
422
435
|
}
|
|
423
436
|
}
|
|
424
437
|
seenArtifactsByPath.set(pathKey, artifact);
|
|
425
438
|
for (const owner of artifact.owned_by) {
|
|
426
439
|
if (!stageIds.has(owner)) {
|
|
427
|
-
errors.push(`build-plan.schema.json references unknown stage "${owner}" for
|
|
440
|
+
errors.push(`build-plan.schema.json references unknown stage "${owner}" for requested output path "${artifact.path}".`);
|
|
428
441
|
continue;
|
|
429
442
|
}
|
|
430
443
|
const ownerStage = stages.find((stage) => stage.id === owner);
|
|
431
444
|
if (ownerStage && !ownerStage.writes.includes(artifact.id)) {
|
|
432
|
-
errors.push(`build-plan.schema.json
|
|
445
|
+
errors.push(`build-plan.schema.json requested output "${artifact.id}" is owned by stage "${owner}" but that stage does not write it in build-plan.json.`);
|
|
433
446
|
}
|
|
434
447
|
}
|
|
435
448
|
}
|
|
436
|
-
for (const requiredPath of
|
|
449
|
+
for (const requiredPath of CANONICAL_LAYER_DIRS) {
|
|
437
450
|
const artifact = seenArtifactsByPath.get(requiredPath);
|
|
438
451
|
if (!artifact) {
|
|
439
|
-
errors.push(`File-based Build Plan packages must declare a writable
|
|
452
|
+
errors.push(`File-based Build Plan packages must declare a writable requested output at "${requiredPath}".`);
|
|
440
453
|
continue;
|
|
441
454
|
}
|
|
442
455
|
if (artifact.owned_by.length === 0) {
|
|
443
|
-
errors.push(`File-based Build Plan
|
|
456
|
+
errors.push(`File-based Build Plan requested output "${artifact.id}" at "${requiredPath}" must be owned by at least one stage.`);
|
|
444
457
|
}
|
|
445
458
|
}
|
|
446
459
|
for (const stage of stages) {
|
|
447
460
|
for (const artifactId of stage.reads) {
|
|
448
461
|
if (!artifactById.has(artifactId)) {
|
|
449
|
-
errors.push(`Stage "${stage.id}" reads unknown
|
|
462
|
+
errors.push(`Stage "${stage.id}" reads unknown requested output "${artifactId}".`);
|
|
450
463
|
}
|
|
451
464
|
}
|
|
452
465
|
for (const artifactId of stage.writes) {
|
|
453
466
|
const artifact = artifactById.get(artifactId);
|
|
454
467
|
if (!artifact) {
|
|
455
|
-
errors.push(`Stage "${stage.id}" writes unknown
|
|
468
|
+
errors.push(`Stage "${stage.id}" writes unknown requested output "${artifactId}".`);
|
|
456
469
|
continue;
|
|
457
470
|
}
|
|
458
471
|
if (!artifact.owned_by.includes(stage.id)) {
|
|
459
|
-
errors.push(`Stage "${stage.id}" writes
|
|
472
|
+
errors.push(`Stage "${stage.id}" writes requested output "${artifactId}" but that output is not owned by the stage in build-plan.schema.json.`);
|
|
460
473
|
}
|
|
461
474
|
}
|
|
462
475
|
}
|
|
@@ -477,21 +490,33 @@ export function validateBuildPlanPackage(dirPath) {
|
|
|
477
490
|
counts,
|
|
478
491
|
};
|
|
479
492
|
}
|
|
480
|
-
|
|
493
|
+
/**
|
|
494
|
+
* Explain WHY a `build-plan.schema.json` failed to read. Exported so the
|
|
495
|
+
* regression test can assert the corrected branch directly: a valid schema must
|
|
496
|
+
* return `[]` (no issues), an invalid one must return the concrete Zod issues.
|
|
497
|
+
* The previous inverted `if (parsed.success)` reported a VALID schema as
|
|
498
|
+
* "missing or invalid."
|
|
499
|
+
*/
|
|
500
|
+
export function describeContextInterfaceValidationIssues(dirPath) {
|
|
481
501
|
const buildPlanSchemaPath = contextInterfaceFilePath(dirPath);
|
|
482
502
|
if (!existsSync(buildPlanSchemaPath)) {
|
|
483
503
|
return ["build-plan.schema.json is missing."];
|
|
484
504
|
}
|
|
485
|
-
const raw = readJsonFileUnchecked(buildPlanSchemaPath, "Build Plan requested
|
|
505
|
+
const raw = readJsonFileUnchecked(buildPlanSchemaPath, "Build Plan requested output contract");
|
|
486
506
|
if (raw === null) {
|
|
487
507
|
return ["build-plan.schema.json is invalid JSON."];
|
|
488
508
|
}
|
|
489
509
|
const parsed = ContextInterfaceSchema.safeParse(raw);
|
|
490
|
-
if (parsed.success) {
|
|
491
|
-
|
|
510
|
+
if (!parsed.success) {
|
|
511
|
+
// Invalid schema: surface the concrete Zod issues. Matches the sibling
|
|
512
|
+
// `readContextInterface` (context-interface.ts:174), which treats
|
|
513
|
+
// `!parsed.success` as the failure case. The previous `if (parsed.success)`
|
|
514
|
+
// was inverted and reported a VALID schema as "missing or invalid."
|
|
515
|
+
return parsed.error.issues.map((issue) => {
|
|
516
|
+
const path = issue.path.length > 0 ? issue.path.join(".") : "<root>";
|
|
517
|
+
return `build-plan.schema.json ${path}: ${issue.message}`;
|
|
518
|
+
});
|
|
492
519
|
}
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
return `build-plan.schema.json ${path}: ${issue.message}`;
|
|
496
|
-
});
|
|
520
|
+
// A valid schema has no issues to describe.
|
|
521
|
+
return [];
|
|
497
522
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export * as schema from "./lib/schema.js";
|
|
2
2
|
export * as projectSchema from "./lib/project-schema.js";
|
|
3
|
-
export type { AgentRecord, AgentsRegistry, Artifact, ArtifactId, ArtifactShape, ArtifactStatus, CanonicalRole, Check, CheckKind, BuildCheckRow, BuildEvidenceIssueState, BuildEvidenceMetric, BuildEvidenceRef, BuildEvidenceResource, ContextCheck, ContextCheckDeclaration, ContextCheckProjection, ContextCheckStatus, GateStatus, Locator, LocatorKind, BuildPlanId, ProjectId, CheckResult, ReadinessGate, ReadinessStatus, Readiness, ReadyVerdict, RoleMap, RuntimeContractType, RuntimeExecutorInfo, RuntimeStage, RuntimeTargetType, Source, SourceFile, SourceFiles, SourceKind, SourceState, StageEvidence, StageEvidenceCount, StageEvidenceEdge, StageEvidenceItem, StageEvidenceOutputRef, StageEvidenceSourceRef, StageInput, StageInputs, StandardEvidenceFrontmatterKey, TestCaseExpect, TestTargetType, VerifyTargetResult, } from "./lib/schema.js";
|
|
4
|
-
export type { ContextGraph, ContextGraphLocator, DriftKind, ProjectName, ProjectSourceState, Trace, Traces, } from "./lib/project-schema.js";
|
|
5
|
-
export { CANONICAL_ROLES, CHECK_PARAM_CONTRACTS, CHECK_KINDS, ContextCheckDeclarationSchema, ContextCheckProjectionSchema, ContextCheckSchema, ContextCheckStatusSchema, BuildCheckRowSchema, BuildEvidenceIssueStateSchema, BuildEvidenceMetricSchema, BuildEvidenceRefSchema, BuildEvidenceResourceSchema, EvidenceCountKeySchema, StageEvidenceCountSchema, StageEvidenceEdgeSchema, StageEvidenceItemSchema, StageEvidenceOutputRefSchema, StageEvidenceSchema, StageEvidenceSourceRefSchema, STANDARD_EVIDENCE_FRONTMATTER_KEYS, } from "./lib/schema.js";
|
|
3
|
+
export type { AgentRecord, AgentsRegistry, Artifact, ArtifactId, ArtifactShape, ArtifactStatus, CanonicalRole, Check, CheckKind, BuildCheckRow, BuildEvidenceIssueState, BuildEvidenceMetric, BuildEvidenceRef, BuildEvidenceResource, ContextCheck, ContextCheckDeclaration, ContextCheckProjection, ContextCheckStatus, GateStatus, Locator, LocatorKind, BuildPlanId, ProjectId, ProjectIntent, CheckResult, ReadinessGate, ReadinessStatus, Readiness, ReadyVerdict, RoleMap, RuntimeContractType, RuntimeExecutorInfo, RuntimeStage, RuntimeTargetType, Source, SourceBinding, SourceFile, SourceFiles, SourceKind, SourceState, StageEvidence, StageEvidenceCount, StageEvidenceEdge, StageEvidenceItem, StageEvidenceOutputRef, StageEvidenceSourceRef, StageInput, StageInputs, StandardEvidenceFrontmatterKey, TestCaseExpect, TestTargetType, VerifyTargetResult, } from "./lib/schema.js";
|
|
4
|
+
export type { ContextGraph, ContextGraphArtifactHandoff, ContextGraphHandoff, ContextGraphLocator, ContextGraphPortableHandoff, DriftKind, ProjectName, ProjectSourceState, Trace, Traces, } from "./lib/project-schema.js";
|
|
5
|
+
export { CANONICAL_ROLES, CHECK_PARAM_CONTRACTS, CHECK_KINDS, ContextCheckDeclarationSchema, ContextCheckProjectionSchema, ContextCheckSchema, ContextCheckStatusSchema, ProjectIntentSchema, SourceBindingSchema, BuildCheckRowSchema, BuildEvidenceIssueStateSchema, BuildEvidenceMetricSchema, BuildEvidenceRefSchema, BuildEvidenceResourceSchema, EvidenceCountKeySchema, StageEvidenceCountSchema, StageEvidenceEdgeSchema, StageEvidenceItemSchema, StageEvidenceOutputRefSchema, StageEvidenceSchema, StageEvidenceSourceRefSchema, STANDARD_EVIDENCE_FRONTMATTER_KEYS, } from "./lib/schema.js";
|
|
6
|
+
export { ContextGraphArtifactHandoffSchema, ContextGraphHandoffSchema, ContextGraphPortableHandoffSchema, } from "./lib/project-schema.js";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export * as schema from "./lib/schema.js";
|
|
2
2
|
export * as projectSchema from "./lib/project-schema.js";
|
|
3
|
-
export { CANONICAL_ROLES, CHECK_PARAM_CONTRACTS, CHECK_KINDS, ContextCheckDeclarationSchema, ContextCheckProjectionSchema, ContextCheckSchema, ContextCheckStatusSchema, BuildCheckRowSchema, BuildEvidenceIssueStateSchema, BuildEvidenceMetricSchema, BuildEvidenceRefSchema, BuildEvidenceResourceSchema, EvidenceCountKeySchema, StageEvidenceCountSchema, StageEvidenceEdgeSchema, StageEvidenceItemSchema, StageEvidenceOutputRefSchema, StageEvidenceSchema, StageEvidenceSourceRefSchema, STANDARD_EVIDENCE_FRONTMATTER_KEYS, } from "./lib/schema.js";
|
|
3
|
+
export { CANONICAL_ROLES, CHECK_PARAM_CONTRACTS, CHECK_KINDS, ContextCheckDeclarationSchema, ContextCheckProjectionSchema, ContextCheckSchema, ContextCheckStatusSchema, ProjectIntentSchema, SourceBindingSchema, BuildCheckRowSchema, BuildEvidenceIssueStateSchema, BuildEvidenceMetricSchema, BuildEvidenceRefSchema, BuildEvidenceResourceSchema, EvidenceCountKeySchema, StageEvidenceCountSchema, StageEvidenceEdgeSchema, StageEvidenceItemSchema, StageEvidenceOutputRefSchema, StageEvidenceSchema, StageEvidenceSourceRefSchema, STANDARD_EVIDENCE_FRONTMATTER_KEYS, } from "./lib/schema.js";
|
|
4
|
+
export { ContextGraphArtifactHandoffSchema, ContextGraphHandoffSchema, ContextGraphPortableHandoffSchema, } from "./lib/project-schema.js";
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* The Context Graph layer model — defined ONCE here and imported by every
|
|
4
|
+
* consumer (Build Plan authoring validation, package validation, StageManifest
|
|
5
|
+
* role inference, the graph-relative link scanner, and the deterministic check
|
|
6
|
+
* defaults). This is the single source of truth for "what are the canonical
|
|
7
|
+
* top-level layers of a Context Graph, and how does a path classify into one."
|
|
8
|
+
*
|
|
9
|
+
* The architecture is FIXED top-level layers / FLEXIBLE interior:
|
|
10
|
+
* - `summaries/` — the grounding/coverage layer (one folder per Source file).
|
|
11
|
+
* - `knowledge/` — the knowledge graph layer; its interior is free
|
|
12
|
+
* (`knowledge/claims/`, `knowledge/entities/`, `knowledge/timelines/`, …).
|
|
13
|
+
* - `artifacts/` — task handoffs / supplemental entrypoints.
|
|
14
|
+
* - `home.md` — the primary entrypoint spine file (exact, no children).
|
|
15
|
+
*
|
|
16
|
+
* Two faces, one definition:
|
|
17
|
+
* - The canonical lowercase set (`CANONICAL_LAYER_DIRS`, `CanonicalLayerSchema`,
|
|
18
|
+
* `isCanonicalLayerDeclaration`) is what a Build Plan may DECLARE. Authoring
|
|
19
|
+
* is strict: a layer must be declared in exact lowercase (`knowledge/`, not
|
|
20
|
+
* `Knowledge/`).
|
|
21
|
+
* - The tolerant classifier (`layerForPath`, `roleForLayerPath`) is DEFENSIVE
|
|
22
|
+
* POLICING of already-built (possibly hand-edited or bad) outputs. It is
|
|
23
|
+
* case-insensitive so a graph that shipped `Knowledge/` notes is still
|
|
24
|
+
* routed into the knowledge layer and still policed by the orphan / web
|
|
25
|
+
* gates — casing can never be used to dodge a gate. Classification only ever
|
|
26
|
+
* widens membership; it never narrows it.
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* The three canonical top-level DIRECTORY layers, in lockstep lowercase. These
|
|
30
|
+
* are the only top-level folders a Build Plan may declare for core derived
|
|
31
|
+
* content. `home.md` is the spine FILE and is handled separately (it is not a
|
|
32
|
+
* directory layer).
|
|
33
|
+
*/
|
|
34
|
+
export declare const CANONICAL_LAYER_DIRS: readonly ["summaries", "knowledge", "artifacts"];
|
|
35
|
+
export type CanonicalLayerDir = (typeof CANONICAL_LAYER_DIRS)[number];
|
|
36
|
+
/**
|
|
37
|
+
* Set form of the canonical directory layers, for membership tests at call
|
|
38
|
+
* sites (authoring guard, package validation) that previously hand-rolled their
|
|
39
|
+
* own `new Set(["summaries", "knowledge", "artifacts"])`.
|
|
40
|
+
*/
|
|
41
|
+
export declare const CANONICAL_LAYER_DIR_SET: ReadonlySet<CanonicalLayerDir>;
|
|
42
|
+
/**
|
|
43
|
+
* The canonical layer "label" a path resolves to. Mirrors the directory layers
|
|
44
|
+
* plus `home` (the spine) and `other` (anything outside the canonical
|
|
45
|
+
* skeleton). This is the layer identity used for role inference and per-layer
|
|
46
|
+
* rollups.
|
|
47
|
+
*/
|
|
48
|
+
export declare const CanonicalLayerSchema: z.ZodEnum<{
|
|
49
|
+
other: "other";
|
|
50
|
+
knowledge: "knowledge";
|
|
51
|
+
summaries: "summaries";
|
|
52
|
+
artifacts: "artifacts";
|
|
53
|
+
home: "home";
|
|
54
|
+
}>;
|
|
55
|
+
export type CanonicalLayer = z.infer<typeof CanonicalLayerSchema>;
|
|
56
|
+
/**
|
|
57
|
+
* The exact spine file name. Canonical only as the top-level file `home.md`
|
|
58
|
+
* with no children.
|
|
59
|
+
*/
|
|
60
|
+
export declare const HOME_SPINE_FILE = "home.md";
|
|
61
|
+
/**
|
|
62
|
+
* Normalize a path to forward slashes with no leading `./` and no trailing
|
|
63
|
+
* slashes. Shared so every consumer normalizes identically before classifying
|
|
64
|
+
* — a layer must not depend on `\` vs `/` or a stray trailing separator.
|
|
65
|
+
*/
|
|
66
|
+
export declare function normalizeLayerPath(value: string): string;
|
|
67
|
+
/**
|
|
68
|
+
* The FIRST path segment of a normalized path (the top-level folder, or the
|
|
69
|
+
* file name when the path is a bare top-level file). Empty string for an empty
|
|
70
|
+
* path. Layer membership keys off this segment only, so the entire interior of
|
|
71
|
+
* `knowledge/` is unconstrained.
|
|
72
|
+
*/
|
|
73
|
+
export declare function topLevelSegment(value: string): string;
|
|
74
|
+
/**
|
|
75
|
+
* Is `segment` an EXACT canonical layer declaration a Build Plan may use? Used
|
|
76
|
+
* by authoring validation. Strict: `knowledge` passes, `Knowledge` does NOT.
|
|
77
|
+
* The mixed-case form is rejected at authoring so a declaration can never pass
|
|
78
|
+
* authoring and then break the lowercase-path-based package validators and
|
|
79
|
+
* runtime scanners downstream.
|
|
80
|
+
*/
|
|
81
|
+
export declare function isCanonicalLayerDeclaration(segment: string): boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Is this normalized top-level path a legal canonical DECLARATION? Accepts the
|
|
84
|
+
* exact lowercase layer dirs (and their interiors, since only the first segment
|
|
85
|
+
* is checked) and the exact spine file `home.md`. Strict on case. A non-path
|
|
86
|
+
* artifact (no folder) is the caller's concern; this only judges path shape.
|
|
87
|
+
*/
|
|
88
|
+
export declare function isCanonicalDeclarationPath(rawPath: string): boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Classify any path into its canonical layer. Case-INSENSITIVE on the top-level
|
|
91
|
+
* segment: a custom plan (or a hand-edited output) writing notes into
|
|
92
|
+
* `Knowledge/` (or `Summaries/`/`Artifacts/`) still classifies into the right
|
|
93
|
+
* layer, so the orphan + web + connectivity gates can't be dodged by path
|
|
94
|
+
* casing. Canonical layers are lowercase; this only WIDENS membership, never
|
|
95
|
+
* narrows it, and is the single classifier every consumer (note role, stage
|
|
96
|
+
* role, disconnected/web checks, metrics) routes through.
|
|
97
|
+
*
|
|
98
|
+
* Returns `home` for the spine file, a directory layer for `summaries/`,
|
|
99
|
+
* `knowledge/`, `artifacts/`, and `other` for anything else.
|
|
100
|
+
*/
|
|
101
|
+
export declare function layerForPath(rawPath: string): CanonicalLayer;
|
|
102
|
+
/**
|
|
103
|
+
* The directory layer (or `null`) a check should scan for a given artifact
|
|
104
|
+
* target path. `home` and `other` have no scannable directory layer, so they
|
|
105
|
+
* return `null`; the three directory layers return their lowercase dir name.
|
|
106
|
+
* Used by the deterministic checks to derive their scan root from the artifact
|
|
107
|
+
* they are attached to instead of hardcoding a layer dir.
|
|
108
|
+
*/
|
|
109
|
+
export declare function layerDirForPath(rawPath: string): CanonicalLayerDir | null;
|
|
110
|
+
/**
|
|
111
|
+
* The fine-grained kind of a note INSIDE the knowledge layer, by the structural
|
|
112
|
+
* convention every consumer agreed on: a `knowledge/claims/` folder (or a
|
|
113
|
+
* `claim-` leaf) is a claim, `knowledge/entities/` (or `entity-`) an entity,
|
|
114
|
+
* `knowledge/indexes/` (or `index-`) an index. `null` means "knowledge note
|
|
115
|
+
* with no recognized sub-kind". This is the single definition both the
|
|
116
|
+
* StageManifest note-kind labels and the semantic-graph node kinds delegate to,
|
|
117
|
+
* so the `knowledge/claims/` / `claim-` rules can never drift between them.
|
|
118
|
+
*
|
|
119
|
+
* Only the STRUCTURAL rules live here (folder prefix + leaf-token prefix). The
|
|
120
|
+
* looser "leaf merely contains `index`" heuristic is intentionally NOT here; it
|
|
121
|
+
* is a semantic-graph display nicety, and folding it in would silently
|
|
122
|
+
* reclassify manifest note kinds. Case-insensitive, like the rest of this
|
|
123
|
+
* module, so casing can never dodge the classification.
|
|
124
|
+
*/
|
|
125
|
+
export type KnowledgeNoteKind = "claim" | "entity" | "index" | null;
|
|
126
|
+
export declare function knowledgeNoteKind(rawPath: string): KnowledgeNoteKind;
|
|
127
|
+
/**
|
|
128
|
+
* The ResourceRef role a canonical layer maps to. `summaries → summary`,
|
|
129
|
+
* `knowledge → knowledge`, `artifacts`/`home → entrypoint`, `other → other`.
|
|
130
|
+
* Kept here (next to the layer model) so manifest role inference and the layer
|
|
131
|
+
* classifier never drift apart. The string union is the same as
|
|
132
|
+
* `ResourceRoleSchema`'s layer-bearing members; it is intentionally a plain
|
|
133
|
+
* union so this module has no import cycle back into the big schema.
|
|
134
|
+
*/
|
|
135
|
+
export type ContextGraphLayerRole = "summary" | "knowledge" | "entrypoint" | "other";
|
|
136
|
+
export declare function roleForLayer(layer: CanonicalLayer): ContextGraphLayerRole;
|
|
137
|
+
/**
|
|
138
|
+
* Role for a produced-note path (or any graph-relative path), via the tolerant
|
|
139
|
+
* classifier. This is the single mapping `roleForPath` callers route through.
|
|
140
|
+
*/
|
|
141
|
+
export declare function roleForLayerPath(rawPath: string): ContextGraphLayerRole;
|
|
142
|
+
/**
|
|
143
|
+
* Role for a Build Plan artifact's WRITE path. A directory artifact declared as
|
|
144
|
+
* a bare layer token (`knowledge`, `summaries`, `artifacts`) carries no
|
|
145
|
+
* trailing segment; it is still classified as that layer because classification
|
|
146
|
+
* keys off the (case-insensitive) first segment. The `home`/`home.md` spine is
|
|
147
|
+
* the entrypoint. This makes a custom plan that writes artifact id "claims" to
|
|
148
|
+
* path `knowledge/` (or the bare token `knowledge`) still classify as the
|
|
149
|
+
* knowledge layer, with no reliance on stringly ids.
|
|
150
|
+
*/
|
|
151
|
+
export declare function roleForWritePath(rawPath: string): ContextGraphLayerRole;
|
|
152
|
+
/**
|
|
153
|
+
* Matches a graph-relative reference to a canonical layer note inside free text
|
|
154
|
+
* (note bodies): `summaries/…`, `knowledge/…`, `artifacts/…` (optionally ending
|
|
155
|
+
* `.md`), or the exact `home.md`, when bounded by whitespace/brackets/quotes.
|
|
156
|
+
* Derived from `CANONICAL_LAYER_DIRS` so the scanner and the layer model can
|
|
157
|
+
* never list different folders. A fresh RegExp is returned each call because the
|
|
158
|
+
* pattern is stateful (`/g`) and reusing one instance across `matchAll` loops
|
|
159
|
+
* would carry `lastIndex` between callers.
|
|
160
|
+
*/
|
|
161
|
+
export declare function graphRelativePathPattern(): RegExp;
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* The Context Graph layer model — defined ONCE here and imported by every
|
|
4
|
+
* consumer (Build Plan authoring validation, package validation, StageManifest
|
|
5
|
+
* role inference, the graph-relative link scanner, and the deterministic check
|
|
6
|
+
* defaults). This is the single source of truth for "what are the canonical
|
|
7
|
+
* top-level layers of a Context Graph, and how does a path classify into one."
|
|
8
|
+
*
|
|
9
|
+
* The architecture is FIXED top-level layers / FLEXIBLE interior:
|
|
10
|
+
* - `summaries/` — the grounding/coverage layer (one folder per Source file).
|
|
11
|
+
* - `knowledge/` — the knowledge graph layer; its interior is free
|
|
12
|
+
* (`knowledge/claims/`, `knowledge/entities/`, `knowledge/timelines/`, …).
|
|
13
|
+
* - `artifacts/` — task handoffs / supplemental entrypoints.
|
|
14
|
+
* - `home.md` — the primary entrypoint spine file (exact, no children).
|
|
15
|
+
*
|
|
16
|
+
* Two faces, one definition:
|
|
17
|
+
* - The canonical lowercase set (`CANONICAL_LAYER_DIRS`, `CanonicalLayerSchema`,
|
|
18
|
+
* `isCanonicalLayerDeclaration`) is what a Build Plan may DECLARE. Authoring
|
|
19
|
+
* is strict: a layer must be declared in exact lowercase (`knowledge/`, not
|
|
20
|
+
* `Knowledge/`).
|
|
21
|
+
* - The tolerant classifier (`layerForPath`, `roleForLayerPath`) is DEFENSIVE
|
|
22
|
+
* POLICING of already-built (possibly hand-edited or bad) outputs. It is
|
|
23
|
+
* case-insensitive so a graph that shipped `Knowledge/` notes is still
|
|
24
|
+
* routed into the knowledge layer and still policed by the orphan / web
|
|
25
|
+
* gates — casing can never be used to dodge a gate. Classification only ever
|
|
26
|
+
* widens membership; it never narrows it.
|
|
27
|
+
*/
|
|
28
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
29
|
+
// Canonical directory layers
|
|
30
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
31
|
+
/**
|
|
32
|
+
* The three canonical top-level DIRECTORY layers, in lockstep lowercase. These
|
|
33
|
+
* are the only top-level folders a Build Plan may declare for core derived
|
|
34
|
+
* content. `home.md` is the spine FILE and is handled separately (it is not a
|
|
35
|
+
* directory layer).
|
|
36
|
+
*/
|
|
37
|
+
export const CANONICAL_LAYER_DIRS = ["summaries", "knowledge", "artifacts"];
|
|
38
|
+
/**
|
|
39
|
+
* Set form of the canonical directory layers, for membership tests at call
|
|
40
|
+
* sites (authoring guard, package validation) that previously hand-rolled their
|
|
41
|
+
* own `new Set(["summaries", "knowledge", "artifacts"])`.
|
|
42
|
+
*/
|
|
43
|
+
export const CANONICAL_LAYER_DIR_SET = new Set(CANONICAL_LAYER_DIRS);
|
|
44
|
+
/**
|
|
45
|
+
* The canonical layer "label" a path resolves to. Mirrors the directory layers
|
|
46
|
+
* plus `home` (the spine) and `other` (anything outside the canonical
|
|
47
|
+
* skeleton). This is the layer identity used for role inference and per-layer
|
|
48
|
+
* rollups.
|
|
49
|
+
*/
|
|
50
|
+
export const CanonicalLayerSchema = z.enum([
|
|
51
|
+
"summaries",
|
|
52
|
+
"knowledge",
|
|
53
|
+
"artifacts",
|
|
54
|
+
"home",
|
|
55
|
+
"other",
|
|
56
|
+
]);
|
|
57
|
+
/**
|
|
58
|
+
* The exact spine file name. Canonical only as the top-level file `home.md`
|
|
59
|
+
* with no children.
|
|
60
|
+
*/
|
|
61
|
+
export const HOME_SPINE_FILE = "home.md";
|
|
62
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
63
|
+
// Path normalization
|
|
64
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
65
|
+
/**
|
|
66
|
+
* Normalize a path to forward slashes with no leading `./` and no trailing
|
|
67
|
+
* slashes. Shared so every consumer normalizes identically before classifying
|
|
68
|
+
* — a layer must not depend on `\` vs `/` or a stray trailing separator.
|
|
69
|
+
*/
|
|
70
|
+
export function normalizeLayerPath(value) {
|
|
71
|
+
return value
|
|
72
|
+
.replaceAll("\\", "/")
|
|
73
|
+
.replace(/^\.\/+/, "")
|
|
74
|
+
.replace(/\/+$/g, "");
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The FIRST path segment of a normalized path (the top-level folder, or the
|
|
78
|
+
* file name when the path is a bare top-level file). Empty string for an empty
|
|
79
|
+
* path. Layer membership keys off this segment only, so the entire interior of
|
|
80
|
+
* `knowledge/` is unconstrained.
|
|
81
|
+
*/
|
|
82
|
+
export function topLevelSegment(value) {
|
|
83
|
+
const normalized = normalizeLayerPath(value);
|
|
84
|
+
if (normalized.length === 0)
|
|
85
|
+
return "";
|
|
86
|
+
return normalized.split("/")[0] ?? "";
|
|
87
|
+
}
|
|
88
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
89
|
+
// Authoring face — strict, exact-lowercase declarations
|
|
90
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
91
|
+
/**
|
|
92
|
+
* Is `segment` an EXACT canonical layer declaration a Build Plan may use? Used
|
|
93
|
+
* by authoring validation. Strict: `knowledge` passes, `Knowledge` does NOT.
|
|
94
|
+
* The mixed-case form is rejected at authoring so a declaration can never pass
|
|
95
|
+
* authoring and then break the lowercase-path-based package validators and
|
|
96
|
+
* runtime scanners downstream.
|
|
97
|
+
*/
|
|
98
|
+
export function isCanonicalLayerDeclaration(segment) {
|
|
99
|
+
return CANONICAL_LAYER_DIRS.includes(segment);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Is this normalized top-level path a legal canonical DECLARATION? Accepts the
|
|
103
|
+
* exact lowercase layer dirs (and their interiors, since only the first segment
|
|
104
|
+
* is checked) and the exact spine file `home.md`. Strict on case. A non-path
|
|
105
|
+
* artifact (no folder) is the caller's concern; this only judges path shape.
|
|
106
|
+
*/
|
|
107
|
+
export function isCanonicalDeclarationPath(rawPath) {
|
|
108
|
+
const normalized = normalizeLayerPath(rawPath);
|
|
109
|
+
if (normalized.length === 0)
|
|
110
|
+
return false;
|
|
111
|
+
const segment = topLevelSegment(normalized);
|
|
112
|
+
// `home.md` is canonical only as the exact top-level spine file (no children).
|
|
113
|
+
if (segment === HOME_SPINE_FILE && normalized === segment)
|
|
114
|
+
return true;
|
|
115
|
+
return isCanonicalLayerDeclaration(segment);
|
|
116
|
+
}
|
|
117
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
118
|
+
// Policing face — tolerant, case-insensitive classification
|
|
119
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
120
|
+
/**
|
|
121
|
+
* Classify any path into its canonical layer. Case-INSENSITIVE on the top-level
|
|
122
|
+
* segment: a custom plan (or a hand-edited output) writing notes into
|
|
123
|
+
* `Knowledge/` (or `Summaries/`/`Artifacts/`) still classifies into the right
|
|
124
|
+
* layer, so the orphan + web + connectivity gates can't be dodged by path
|
|
125
|
+
* casing. Canonical layers are lowercase; this only WIDENS membership, never
|
|
126
|
+
* narrows it, and is the single classifier every consumer (note role, stage
|
|
127
|
+
* role, disconnected/web checks, metrics) routes through.
|
|
128
|
+
*
|
|
129
|
+
* Returns `home` for the spine file, a directory layer for `summaries/`,
|
|
130
|
+
* `knowledge/`, `artifacts/`, and `other` for anything else.
|
|
131
|
+
*/
|
|
132
|
+
export function layerForPath(rawPath) {
|
|
133
|
+
const lower = normalizeLayerPath(rawPath).toLowerCase();
|
|
134
|
+
if (lower.length === 0)
|
|
135
|
+
return "other";
|
|
136
|
+
if (lower === HOME_SPINE_FILE)
|
|
137
|
+
return "home";
|
|
138
|
+
const segment = lower.split("/")[0] ?? "";
|
|
139
|
+
if (CANONICAL_LAYER_DIRS.includes(segment)) {
|
|
140
|
+
return segment;
|
|
141
|
+
}
|
|
142
|
+
return "other";
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* The directory layer (or `null`) a check should scan for a given artifact
|
|
146
|
+
* target path. `home` and `other` have no scannable directory layer, so they
|
|
147
|
+
* return `null`; the three directory layers return their lowercase dir name.
|
|
148
|
+
* Used by the deterministic checks to derive their scan root from the artifact
|
|
149
|
+
* they are attached to instead of hardcoding a layer dir.
|
|
150
|
+
*/
|
|
151
|
+
export function layerDirForPath(rawPath) {
|
|
152
|
+
const layer = layerForPath(rawPath);
|
|
153
|
+
return layer === "home" || layer === "other" ? null : layer;
|
|
154
|
+
}
|
|
155
|
+
export function knowledgeNoteKind(rawPath) {
|
|
156
|
+
const normalized = normalizeLayerPath(rawPath).toLowerCase();
|
|
157
|
+
const leaf = normalized.split("/").pop() ?? "";
|
|
158
|
+
if (normalized.startsWith("knowledge/claims/") || leaf.startsWith("claim-"))
|
|
159
|
+
return "claim";
|
|
160
|
+
if (normalized.startsWith("knowledge/entities/") || leaf.startsWith("entity-"))
|
|
161
|
+
return "entity";
|
|
162
|
+
if (normalized.startsWith("knowledge/indexes/") || leaf.startsWith("index-"))
|
|
163
|
+
return "index";
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
export function roleForLayer(layer) {
|
|
167
|
+
switch (layer) {
|
|
168
|
+
case "summaries":
|
|
169
|
+
return "summary";
|
|
170
|
+
case "knowledge":
|
|
171
|
+
return "knowledge";
|
|
172
|
+
case "artifacts":
|
|
173
|
+
case "home":
|
|
174
|
+
return "entrypoint";
|
|
175
|
+
case "other":
|
|
176
|
+
return "other";
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Role for a produced-note path (or any graph-relative path), via the tolerant
|
|
181
|
+
* classifier. This is the single mapping `roleForPath` callers route through.
|
|
182
|
+
*/
|
|
183
|
+
export function roleForLayerPath(rawPath) {
|
|
184
|
+
return roleForLayer(layerForPath(rawPath));
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Role for a Build Plan artifact's WRITE path. A directory artifact declared as
|
|
188
|
+
* a bare layer token (`knowledge`, `summaries`, `artifacts`) carries no
|
|
189
|
+
* trailing segment; it is still classified as that layer because classification
|
|
190
|
+
* keys off the (case-insensitive) first segment. The `home`/`home.md` spine is
|
|
191
|
+
* the entrypoint. This makes a custom plan that writes artifact id "claims" to
|
|
192
|
+
* path `knowledge/` (or the bare token `knowledge`) still classify as the
|
|
193
|
+
* knowledge layer, with no reliance on stringly ids.
|
|
194
|
+
*/
|
|
195
|
+
export function roleForWritePath(rawPath) {
|
|
196
|
+
const path = normalizeLayerPath(rawPath);
|
|
197
|
+
if (path === "home" || path === HOME_SPINE_FILE)
|
|
198
|
+
return "entrypoint";
|
|
199
|
+
return roleForLayerPath(path);
|
|
200
|
+
}
|
|
201
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
202
|
+
// Graph-relative link scanner
|
|
203
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
204
|
+
/**
|
|
205
|
+
* Matches a graph-relative reference to a canonical layer note inside free text
|
|
206
|
+
* (note bodies): `summaries/…`, `knowledge/…`, `artifacts/…` (optionally ending
|
|
207
|
+
* `.md`), or the exact `home.md`, when bounded by whitespace/brackets/quotes.
|
|
208
|
+
* Derived from `CANONICAL_LAYER_DIRS` so the scanner and the layer model can
|
|
209
|
+
* never list different folders. A fresh RegExp is returned each call because the
|
|
210
|
+
* pattern is stateful (`/g`) and reusing one instance across `matchAll` loops
|
|
211
|
+
* would carry `lastIndex` between callers.
|
|
212
|
+
*/
|
|
213
|
+
export function graphRelativePathPattern() {
|
|
214
|
+
const dirs = CANONICAL_LAYER_DIRS.join("|");
|
|
215
|
+
return new RegExp(`(?:^|[\\s"'([{<])((?:${dirs})\\/[A-Za-z0-9._~!$&*+,;=:@%/-]+(?:\\.md)?|${HOME_SPINE_FILE.replace(".", "\\.")})(?=$|[\\s"'\`)\\]}>.,;:])`, "g");
|
|
216
|
+
}
|
|
@@ -103,6 +103,13 @@ export declare function projectRunContextGraphPath(projectDataDir: ProjectDataDi
|
|
|
103
103
|
export declare function projectServiceRoot(projectDataDir: ProjectDataDir): string;
|
|
104
104
|
/** `<project-data>/.service/jobs/`. */
|
|
105
105
|
export declare function projectServiceJobsRoot(projectDataDir: ProjectDataDir): string;
|
|
106
|
+
/**
|
|
107
|
+
* `<project-data>/.service/jobs/shells/` — preserved, inspectable execution
|
|
108
|
+
* shells for graph-less agent jobs (Build Plan draft/improve, benchmark-question
|
|
109
|
+
* draft). Each `LocalJobRun.result.shell_path` points at one frozen shell here,
|
|
110
|
+
* the graph-less analogue of a Context Graph's stage execution shells.
|
|
111
|
+
*/
|
|
112
|
+
export declare function projectServiceJobShellsRoot(projectDataDir: ProjectDataDir): string;
|
|
106
113
|
/** `<project-data>/.service/action-proposals/`. */
|
|
107
114
|
export declare function projectServiceActionProposalsRoot(projectDataDir: ProjectDataDir): string;
|
|
108
115
|
/** `<project-data>/.service/action-plans/`. */
|
|
@@ -140,6 +140,15 @@ export function projectServiceRoot(projectDataDir) {
|
|
|
140
140
|
export function projectServiceJobsRoot(projectDataDir) {
|
|
141
141
|
return join(projectServiceRoot(projectDataDir), SERVICE_JOBS_DIR);
|
|
142
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* `<project-data>/.service/jobs/shells/` — preserved, inspectable execution
|
|
145
|
+
* shells for graph-less agent jobs (Build Plan draft/improve, benchmark-question
|
|
146
|
+
* draft). Each `LocalJobRun.result.shell_path` points at one frozen shell here,
|
|
147
|
+
* the graph-less analogue of a Context Graph's stage execution shells.
|
|
148
|
+
*/
|
|
149
|
+
export function projectServiceJobShellsRoot(projectDataDir) {
|
|
150
|
+
return join(projectServiceJobsRoot(projectDataDir), "shells");
|
|
151
|
+
}
|
|
143
152
|
/** `<project-data>/.service/action-proposals/`. */
|
|
144
153
|
export function projectServiceActionProposalsRoot(projectDataDir) {
|
|
145
154
|
return join(projectServiceRoot(projectDataDir), SERVICE_ACTION_PROPOSALS_DIR);
|