@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
|
@@ -16,13 +16,11 @@ import { BuildRunCreateRequestSchema, BuildRunResourceSchema, LocalRunHandlerRes
|
|
|
16
16
|
import { uniqueArtifacts } from "./run-observability.js";
|
|
17
17
|
import { requireSelectedBuildPlan } from "./runtime-proposal-helpers.js";
|
|
18
18
|
import { readinessUpdatedEvent } from "./runtime-verify-runs.js";
|
|
19
|
+
import { isTerminalStatus } from "./runtime-status.js";
|
|
19
20
|
/** TTL for `POST .../build-runs` idempotency-key dedupe entries. */
|
|
20
21
|
const IDEMPOTENCY_TTL_MS = 60 * 60 * 1000;
|
|
21
22
|
/** Idempotency cache size at which to schedule an opportunistic prune. */
|
|
22
23
|
const IDEMPOTENCY_PRUNE_THRESHOLD = 64;
|
|
23
|
-
function isTerminalBuildRunStatus(status) {
|
|
24
|
-
return status === "succeeded" || status === "failed" || status === "cancelled";
|
|
25
|
-
}
|
|
26
24
|
function countsFromContextGraphState(state, contextGraphPath) {
|
|
27
25
|
const counts = {};
|
|
28
26
|
const sourceManifest = loadContextGraphSourceManifest(contextGraphPath);
|
|
@@ -60,9 +58,7 @@ export function listBuildRuns(runtime, projectDataDir) {
|
|
|
60
58
|
.flatMap((project) => listBuildRunsForProject(runtime, projectDataDir, project.name))).map((run) => BuildRunResourceSchema.parse({ run }));
|
|
61
59
|
}
|
|
62
60
|
export function listBuildRunsForProject(runtime, projectDataDir, projectName) {
|
|
63
|
-
return runtime.buildRunCache.get(projectDataDir, projectName, () =>
|
|
64
|
-
return byCreatedAtDesc(readBuildRunRecordsForProject(projectDataDir, projectName)).map((run) => hydrateBuildRunFromRuntime(runtime, projectDataDir, run));
|
|
65
|
-
}, (run) => run.run_id);
|
|
61
|
+
return runtime.buildRunCache.get(projectDataDir, projectName, () => byCreatedAtDesc(readBuildRunRecordsForProject(projectDataDir, projectName)), (run) => run.run_id);
|
|
66
62
|
}
|
|
67
63
|
export function getBuildRun(runtime, projectDataDir, runId) {
|
|
68
64
|
// Fast path: if the runId was seen during a recent listing, look up
|
|
@@ -143,7 +139,7 @@ export async function createBuildRun(runtime, projectDataDir, requestValue) {
|
|
|
143
139
|
events: [],
|
|
144
140
|
context_checks: buildPlanContextChecks({
|
|
145
141
|
brief: buildPlan.brief ?? null,
|
|
146
|
-
artifacts: buildPlan.contextInterface?.artifacts ??
|
|
142
|
+
artifacts: buildPlan.contextInterface?.artifacts ?? [],
|
|
147
143
|
}),
|
|
148
144
|
});
|
|
149
145
|
writeBuildRun(runtime, projectDataDir, run);
|
|
@@ -198,7 +194,7 @@ export function cancelBuildRun(runtime, runId) {
|
|
|
198
194
|
handle.cancelled = true;
|
|
199
195
|
handle.cancelledAt = cancelledAt;
|
|
200
196
|
const current = readBuildRun(handle.projectDataDir, runId);
|
|
201
|
-
if (current && !
|
|
197
|
+
if (current && !isTerminalStatus(current.status)) {
|
|
202
198
|
writeBuildRun(runtime, handle.projectDataDir, applyEventToBuildRun(current, {
|
|
203
199
|
type: "run.cancelled",
|
|
204
200
|
event_id: createRunEventId("event"),
|
|
@@ -352,12 +348,6 @@ async function runBuildInBackground(runtime, projectDataDir, request, context) {
|
|
|
352
348
|
export function readBuildRun(projectDataDir, runId) {
|
|
353
349
|
return readBuildRunAt(projectBuildRunPath(projectDataDir, runId));
|
|
354
350
|
}
|
|
355
|
-
function hydrateBuildRunFromRuntime(runtime, projectDataDir, run) {
|
|
356
|
-
if (!isTerminalBuildRunStatus(run.status))
|
|
357
|
-
return run;
|
|
358
|
-
refreshBuildRunFromRuntime(runtime, projectDataDir, run.context_graph_path, run.run_id);
|
|
359
|
-
return readBuildRun(projectDataDir, run.run_id) ?? run;
|
|
360
|
-
}
|
|
361
351
|
export function finalizeInterruptedBuildRuns(runtime, projectDataDir) {
|
|
362
352
|
let projects;
|
|
363
353
|
try {
|
|
@@ -368,7 +358,7 @@ export function finalizeInterruptedBuildRuns(runtime, projectDataDir) {
|
|
|
368
358
|
}
|
|
369
359
|
for (const project of projects) {
|
|
370
360
|
for (const run of readBuildRunRecordsForProject(projectDataDir, project.name)) {
|
|
371
|
-
if (
|
|
361
|
+
if (isTerminalStatus(run.status) || runtime.activeBuildRuns.has(run.run_id))
|
|
372
362
|
continue;
|
|
373
363
|
const timestamp = createRunEventTimestamp();
|
|
374
364
|
const interruptedRun = {
|
|
@@ -438,6 +428,9 @@ export function writeBuildRun(runtime, projectDataDir, run) {
|
|
|
438
428
|
// and the simpler model avoids fan-out bugs.
|
|
439
429
|
runtime.buildRunCache.invalidateProject(projectDataDir, run.project);
|
|
440
430
|
runtime.readinessCache.invalidateProject(projectDataDir, run.project);
|
|
431
|
+
// The Context Graph resource embeds the joined readiness verdict, so bust it
|
|
432
|
+
// whenever a Build run is written (build completion, refresh, cancel).
|
|
433
|
+
runtime.contextGraphResourceCache.invalidateProject(projectDataDir);
|
|
441
434
|
}
|
|
442
435
|
async function recordBuildRunEvent(runtime, projectDataDir, contextGraphPath, runId, event) {
|
|
443
436
|
const current = readBuildRun(projectDataDir, runId);
|
|
@@ -510,7 +503,7 @@ function refreshBuildRunFromRuntime(runtime, projectDataDir, contextGraphPath, r
|
|
|
510
503
|
next.context_checks = projectContextChecksForRun({
|
|
511
504
|
contextChecks: buildPlanContextChecks({
|
|
512
505
|
brief: buildPlan.brief ?? null,
|
|
513
|
-
artifacts: buildPlan.contextInterface?.artifacts ??
|
|
506
|
+
artifacts: buildPlan.contextInterface?.artifacts ?? [],
|
|
514
507
|
}),
|
|
515
508
|
artifactStatuses: next.artifacts,
|
|
516
509
|
});
|
|
@@ -89,3 +89,29 @@ export declare class ProjectSourceStateCache<TState> {
|
|
|
89
89
|
invalidateProject(projectId: string): void;
|
|
90
90
|
invalidateAll(): void;
|
|
91
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* Per-Build-run Context Graph resource cache.
|
|
94
|
+
*
|
|
95
|
+
* A succeeded Build's Context Graph is immutable: its on-disk folder
|
|
96
|
+
* (`graph-manifest.json`, source manifest, stage sessions, semantic graph) is
|
|
97
|
+
* frozen once the run reaches `succeeded`. Rebuilding the full
|
|
98
|
+
* `ContextGraphResource` — readiness join, semantic graph, build evidence,
|
|
99
|
+
* validation — on every read is the dominant cost of opening a built Project.
|
|
100
|
+
*
|
|
101
|
+
* The cache keys by `(projectDataDir, runId, manifestMtimeMs)`:
|
|
102
|
+
* - `runId` scopes a single Build's output.
|
|
103
|
+
* - `manifestMtimeMs` is the mtime of the Build's
|
|
104
|
+
* `.interf/runtime/graph-manifest.json`. It busts the entry if the graph is
|
|
105
|
+
* rebuilt or edited in place; a fresh Build produces a fresh `runId`, so
|
|
106
|
+
* those never collide either.
|
|
107
|
+
*
|
|
108
|
+
* Entries without a readable manifest mtime (mtime 0) are not cached — that
|
|
109
|
+
* only happens for an in-flight or malformed Build, where the resource is
|
|
110
|
+
* still changing and must be recomputed.
|
|
111
|
+
*/
|
|
112
|
+
export declare class ContextGraphResourceCache<TResource> {
|
|
113
|
+
private byKey;
|
|
114
|
+
get(projectDataDir: string, runId: string, manifestPath: string, compute: () => TResource): TResource;
|
|
115
|
+
invalidateProject(projectDataDir: string): void;
|
|
116
|
+
invalidateAll(): void;
|
|
117
|
+
}
|
|
@@ -217,3 +217,50 @@ export class ProjectSourceStateCache {
|
|
|
217
217
|
this.byProjectId.clear();
|
|
218
218
|
}
|
|
219
219
|
}
|
|
220
|
+
/**
|
|
221
|
+
* Per-Build-run Context Graph resource cache.
|
|
222
|
+
*
|
|
223
|
+
* A succeeded Build's Context Graph is immutable: its on-disk folder
|
|
224
|
+
* (`graph-manifest.json`, source manifest, stage sessions, semantic graph) is
|
|
225
|
+
* frozen once the run reaches `succeeded`. Rebuilding the full
|
|
226
|
+
* `ContextGraphResource` — readiness join, semantic graph, build evidence,
|
|
227
|
+
* validation — on every read is the dominant cost of opening a built Project.
|
|
228
|
+
*
|
|
229
|
+
* The cache keys by `(projectDataDir, runId, manifestMtimeMs)`:
|
|
230
|
+
* - `runId` scopes a single Build's output.
|
|
231
|
+
* - `manifestMtimeMs` is the mtime of the Build's
|
|
232
|
+
* `.interf/runtime/graph-manifest.json`. It busts the entry if the graph is
|
|
233
|
+
* rebuilt or edited in place; a fresh Build produces a fresh `runId`, so
|
|
234
|
+
* those never collide either.
|
|
235
|
+
*
|
|
236
|
+
* Entries without a readable manifest mtime (mtime 0) are not cached — that
|
|
237
|
+
* only happens for an in-flight or malformed Build, where the resource is
|
|
238
|
+
* still changing and must be recomputed.
|
|
239
|
+
*/
|
|
240
|
+
export class ContextGraphResourceCache {
|
|
241
|
+
byKey = new Map();
|
|
242
|
+
get(projectDataDir, runId, manifestPath, compute) {
|
|
243
|
+
const mtimeMs = safeStat(manifestPath)?.mtimeMs ?? 0;
|
|
244
|
+
// mtime 0 means the manifest is missing/unreadable — the graph is not yet
|
|
245
|
+
// a frozen, succeeded output, so recompute every time without caching.
|
|
246
|
+
if (mtimeMs === 0)
|
|
247
|
+
return compute();
|
|
248
|
+
const cacheKey = `${resolve(projectDataDir)}${runId}`;
|
|
249
|
+
const entry = this.byKey.get(cacheKey);
|
|
250
|
+
if (entry && entry.mtimeMs === mtimeMs)
|
|
251
|
+
return entry.value;
|
|
252
|
+
const value = compute();
|
|
253
|
+
this.byKey.set(cacheKey, { mtimeMs, value });
|
|
254
|
+
return value;
|
|
255
|
+
}
|
|
256
|
+
invalidateProject(projectDataDir) {
|
|
257
|
+
const prefix = `${resolve(projectDataDir)}`;
|
|
258
|
+
for (const key of this.byKey.keys()) {
|
|
259
|
+
if (key.startsWith(prefix))
|
|
260
|
+
this.byKey.delete(key);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
invalidateAll() {
|
|
264
|
+
this.byKey.clear();
|
|
265
|
+
}
|
|
266
|
+
}
|
|
@@ -7,10 +7,8 @@ import { createRunId } from "./runtime-resource-builders.js";
|
|
|
7
7
|
import { upsertProjectConfig, findProjectConfig, loadSourceFolderConfig, writeBenchmarkSpecsForProject, } from "../projects/source-config.js";
|
|
8
8
|
import { BuildPlanAuthoringRuntimeRequestSchema, BuildPlanAuthoringResultSchema, LocalJobEventAppendRequestSchema, LocalJobRunCreateRequestSchema, LocalJobRunResourceSchema, BenchmarkQuestionDraftRuntimeRequestSchema, BenchmarkQuestionDraftResultSchema, } from "./schemas/index.js";
|
|
9
9
|
import { artifactRequirementsForPlanAuthoring, requestedArtifactsForPlanAuthoring, } from "./plan-artifact-contract.js";
|
|
10
|
+
import { isTerminalStatus } from "./runtime-status.js";
|
|
10
11
|
const INTERRUPTED_JOB_RUN_MESSAGE = "Job interrupted because the local service stopped before the job reached a terminal state.";
|
|
11
|
-
function isTerminalJobStatus(status) {
|
|
12
|
-
return status === "succeeded" || status === "failed" || status === "cancelled";
|
|
13
|
-
}
|
|
14
12
|
export function listJobs(projectDataDir) {
|
|
15
13
|
return byCreatedAtDesc(listJsonFiles(localJobsRoot(projectDataDir))
|
|
16
14
|
.map(readLocalJobRunAt)
|
|
@@ -62,7 +60,7 @@ export function appendJobRunEvent(runtime, projectDataDir, runId, requestValue)
|
|
|
62
60
|
const current = getJob(projectDataDir, runId);
|
|
63
61
|
if (!current)
|
|
64
62
|
return null;
|
|
65
|
-
if (
|
|
63
|
+
if (isTerminalStatus(current.status))
|
|
66
64
|
return current;
|
|
67
65
|
const event = {
|
|
68
66
|
type: request.type,
|
|
@@ -349,6 +347,7 @@ async function runBuildPlanAuthoringInBackgroundInner(runtime, projectDataDir, r
|
|
|
349
347
|
runtime.readinessCache.invalidateProject(projectDataDir, selected.name);
|
|
350
348
|
runtime.buildRunCache.invalidateProject(projectDataDir, selected.name);
|
|
351
349
|
runtime.verifyRunCache.invalidateProject(projectDataDir, selected.name);
|
|
350
|
+
runtime.contextGraphResourceCache.invalidateProject(projectDataDir);
|
|
352
351
|
runtime.buildPlanListingCache.invalidate(projectDataDir);
|
|
353
352
|
selectedProject = selected.name;
|
|
354
353
|
}
|
|
@@ -418,13 +417,14 @@ export function writeJobRun(runtime, projectDataDir, run) {
|
|
|
418
417
|
if (run.project) {
|
|
419
418
|
// Some job runs (benchmark-question drafts) flip readiness state.
|
|
420
419
|
runtime.readinessCache.invalidateProject(projectDataDir, run.project);
|
|
420
|
+
runtime.contextGraphResourceCache.invalidateProject(projectDataDir);
|
|
421
421
|
}
|
|
422
422
|
}
|
|
423
423
|
export function setJobRunResult(runtime, projectDataDir, runId, result) {
|
|
424
424
|
const current = getJob(projectDataDir, runId);
|
|
425
425
|
if (!current)
|
|
426
426
|
return;
|
|
427
|
-
if (
|
|
427
|
+
if (isTerminalStatus(current.status))
|
|
428
428
|
return;
|
|
429
429
|
const normalizedResult = result && typeof result === "object" && !Array.isArray(result)
|
|
430
430
|
? result
|
|
@@ -436,7 +436,7 @@ export function setJobRunResult(runtime, projectDataDir, runId, result) {
|
|
|
436
436
|
}
|
|
437
437
|
export function finalizeInterruptedJobRuns(runtime, projectDataDir) {
|
|
438
438
|
for (const run of listJobs(projectDataDir)) {
|
|
439
|
-
if (
|
|
439
|
+
if (isTerminalStatus(run.status) || runtime.activeJobRuns.has(run.run_id))
|
|
440
440
|
continue;
|
|
441
441
|
const timestamp = createRunEventTimestamp();
|
|
442
442
|
const interruptedRun = LocalJobRunResourceSchema.parse({
|
|
@@ -23,6 +23,7 @@ export function applyReset(runtime, projectDataDir, requestValue) {
|
|
|
23
23
|
runtime.buildRunCache.invalidateProject(projectDataDir, request.project);
|
|
24
24
|
runtime.verifyRunCache.invalidateProject(projectDataDir, request.project);
|
|
25
25
|
runtime.readinessCache.invalidateProject(projectDataDir, request.project);
|
|
26
|
+
runtime.contextGraphResourceCache.invalidateProject(projectDataDir);
|
|
26
27
|
return ResetResultSchema.parse({
|
|
27
28
|
kind: "interf-reset-result",
|
|
28
29
|
version: 1,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type Readiness } from "../contracts/lib/schema.js";
|
|
2
|
-
import { type
|
|
2
|
+
import { type ContextGraphHandoff } from "../contracts/lib/project-schema.js";
|
|
3
|
+
import { type ProjectResource, type SourceFileResource, type ContextGraphResource, type StageExecutionSession } from "./schemas/index.js";
|
|
3
4
|
import type { ProjectConfig } from "../projects/lib/schema.js";
|
|
4
5
|
import type { LocalServiceRuntime } from "./runtime.js";
|
|
5
6
|
export declare function listProjects(runtime: LocalServiceRuntime, projectDataDir: string): ProjectResource[];
|
|
@@ -13,3 +14,5 @@ export declare function listSourceFiles(runtime: LocalServiceRuntime, projectDat
|
|
|
13
14
|
export declare function listContextGraphs(runtime: LocalServiceRuntime, projectDataDir: string, projectName?: string | null): ContextGraphResource[];
|
|
14
15
|
export declare function getContextGraph(runtime: LocalServiceRuntime, projectDataDir: string, graphId: string): ContextGraphResource | null;
|
|
15
16
|
export declare function getLatestContextGraph(runtime: LocalServiceRuntime, projectDataDir: string, projectName: string): ContextGraphResource | null;
|
|
17
|
+
export declare function listLatestContextGraphStageSessions(runtime: LocalServiceRuntime, projectDataDir: string, projectName: string): StageExecutionSession[];
|
|
18
|
+
export declare function getContextGraphHandoff(runtime: LocalServiceRuntime, projectDataDir: string, projectName: string): ContextGraphHandoff | null;
|
|
@@ -1,14 +1,21 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
2
|
-
import {
|
|
1
|
+
import { existsSync, statSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { asProjectDataDir, projectConfigPath, projectRunContextGraphPath, } from "../contracts/lib/project-paths.js";
|
|
4
|
+
import { layerForPath } from "../contracts/lib/context-graph-layer.js";
|
|
3
5
|
import { buildPlanIdForProjectConfig, buildTestSpecFromSourceFolderConfig, fingerprintSavedBenchmarkSpec, findProjectConfig, listProjectConfigs, loadSourceFolderConfig, resolveProjectSourceBindingPath, } from "../projects/source-config.js";
|
|
4
|
-
import { ReadinessSchema, } from "../contracts/lib/schema.js";
|
|
6
|
+
import { isInterfRelativePath, ReadinessSchema, } from "../contracts/lib/schema.js";
|
|
7
|
+
import { ContextGraphHandoffSchema, } from "../contracts/lib/project-schema.js";
|
|
5
8
|
import { readInterfConfig, } from "../projects/interf.js";
|
|
6
9
|
import { loadContextGraphSourceManifest, } from "./build/source-manifest.js";
|
|
7
|
-
import {
|
|
10
|
+
import { loadGraphManifest, } from "./build/stage-manifest.js";
|
|
11
|
+
import { contextGraphRuntimeGraphManifestPath, } from "./build/context-graph-paths.js";
|
|
12
|
+
import { listStageExecutionSessions, } from "./build/stage-session.js";
|
|
13
|
+
import { buildProjectResource, readinessSummaryForStatus, readinessTargetResult, } from "./runtime-resource-builders.js";
|
|
8
14
|
import { aggregateArtifactVerdict, } from "./build/artifact-status.js";
|
|
9
15
|
import { buildBuildEvidence, } from "./build/build-evidence.js";
|
|
16
|
+
import { buildContextGraphSemanticGraph, } from "./context-graph-semantic-graph.js";
|
|
10
17
|
import { validateContextGraph } from "./build/validate.js";
|
|
11
|
-
import { SourceFileResourceSchema, ContextGraphResourceSchema, } from "./schemas/index.js";
|
|
18
|
+
import { SourceFileResourceSchema, ContextGraphResourceSchema, StageExecutionSessionSchema, } from "./schemas/index.js";
|
|
12
19
|
import { uniqueArtifacts } from "./run-observability.js";
|
|
13
20
|
import { listBuildRunsForProject, } from "./runtime-build-runs.js";
|
|
14
21
|
import { readExecutionStageLedgerHistory } from "./runtime-persistence.js";
|
|
@@ -17,6 +24,18 @@ import { listContextInterfaceArtifacts } from "../build-plans/package/context-in
|
|
|
17
24
|
import { latestTopLevelVerifyRun, listVerifyRunsForProject, readLatestBenchmarkRun, } from "./runtime-verify-runs.js";
|
|
18
25
|
export function listProjects(runtime, projectDataDir) {
|
|
19
26
|
const config = loadSourceFolderConfig(projectDataDir);
|
|
27
|
+
// Per-project config file mtime is a migration-free "last touched" signal —
|
|
28
|
+
// each Project owns its `~/.interf/projects/<id>/interf.json`. Clients sort
|
|
29
|
+
// the Projects list newest-first by this so a just-created Project lands on
|
|
30
|
+
// top instead of buried alphabetically.
|
|
31
|
+
const configPath = projectConfigPath(asProjectDataDir(projectDataDir));
|
|
32
|
+
let updatedAt = null;
|
|
33
|
+
try {
|
|
34
|
+
updatedAt = statSync(configPath).mtime.toISOString();
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
updatedAt = null;
|
|
38
|
+
}
|
|
20
39
|
return listProjectConfigs(config).map((project) => {
|
|
21
40
|
const buildRuns = listBuildRunsForProject(runtime, projectDataDir, project.name);
|
|
22
41
|
const verifyRuns = listVerifyRunsForProject(runtime, projectDataDir, project.name);
|
|
@@ -27,21 +46,20 @@ export function listProjects(runtime, projectDataDir) {
|
|
|
27
46
|
latestBuildRunId: buildRuns[0]?.run_id ?? null,
|
|
28
47
|
latestContextGraphBuildRunId: contextGraphRun?.run_id ?? null,
|
|
29
48
|
latestTestRunId: latestVerifyRun?.run_id ?? null,
|
|
30
|
-
}, resolveProjectSourceBindingPath(projectDataDir, project, config),
|
|
49
|
+
}, resolveProjectSourceBindingPath(projectDataDir, project, config), configPath,
|
|
31
50
|
// Surface per-Artifact status from the latest Build run so the UI can
|
|
32
51
|
// render Artifact rows on the Project page without a separate fetch.
|
|
33
|
-
contextGraphRun?.artifacts ?? []);
|
|
52
|
+
contextGraphRun?.artifacts ?? [], updatedAt);
|
|
34
53
|
});
|
|
35
54
|
}
|
|
36
55
|
export function getProject(runtime, projectDataDir, projectName) {
|
|
37
56
|
return listProjects(runtime, projectDataDir).find((project) => project.name === projectName) ?? null;
|
|
38
57
|
}
|
|
39
58
|
export function listProjectReadiness(runtime, projectDataDir) {
|
|
40
|
-
return listReadiness(runtime, projectDataDir)
|
|
59
|
+
return listReadiness(runtime, projectDataDir);
|
|
41
60
|
}
|
|
42
61
|
export function getProjectReadiness(runtime, projectDataDir, projectName) {
|
|
43
|
-
|
|
44
|
-
return readiness ? readinessStateToProjectReadiness(readiness) : null;
|
|
62
|
+
return getReadiness(runtime, projectDataDir, projectName);
|
|
45
63
|
}
|
|
46
64
|
export function listReadiness(runtime, projectDataDir) {
|
|
47
65
|
const config = loadSourceFolderConfig(projectDataDir);
|
|
@@ -60,16 +78,27 @@ function latestContextGraphBuildRun(project, buildRuns) {
|
|
|
60
78
|
: null;
|
|
61
79
|
return selected ?? buildRuns.find((run) => run.status === "succeeded") ?? null;
|
|
62
80
|
}
|
|
81
|
+
function contextGraphPathForBuildRun(projectDataDir, buildRun) {
|
|
82
|
+
if (!buildRun)
|
|
83
|
+
return null;
|
|
84
|
+
if (existsSync(buildRun.context_graph_path))
|
|
85
|
+
return buildRun.context_graph_path;
|
|
86
|
+
const projectOwnedPath = projectRunContextGraphPath(asProjectDataDir(projectDataDir), buildRun.run_id);
|
|
87
|
+
if (existsSync(projectOwnedPath))
|
|
88
|
+
return projectOwnedPath;
|
|
89
|
+
return buildRun.context_graph_path;
|
|
90
|
+
}
|
|
63
91
|
function computeProjectReadinessUncached(runtime, projectDataDir, project) {
|
|
64
92
|
const generatedAt = new Date().toISOString();
|
|
65
93
|
const buildRuns = listBuildRunsForProject(runtime, projectDataDir, project.name);
|
|
66
94
|
const buildRun = buildRuns[0] ?? null;
|
|
67
95
|
const contextGraphRun = latestContextGraphBuildRun(project, buildRuns);
|
|
68
|
-
const contextGraphPath = contextGraphRun
|
|
96
|
+
const contextGraphPath = contextGraphPathForBuildRun(projectDataDir, contextGraphRun);
|
|
69
97
|
const contextExists = Boolean(contextGraphPath && existsSync(contextGraphPath));
|
|
70
98
|
const contextGraphValidation = contextGraphPath && contextExists
|
|
71
99
|
? validateContextGraph(contextGraphPath)
|
|
72
100
|
: null;
|
|
101
|
+
const graphManifest = contextGraphPath && contextExists ? loadGraphManifest(contextGraphPath) : null;
|
|
73
102
|
const contextReady = Boolean(contextGraphRun && contextGraphValidation?.ok);
|
|
74
103
|
const verifyRun = latestTopLevelVerifyRun(listVerifyRunsForProject(runtime, projectDataDir, project.name));
|
|
75
104
|
const benchmarkRun = readLatestBenchmarkRun(projectDataDir, project.name);
|
|
@@ -143,9 +172,45 @@ function computeProjectReadinessUncached(runtime, projectDataDir, project) {
|
|
|
143
172
|
artifact_path: contextReady ? contextGraphPath : null,
|
|
144
173
|
};
|
|
145
174
|
})();
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
175
|
+
if (graphManifest && buildRun?.status === "succeeded" && contextReady) {
|
|
176
|
+
const status = graphManifest.readiness.ready ? "ready" : "not-ready";
|
|
177
|
+
return ReadinessSchema.parse({
|
|
178
|
+
kind: "interf-readiness-state",
|
|
179
|
+
version: 1,
|
|
180
|
+
generated_at: generatedAt,
|
|
181
|
+
project: project.name,
|
|
182
|
+
status,
|
|
183
|
+
ready: graphManifest.readiness.ready,
|
|
184
|
+
summary: graphManifest.readiness.summary,
|
|
185
|
+
context_graph_path: contextGraphPath,
|
|
186
|
+
latest_build_run_id: buildRun.run_id,
|
|
187
|
+
latest_benchmark_run_id: verifyRun?.run_id ?? null,
|
|
188
|
+
build: buildCheck,
|
|
189
|
+
check_results: {
|
|
190
|
+
configured: configuredChecks,
|
|
191
|
+
fingerprint: currentFingerprint,
|
|
192
|
+
source_files: sourceResult,
|
|
193
|
+
context_graph: contextResult,
|
|
194
|
+
},
|
|
195
|
+
checks: [
|
|
196
|
+
{
|
|
197
|
+
gate: "context-graph",
|
|
198
|
+
ok: graphManifest.readiness.ready,
|
|
199
|
+
status,
|
|
200
|
+
summary: graphManifest.readiness.summary,
|
|
201
|
+
artifact_path: contextGraphPath,
|
|
202
|
+
},
|
|
203
|
+
buildCheck,
|
|
204
|
+
],
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
// COMPAT fallback — reached only when no GraphManifest exists yet
|
|
208
|
+
// (pre-refactor build or build still running). The primary readiness path
|
|
209
|
+
// is the early return above that reads graphManifest.readiness directly.
|
|
210
|
+
// Keep these legacy gates so old UIs that consume readiness.checks don't
|
|
211
|
+
// crash; do not add new gates here. Removal path: once every active Build
|
|
212
|
+
// produces a GraphManifest, the early return covers all cases and this
|
|
213
|
+
// fallback can be replaced with a single "not yet built" check.
|
|
149
214
|
const checks = [
|
|
150
215
|
{
|
|
151
216
|
gate: "context-graph",
|
|
@@ -164,7 +229,7 @@ function computeProjectReadinessUncached(runtime, projectDataDir, project) {
|
|
|
164
229
|
? "not-configured"
|
|
165
230
|
: artifactVerdict === "ready" ? "ready" : "not-ready",
|
|
166
231
|
summary: !hasArtifactContract
|
|
167
|
-
? "No
|
|
232
|
+
? "No outputs declared by the selected Build Plan."
|
|
168
233
|
: artifactVerdict === "ready"
|
|
169
234
|
? `${artifactStatuses.length} Artifact${artifactStatuses.length === 1 ? "" : "s"} ready; ${passedArtifactCheckResults.length}/${requiredArtifactCheckResults.length} required diagnostic${requiredArtifactCheckResults.length === 1 ? "" : "s"} passed.`
|
|
170
235
|
: `${artifactFailures.length} Artifact${artifactFailures.length === 1 ? "" : "s"} not ready.`,
|
|
@@ -176,10 +241,10 @@ function computeProjectReadinessUncached(runtime, projectDataDir, project) {
|
|
|
176
241
|
? "not-configured"
|
|
177
242
|
: contextChecksPassed ? "ready" : "not-ready",
|
|
178
243
|
summary: requiredContextChecks.length === 0
|
|
179
|
-
? "No
|
|
244
|
+
? "No GraphManifest coverage rollup exists for this Build."
|
|
180
245
|
: contextChecksPassed
|
|
181
|
-
? `${requiredContextChecks.length}
|
|
182
|
-
: `${failedContextChecks.length}
|
|
246
|
+
? `${requiredContextChecks.length} legacy readiness check${requiredContextChecks.length === 1 ? "" : "s"} passed.`
|
|
247
|
+
: `${failedContextChecks.length} legacy readiness check${failedContextChecks.length === 1 ? "" : "s"} not passed.`,
|
|
183
248
|
},
|
|
184
249
|
{
|
|
185
250
|
gate: "benchmarks",
|
|
@@ -241,6 +306,25 @@ function computeProjectReadinessUncached(runtime, projectDataDir, project) {
|
|
|
241
306
|
checks,
|
|
242
307
|
});
|
|
243
308
|
}
|
|
309
|
+
/**
|
|
310
|
+
* Real on-disk size + mtime for a source file, read live from the source
|
|
311
|
+
* folder. The build manifest only sometimes carries `size_bytes` (older
|
|
312
|
+
* builds omit it) and never carries an mtime, so reads that trusted the
|
|
313
|
+
* manifest showed "0 B / -" for files that are really tens of KB to MBs.
|
|
314
|
+
* Returns null when the file moved or the locator isn't a local path.
|
|
315
|
+
*/
|
|
316
|
+
function statSourceFile(sourceLocator, relativePath) {
|
|
317
|
+
try {
|
|
318
|
+
const absolute = join(sourceLocator, relativePath);
|
|
319
|
+
if (!existsSync(absolute))
|
|
320
|
+
return null;
|
|
321
|
+
const info = statSync(absolute);
|
|
322
|
+
return info.isFile() ? { size: info.size, mtime: info.mtime } : null;
|
|
323
|
+
}
|
|
324
|
+
catch {
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
244
328
|
export function listSourceFiles(runtime, projectDataDir, projectName) {
|
|
245
329
|
const config = loadSourceFolderConfig(projectDataDir);
|
|
246
330
|
const projects = listProjectConfigs(config)
|
|
@@ -248,22 +332,25 @@ export function listSourceFiles(runtime, projectDataDir, projectName) {
|
|
|
248
332
|
return projects.flatMap((project) => {
|
|
249
333
|
const buildRuns = listBuildRunsForProject(runtime, projectDataDir, project.name);
|
|
250
334
|
const latestRun = latestContextGraphBuildRun(project, buildRuns);
|
|
251
|
-
const contextGraphPath = latestRun
|
|
335
|
+
const contextGraphPath = contextGraphPathForBuildRun(projectDataDir, latestRun);
|
|
252
336
|
const manifest = contextGraphPath ? loadContextGraphSourceManifest(contextGraphPath) : null;
|
|
253
337
|
if (!manifest)
|
|
254
338
|
return [];
|
|
255
|
-
return manifest.files.map((file) =>
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
339
|
+
return manifest.files.map((file) => {
|
|
340
|
+
const stat = statSourceFile(manifest.source.locator, file.path);
|
|
341
|
+
return SourceFileResourceSchema.parse({
|
|
342
|
+
project: project.name,
|
|
343
|
+
source_manifest_id: manifest.manifest_id,
|
|
344
|
+
source_file_id: file.id,
|
|
345
|
+
path: file.path,
|
|
346
|
+
locator: file.locator,
|
|
347
|
+
kind: file.kind,
|
|
348
|
+
absolute_path: file.locator,
|
|
349
|
+
size_bytes: stat?.size ?? file.size_bytes ?? 0,
|
|
350
|
+
modified_at: stat ? stat.mtime.toISOString() : null,
|
|
351
|
+
source_folder_path: manifest.source.locator,
|
|
352
|
+
});
|
|
353
|
+
});
|
|
267
354
|
});
|
|
268
355
|
}
|
|
269
356
|
export function listContextGraphs(runtime, projectDataDir, projectName) {
|
|
@@ -288,6 +375,7 @@ export function getLatestContextGraph(runtime, projectDataDir, projectName) {
|
|
|
288
375
|
const buildRunId = contextGraphRun?.run_id ?? null;
|
|
289
376
|
const rows = context.build_evidence?.rows ?? [];
|
|
290
377
|
const passing = rows.filter((row) => !row.issue_state || row.issue_state === "pass").length;
|
|
378
|
+
const primaryMetricCount = context.primary_metrics.length;
|
|
291
379
|
return ContextGraphResourceSchema.parse({
|
|
292
380
|
...context,
|
|
293
381
|
kind: "interf-context-graph",
|
|
@@ -300,11 +388,36 @@ export function getLatestContextGraph(runtime, projectDataDir, projectName) {
|
|
|
300
388
|
build_evidence: context.build_evidence
|
|
301
389
|
? {
|
|
302
390
|
...context.build_evidence,
|
|
303
|
-
summary:
|
|
391
|
+
summary: primaryMetricCount > 0
|
|
392
|
+
? `${context.build_evidence.summary} · ${primaryMetricCount} primary metric${primaryMetricCount === 1 ? "" : "s"}`
|
|
393
|
+
: `${context.build_evidence.summary} · ${passing}/${rows.length} diagnostic rows`,
|
|
304
394
|
}
|
|
305
395
|
: context.build_evidence,
|
|
306
396
|
});
|
|
307
397
|
}
|
|
398
|
+
export function listLatestContextGraphStageSessions(runtime, projectDataDir, projectName) {
|
|
399
|
+
const project = findProjectConfig(loadSourceFolderConfig(projectDataDir), projectName);
|
|
400
|
+
if (!project)
|
|
401
|
+
return [];
|
|
402
|
+
const latestRun = listBuildRunsForProject(runtime, projectDataDir, project.name)[0] ?? null;
|
|
403
|
+
const contextGraphPath = contextGraphPathForBuildRun(projectDataDir, latestRun);
|
|
404
|
+
if (!contextGraphPath || !existsSync(contextGraphPath))
|
|
405
|
+
return [];
|
|
406
|
+
return listStageExecutionSessions(contextGraphPath)
|
|
407
|
+
.map((session) => StageExecutionSessionSchema.parse(session));
|
|
408
|
+
}
|
|
409
|
+
export function getContextGraphHandoff(runtime, projectDataDir, projectName) {
|
|
410
|
+
const context = getLatestContextGraph(runtime, projectDataDir, projectName);
|
|
411
|
+
if (!context)
|
|
412
|
+
return null;
|
|
413
|
+
return ContextGraphHandoffSchema.parse({
|
|
414
|
+
kind: "interf-context-graph-handoff",
|
|
415
|
+
version: 1,
|
|
416
|
+
entrypoint: context.entrypoint_artifact ?? contextGraphEntrypointHandoff(context.path),
|
|
417
|
+
artifacts: context.artifact_handoffs,
|
|
418
|
+
...(context.portable_handoff ? { portable: context.portable_handoff } : {}),
|
|
419
|
+
});
|
|
420
|
+
}
|
|
308
421
|
function listProjectContextGraphs(runtime, projectDataDir, project) {
|
|
309
422
|
const buildRuns = listBuildRunsForProject(runtime, projectDataDir, project.name);
|
|
310
423
|
const latest = latestContextGraphBuildRun(project, buildRuns);
|
|
@@ -317,8 +430,23 @@ function listProjectContextGraphs(runtime, projectDataDir, project) {
|
|
|
317
430
|
function getProjectContextGraph(runtime, projectDataDir, project, buildRun, isLatest = true) {
|
|
318
431
|
if (!buildRun)
|
|
319
432
|
return null;
|
|
320
|
-
const path = buildRun
|
|
433
|
+
const path = contextGraphPathForBuildRun(projectDataDir, buildRun);
|
|
434
|
+
if (!path)
|
|
435
|
+
return null;
|
|
436
|
+
// A succeeded Build's Context Graph is immutable: cache the fully-built
|
|
437
|
+
// resource keyed by run id + graph-manifest mtime. Non-succeeded runs (and
|
|
438
|
+
// graphs without a readable manifest) fall through to a fresh compute every
|
|
439
|
+
// time. `isLatest` flips the `is_latest` flag but is otherwise stable per
|
|
440
|
+
// run within a request, so fold it into the cache key suffix.
|
|
441
|
+
if (buildRun.status === "succeeded") {
|
|
442
|
+
return runtime.contextGraphResourceCache.get(projectDataDir, `${buildRun.run_id}:${isLatest ? "latest" : "historical"}`, contextGraphRuntimeGraphManifestPath(path), () => buildProjectContextGraphResource(runtime, projectDataDir, project, buildRun, path, isLatest));
|
|
443
|
+
}
|
|
444
|
+
return buildProjectContextGraphResource(runtime, projectDataDir, project, buildRun, path, isLatest);
|
|
445
|
+
}
|
|
446
|
+
function buildProjectContextGraphResource(runtime, projectDataDir, project, buildRun, path, isLatest) {
|
|
321
447
|
const config = readInterfConfig(path);
|
|
448
|
+
const sourceManifest = loadContextGraphSourceManifest(path);
|
|
449
|
+
const graphManifest = loadGraphManifest(path);
|
|
322
450
|
const verifyRuns = listVerifyRunsForProject(runtime, projectDataDir, project.name);
|
|
323
451
|
const latestVerifyRun = latestTopLevelVerifyRun(verifyRuns);
|
|
324
452
|
const readiness = computeProjectReadiness(runtime, projectDataDir, project);
|
|
@@ -330,7 +458,7 @@ function getProjectContextGraph(runtime, projectDataDir, project, buildRun, isLa
|
|
|
330
458
|
try {
|
|
331
459
|
const activeBuildPlan = getBuildPlan(buildPlan, { projectDataDir });
|
|
332
460
|
expectedStageCount = activeBuildPlan.stages.length;
|
|
333
|
-
const contextInterface = activeBuildPlan.contextInterface
|
|
461
|
+
const contextInterface = activeBuildPlan.contextInterface;
|
|
334
462
|
expectedOutputCount = contextInterface ? listContextInterfaceArtifacts(contextInterface).length : undefined;
|
|
335
463
|
}
|
|
336
464
|
catch {
|
|
@@ -338,13 +466,21 @@ function getProjectContextGraph(runtime, projectDataDir, project, buildRun, isLa
|
|
|
338
466
|
expectedOutputCount = undefined;
|
|
339
467
|
}
|
|
340
468
|
}
|
|
469
|
+
const artifacts = uniqueArtifacts(buildRun.stages.flatMap((stage) => stage.artifacts));
|
|
470
|
+
const artifactHandoffs = contextGraphArtifactHandoffs(path, artifacts);
|
|
471
|
+
const createdAt = buildRun.finished_at ?? buildRun.started_at ?? buildRun.created_at ?? readiness.generated_at;
|
|
472
|
+
const semanticEntrypointPath = artifactHandoffs.find((handoff) => handoff.path?.endsWith(".md"))?.path
|
|
473
|
+
?? artifactHandoffs[0]?.path
|
|
474
|
+
?? null;
|
|
341
475
|
return ContextGraphResourceSchema.parse({
|
|
342
476
|
kind: "interf-context-graph",
|
|
343
477
|
version: 1,
|
|
344
478
|
graph_id: buildRun.run_id,
|
|
345
479
|
project_id: project.name,
|
|
480
|
+
intent: project.intent ?? "",
|
|
346
481
|
build_run_id: buildRun.run_id,
|
|
347
|
-
|
|
482
|
+
source_manifest_id: sourceManifest?.manifest_id ?? null,
|
|
483
|
+
created_at: createdAt,
|
|
348
484
|
is_latest: isLatest,
|
|
349
485
|
project: project.name,
|
|
350
486
|
path,
|
|
@@ -353,7 +489,27 @@ function getProjectContextGraph(runtime, projectDataDir, project, buildRun, isLa
|
|
|
353
489
|
build_plan: buildPlan,
|
|
354
490
|
latest_build_run_id: buildRun.run_id,
|
|
355
491
|
latest_benchmark_run_id: latestVerifyRun?.run_id ?? null,
|
|
356
|
-
|
|
492
|
+
entrypoint_artifact: artifactHandoffs[0] ?? null,
|
|
493
|
+
artifact_handoffs: artifactHandoffs,
|
|
494
|
+
portable_handoff: {
|
|
495
|
+
locator: { kind: "local-path", value: path },
|
|
496
|
+
instructions: "Start from home.md, then follow links into knowledge/, summaries/, and source refs.",
|
|
497
|
+
},
|
|
498
|
+
artifacts,
|
|
499
|
+
semantic_graph: buildContextGraphSemanticGraph({
|
|
500
|
+
contextGraphPath: path,
|
|
501
|
+
projectId: project.name,
|
|
502
|
+
generatedAt: createdAt,
|
|
503
|
+
sourceManifest,
|
|
504
|
+
entrypointPath: semanticEntrypointPath,
|
|
505
|
+
}),
|
|
506
|
+
graph_manifest: graphManifest,
|
|
507
|
+
primary_metrics: graphManifest?.primary_metrics ?? [],
|
|
508
|
+
stage_summaries: graphManifest?.stages ?? [],
|
|
509
|
+
entrypoints: graphManifest?.entrypoints ?? [],
|
|
510
|
+
resources: graphManifest?.resources ?? [],
|
|
511
|
+
readiness_rollup: graphManifest?.readiness ?? null,
|
|
512
|
+
stage_sessions: listStageExecutionSessions(path),
|
|
357
513
|
build_evidence: buildBuildEvidence({
|
|
358
514
|
projectId: project.name,
|
|
359
515
|
buildRun,
|
|
@@ -362,9 +518,46 @@ function getProjectContextGraph(runtime, projectDataDir, project, buildRun, isLa
|
|
|
362
518
|
expectedStageCount,
|
|
363
519
|
expectedOutputCount,
|
|
364
520
|
stageEvidence: latestStageEvidenceForContext(path),
|
|
521
|
+
primaryMetrics: graphManifest?.primary_metrics ?? [],
|
|
365
522
|
}),
|
|
366
523
|
});
|
|
367
524
|
}
|
|
525
|
+
function contextGraphArtifactHandoffs(contextGraphPath, artifacts) {
|
|
526
|
+
const entrypoint = contextGraphEntrypointHandoff(contextGraphPath);
|
|
527
|
+
const outputs = artifacts.filter((artifact) => artifact.role === "output" && isInterfRelativePath(artifact.path));
|
|
528
|
+
const artifactEntrypoints = outputs.filter((artifact) => layerForPath(artifact.path) === "artifacts");
|
|
529
|
+
const ordered = [
|
|
530
|
+
...artifactEntrypoints,
|
|
531
|
+
...outputs.filter((artifact) => !artifactEntrypoints.includes(artifact)),
|
|
532
|
+
];
|
|
533
|
+
const seen = new Set([entrypoint.path]);
|
|
534
|
+
const handoffs = ordered
|
|
535
|
+
.filter((artifact) => {
|
|
536
|
+
if (seen.has(artifact.path))
|
|
537
|
+
return false;
|
|
538
|
+
seen.add(artifact.path);
|
|
539
|
+
return true;
|
|
540
|
+
})
|
|
541
|
+
.map((artifact) => ({
|
|
542
|
+
label: artifact.label ?? artifact.path,
|
|
543
|
+
locator: { kind: "local-path", value: join(contextGraphPath, artifact.path) },
|
|
544
|
+
path: artifact.path,
|
|
545
|
+
role: "artifact",
|
|
546
|
+
...(artifact.stage_id ? { summary: `Produced by stage ${artifact.stage_id}.` } : {}),
|
|
547
|
+
}));
|
|
548
|
+
return [entrypoint, ...handoffs];
|
|
549
|
+
}
|
|
550
|
+
function contextGraphEntrypointHandoff(contextGraphPath) {
|
|
551
|
+
return {
|
|
552
|
+
artifact_id: "home",
|
|
553
|
+
label: "Context Graph home",
|
|
554
|
+
locator: { kind: "local-path", value: join(contextGraphPath, "home.md") },
|
|
555
|
+
path: "home.md",
|
|
556
|
+
artifact_kind: "file",
|
|
557
|
+
role: "entrypoint",
|
|
558
|
+
summary: "Primary downstream agent entrypoint. Start here before following links into knowledge/ and summaries/.",
|
|
559
|
+
};
|
|
560
|
+
}
|
|
368
561
|
function latestStageEvidenceForContext(contextGraphPath) {
|
|
369
562
|
const latestByStage = new Map();
|
|
370
563
|
for (const entry of readExecutionStageLedgerHistory(contextGraphPath)) {
|