clinkx 1.0.0 → 1.1.1
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/CHANGELOG.md +95 -0
- package/README.md +184 -112
- package/clinkx-workflows/dist/chairman-knobs.d.ts +24 -0
- package/clinkx-workflows/dist/chairman-knobs.js +27 -0
- package/clinkx-workflows/dist/chairman-knobs.js.map +1 -0
- package/clinkx-workflows/dist/clink-client.d.ts +10 -0
- package/clinkx-workflows/dist/clink-client.js +39 -1
- package/clinkx-workflows/dist/clink-client.js.map +1 -1
- package/clinkx-workflows/dist/config.d.ts +29 -1
- package/clinkx-workflows/dist/config.js +35 -2
- package/clinkx-workflows/dist/config.js.map +1 -1
- package/clinkx-workflows/dist/context-preflight.d.ts +5 -0
- package/clinkx-workflows/dist/context-preflight.js.map +1 -1
- package/clinkx-workflows/dist/council-execution-policy.d.ts +68 -0
- package/clinkx-workflows/dist/council-execution-policy.js +110 -0
- package/clinkx-workflows/dist/council-execution-policy.js.map +1 -0
- package/clinkx-workflows/dist/council-expander.d.ts +9 -8
- package/clinkx-workflows/dist/council-expander.js +18 -9
- package/clinkx-workflows/dist/council-expander.js.map +1 -1
- package/clinkx-workflows/dist/dashboard/activity-contract.d.ts +5557 -4
- package/clinkx-workflows/dist/dashboard/activity-contract.js +55 -3
- package/clinkx-workflows/dist/dashboard/activity-contract.js.map +1 -1
- package/clinkx-workflows/dist/dashboard/activity-reader.d.ts +9 -5
- package/clinkx-workflows/dist/dashboard/activity-reader.js +15 -2
- package/clinkx-workflows/dist/dashboard/activity-reader.js.map +1 -1
- package/clinkx-workflows/dist/dashboard/api-routes.d.ts +4 -0
- package/clinkx-workflows/dist/dashboard/api-routes.js +133 -25
- package/clinkx-workflows/dist/dashboard/api-routes.js.map +1 -1
- package/clinkx-workflows/dist/dashboard/context-builder-invocation-contract.d.ts +3865 -0
- package/clinkx-workflows/dist/dashboard/context-builder-invocation-contract.js +69 -0
- package/clinkx-workflows/dist/dashboard/context-builder-invocation-contract.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/context-run-reader.d.ts +36 -2
- package/clinkx-workflows/dist/dashboard/context-run-reader.js +142 -19
- package/clinkx-workflows/dist/dashboard/context-run-reader.js.map +1 -1
- package/clinkx-workflows/dist/dashboard/contracts.d.ts +20027 -480
- package/clinkx-workflows/dist/dashboard/contracts.js +133 -6
- package/clinkx-workflows/dist/dashboard/contracts.js.map +1 -1
- package/clinkx-workflows/dist/dashboard/index.d.ts +4 -0
- package/clinkx-workflows/dist/dashboard/index.js +4 -0
- package/clinkx-workflows/dist/dashboard/index.js.map +1 -1
- package/clinkx-workflows/dist/dashboard/invocation-contract.d.ts +786 -0
- package/clinkx-workflows/dist/dashboard/invocation-contract.js +201 -0
- package/clinkx-workflows/dist/dashboard/invocation-contract.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/lazy-content.d.ts +14 -1
- package/clinkx-workflows/dist/dashboard/lazy-content.js +53 -2
- package/clinkx-workflows/dist/dashboard/lazy-content.js.map +1 -1
- package/clinkx-workflows/dist/dashboard/native-transcript/contract.d.ts +90 -0
- package/clinkx-workflows/dist/dashboard/native-transcript/contract.js +31 -0
- package/clinkx-workflows/dist/dashboard/native-transcript/contract.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/native-transcript/projection.d.ts +12 -0
- package/clinkx-workflows/dist/dashboard/native-transcript/projection.js +286 -0
- package/clinkx-workflows/dist/dashboard/native-transcript/projection.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/progress-report-contract.d.ts +147 -4
- package/clinkx-workflows/dist/dashboard/progress-report-contract.js +11 -11
- package/clinkx-workflows/dist/dashboard/progress-report-contract.js.map +1 -1
- package/clinkx-workflows/dist/dashboard/progress-report-reader.js +4 -56
- package/clinkx-workflows/dist/dashboard/progress-report-reader.js.map +1 -1
- package/clinkx-workflows/dist/dashboard/progress-report-status-store.d.ts +2 -1
- package/clinkx-workflows/dist/dashboard/progress-report-status-store.js +6 -5
- package/clinkx-workflows/dist/dashboard/progress-report-status-store.js.map +1 -1
- package/clinkx-workflows/dist/dashboard/prompt-builder-library-contract.d.ts +194 -0
- package/clinkx-workflows/dist/dashboard/prompt-builder-library-contract.js +89 -0
- package/clinkx-workflows/dist/dashboard/prompt-builder-library-contract.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/prompt-builder-library-store.d.ts +26 -0
- package/clinkx-workflows/dist/dashboard/prompt-builder-library-store.js +102 -0
- package/clinkx-workflows/dist/dashboard/prompt-builder-library-store.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/request-admission.js +4 -0
- package/clinkx-workflows/dist/dashboard/request-admission.js.map +1 -1
- package/clinkx-workflows/dist/dashboard/scanner.d.ts +3 -0
- package/clinkx-workflows/dist/dashboard/scanner.js +52 -8
- package/clinkx-workflows/dist/dashboard/scanner.js.map +1 -1
- package/clinkx-workflows/dist/dashboard/server-factory.d.ts +14 -1
- package/clinkx-workflows/dist/dashboard/server-factory.js +73 -21
- package/clinkx-workflows/dist/dashboard/server-factory.js.map +1 -1
- package/clinkx-workflows/dist/dashboard/session-log-contract.d.ts +223 -56
- package/clinkx-workflows/dist/dashboard/session-log-contract.js +26 -0
- package/clinkx-workflows/dist/dashboard/session-log-contract.js.map +1 -1
- package/clinkx-workflows/dist/dashboard/session-log-journal.js +10 -3
- package/clinkx-workflows/dist/dashboard/session-log-journal.js.map +1 -1
- package/clinkx-workflows/dist/dashboard/session-log-redaction.d.ts +9 -1
- package/clinkx-workflows/dist/dashboard/session-log-redaction.js +793 -59
- package/clinkx-workflows/dist/dashboard/session-log-redaction.js.map +1 -1
- package/clinkx-workflows/dist/dashboard-ui/assets/index-JPHQVtn9.js +106 -0
- package/clinkx-workflows/dist/dashboard-ui/assets/style-DOMHk-j6.css +1 -0
- package/clinkx-workflows/dist/dashboard-ui/index.html +2 -2
- package/clinkx-workflows/dist/delegate-finalizer-policy.d.ts +26 -0
- package/clinkx-workflows/dist/delegate-finalizer-policy.js +72 -0
- package/clinkx-workflows/dist/delegate-finalizer-policy.js.map +1 -0
- package/clinkx-workflows/dist/delegate-signature.d.ts +14 -0
- package/clinkx-workflows/dist/delegate-signature.js +14 -0
- package/clinkx-workflows/dist/delegate-signature.js.map +1 -0
- package/clinkx-workflows/dist/delegate-validate.d.ts +32 -2
- package/clinkx-workflows/dist/delegate-validate.js +51 -0
- package/clinkx-workflows/dist/delegate-validate.js.map +1 -1
- package/clinkx-workflows/dist/engine.d.ts +113 -3
- package/clinkx-workflows/dist/engine.js +476 -80
- package/clinkx-workflows/dist/engine.js.map +1 -1
- package/clinkx-workflows/dist/errors.d.ts +22 -2
- package/clinkx-workflows/dist/errors.js +30 -2
- package/clinkx-workflows/dist/errors.js.map +1 -1
- package/clinkx-workflows/dist/fidelity.d.ts +47 -1
- package/clinkx-workflows/dist/fidelity.js +54 -1
- package/clinkx-workflows/dist/fidelity.js.map +1 -1
- package/clinkx-workflows/dist/fingerprint.d.ts +24 -6
- package/clinkx-workflows/dist/fingerprint.js +32 -9
- package/clinkx-workflows/dist/fingerprint.js.map +1 -1
- package/clinkx-workflows/dist/index.js +53 -1
- package/clinkx-workflows/dist/index.js.map +1 -1
- package/clinkx-workflows/dist/logger.d.ts +1 -1
- package/clinkx-workflows/dist/logger.js +17 -3
- package/clinkx-workflows/dist/logger.js.map +1 -1
- package/clinkx-workflows/dist/monotonic-clock.d.ts +19 -0
- package/clinkx-workflows/dist/monotonic-clock.js +22 -0
- package/clinkx-workflows/dist/monotonic-clock.js.map +1 -0
- package/clinkx-workflows/dist/plan-review/contract.d.ts +52 -52
- package/clinkx-workflows/dist/plan-review/publication.d.ts +4 -4
- package/clinkx-workflows/dist/plan-review/run-state.d.ts +16 -16
- package/clinkx-workflows/dist/roster-contract.d.ts +889 -0
- package/clinkx-workflows/dist/roster-contract.js +180 -0
- package/clinkx-workflows/dist/roster-contract.js.map +1 -0
- package/clinkx-workflows/dist/rosters.d.ts +14 -0
- package/clinkx-workflows/dist/rosters.js +169 -0
- package/clinkx-workflows/dist/rosters.js.map +1 -0
- package/clinkx-workflows/dist/run-health.d.ts +7 -0
- package/clinkx-workflows/dist/run-health.js +25 -0
- package/clinkx-workflows/dist/run-health.js.map +1 -0
- package/clinkx-workflows/dist/schema.d.ts +64 -0
- package/clinkx-workflows/dist/schema.js +24 -0
- package/clinkx-workflows/dist/schema.js.map +1 -1
- package/clinkx-workflows/dist/server.js +2 -0
- package/clinkx-workflows/dist/server.js.map +1 -1
- package/clinkx-workflows/dist/shutdown.d.ts +15 -2
- package/clinkx-workflows/dist/shutdown.js +60 -16
- package/clinkx-workflows/dist/shutdown.js.map +1 -1
- package/clinkx-workflows/dist/state-schema.d.ts +23 -0
- package/clinkx-workflows/dist/state.d.ts +5 -0
- package/clinkx-workflows/dist/state.js +128 -21
- package/clinkx-workflows/dist/state.js.map +1 -1
- package/clinkx-workflows/dist/stdio-watchdog.d.ts +52 -0
- package/clinkx-workflows/dist/stdio-watchdog.js +212 -0
- package/clinkx-workflows/dist/stdio-watchdog.js.map +1 -0
- package/clinkx-workflows/dist/types.d.ts +6 -0
- package/clinkx-workflows/dist/validators/council.d.ts +50 -50
- package/clinkx-workflows/dist/validators/plan-review.d.ts +3 -3
- package/clinkx-workflows/dist/workflow-tools.d.ts +70 -0
- package/clinkx-workflows/dist/workflow-tools.js +760 -168
- package/clinkx-workflows/dist/workflow-tools.js.map +1 -1
- package/clinkx-workflows/templates/council/answer-chairman.txt +3 -0
- package/clinkx-workflows/templates/council/answer-cross-reviewer.txt +3 -0
- package/clinkx-workflows/templates/council/answer-specialist.txt +3 -0
- package/clinkx-workflows/templates/council/chairman.txt +3 -0
- package/clinkx-workflows/templates/council/code-review-chairman.txt +3 -0
- package/clinkx-workflows/templates/council/code-review-cross-reviewer.txt +3 -0
- package/clinkx-workflows/templates/council/code-review-reviewer.txt +3 -0
- package/clinkx-workflows/templates/council/debug-chairman.txt +3 -0
- package/clinkx-workflows/templates/council/debug-cross-reviewer.txt +3 -0
- package/clinkx-workflows/templates/council/debug-debugger.txt +3 -0
- package/clinkx-workflows/templates/council/discover-analyst.txt +3 -0
- package/clinkx-workflows/templates/council/discover-chairman.txt +3 -0
- package/clinkx-workflows/templates/council/discover-cross-reviewer.txt +3 -0
- package/clinkx-workflows/templates/council/member.txt +3 -0
- package/clinkx-workflows/templates/council/plan-review-chairman.txt +3 -0
- package/clinkx-workflows/templates/council/plan-review-cross-reviewer.txt +3 -0
- package/clinkx-workflows/templates/council/plan-review-reviewer.txt +3 -0
- package/clinkx-workflows/templates/council/reviewer.txt +3 -0
- package/clinkx-workflows/workflows/council-answer.yaml +3 -0
- package/clinkx-workflows/workflows/council-code-review.yaml +3 -0
- package/clinkx-workflows/workflows/council-debug.yaml +3 -0
- package/clinkx-workflows/workflows/council-default.yaml +7 -0
- package/clinkx-workflows/workflows/council-discover.yaml +3 -0
- package/clinkx-workflows/workflows/council-plan-review.yaml +3 -0
- package/conf/adapters/agy.json +9 -2
- package/conf/adapters/claude.json +7 -0
- package/conf/adapters/codex.json +7 -0
- package/conf/adapters/glm.json +19 -3
- package/conf/adapters/grok.json +9 -2
- package/conf/adapters/hapi/agy.json +9 -2
- package/conf/adapters/hapi/claude.json +7 -0
- package/conf/adapters/hapi/codex.json +7 -0
- package/conf/adapters/hapi/glm.json +20 -4
- package/conf/rosters/default-council.json +21 -0
- package/dist/activity-journal.d.ts +17 -3
- package/dist/activity-journal.js +404 -79
- package/dist/activity-journal.js.map +1 -1
- package/dist/codex/agent-tools.js +36 -0
- package/dist/codex/agent-tools.js.map +1 -1
- package/dist/codex/app-server-client.d.ts +3 -0
- package/dist/codex/app-server-client.js +11 -0
- package/dist/codex/app-server-client.js.map +1 -1
- package/dist/codex/app-server-registry.d.ts +18 -0
- package/dist/codex/app-server-registry.js +88 -2
- package/dist/codex/app-server-registry.js.map +1 -1
- package/dist/codex/client-types.d.ts +7 -1
- package/dist/codex/protocol.d.ts +4 -4
- package/dist/config.d.ts +220 -23
- package/dist/config.js +104 -1
- package/dist/config.js.map +1 -1
- package/dist/context-builder/bundle.d.ts +13 -0
- package/dist/context-builder/bundle.js +46 -0
- package/dist/context-builder/bundle.js.map +1 -1
- package/dist/context-builder/delegate-finalizer-effective.d.ts +33 -0
- package/dist/context-builder/delegate-finalizer-effective.js +82 -0
- package/dist/context-builder/delegate-finalizer-effective.js.map +1 -0
- package/dist/context-builder/delegate-packet.d.ts +18 -0
- package/dist/context-builder/delegate-packet.js +73 -9
- package/dist/context-builder/delegate-packet.js.map +1 -1
- package/dist/context-builder/delegate-reconstruction.d.ts +29 -0
- package/dist/context-builder/delegate-reconstruction.js +110 -41
- package/dist/context-builder/delegate-reconstruction.js.map +1 -1
- package/dist/context-builder/delegate-validation.d.ts +31 -0
- package/dist/context-builder/delegate-validation.js +87 -10
- package/dist/context-builder/delegate-validation.js.map +1 -1
- package/dist/context-builder/delegate.d.ts +9 -0
- package/dist/context-builder/delegate.js +210 -59
- package/dist/context-builder/delegate.js.map +1 -1
- package/dist/context-builder/diagnostics.d.ts +1 -1
- package/dist/context-builder/diagnostics.js.map +1 -1
- package/dist/context-builder/discovery-progress.d.ts +25 -0
- package/dist/context-builder/discovery-progress.js +64 -0
- package/dist/context-builder/discovery-progress.js.map +1 -0
- package/dist/context-builder/discovery-watchdog.d.ts +15 -0
- package/dist/context-builder/discovery-watchdog.js +39 -0
- package/dist/context-builder/discovery-watchdog.js.map +1 -0
- package/dist/context-builder/discovery.d.ts +7 -0
- package/dist/context-builder/discovery.js +119 -7
- package/dist/context-builder/discovery.js.map +1 -1
- package/dist/context-builder/external-gaps.d.ts +73 -0
- package/dist/context-builder/external-gaps.js +248 -0
- package/dist/context-builder/external-gaps.js.map +1 -0
- package/dist/context-builder/globs.d.ts +1 -0
- package/dist/context-builder/globs.js +15 -0
- package/dist/context-builder/globs.js.map +1 -1
- package/dist/context-builder/handler.d.ts +42 -1
- package/dist/context-builder/handler.js +690 -62
- package/dist/context-builder/handler.js.map +1 -1
- package/dist/context-builder/invocation-sidecar.d.ts +41 -0
- package/dist/context-builder/invocation-sidecar.js +189 -0
- package/dist/context-builder/invocation-sidecar.js.map +1 -0
- package/dist/context-builder/lifecycle-contract.d.ts +51 -51
- package/dist/context-builder/mutation-lock.d.ts +32 -0
- package/dist/context-builder/mutation-lock.js +321 -0
- package/dist/context-builder/mutation-lock.js.map +1 -0
- package/dist/context-builder/review-coverage.d.ts +32 -0
- package/dist/context-builder/review-coverage.js +130 -23
- package/dist/context-builder/review-coverage.js.map +1 -1
- package/dist/context-builder/schema.d.ts +76 -1
- package/dist/context-builder/schema.js +21 -1
- package/dist/context-builder/schema.js.map +1 -1
- package/dist/context-builder/secrets.d.ts +31 -0
- package/dist/context-builder/secrets.js +871 -84
- package/dist/context-builder/secrets.js.map +1 -1
- package/dist/context-builder/status.d.ts +1 -1
- package/dist/context-builder/status.js +1 -0
- package/dist/context-builder/status.js.map +1 -1
- package/dist/context-builder/storage.d.ts +29 -5
- package/dist/context-builder/storage.js +311 -236
- package/dist/context-builder/storage.js.map +1 -1
- package/dist/context-builder/versions.d.ts +19 -4
- package/dist/context-builder/versions.js +19 -4
- package/dist/context-builder/versions.js.map +1 -1
- package/dist/context-builder/workflow-runner.d.ts +6 -0
- package/dist/context-builder/workflow-runner.js +363 -173
- package/dist/context-builder/workflow-runner.js.map +1 -1
- package/dist/dashboard-adapter-catalog.js +7 -0
- package/dist/dashboard-adapter-catalog.js.map +1 -1
- package/dist/dashboard-cli.d.ts +2 -0
- package/dist/dashboard-cli.js +40 -2
- package/dist/dashboard-cli.js.map +1 -1
- package/dist/dashboard-companion/client.d.ts +1 -0
- package/dist/dashboard-companion/client.js +22 -3
- package/dist/dashboard-companion/client.js.map +1 -1
- package/dist/dashboard-companion/protocol.js +4 -1
- package/dist/dashboard-companion/protocol.js.map +1 -1
- package/dist/dashboard-gateway/index.d.ts +1 -0
- package/dist/dashboard-gateway/index.js +33 -2
- package/dist/dashboard-gateway/index.js.map +1 -1
- package/dist/handler.js +5 -1
- package/dist/handler.js.map +1 -1
- package/dist/index.d.ts +18 -1
- package/dist/index.js +145 -7
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +1 -1
- package/dist/logger.js +18 -3
- package/dist/logger.js.map +1 -1
- package/dist/parsers/agy-stream-json.d.ts +14 -0
- package/dist/parsers/agy-stream-json.js +172 -0
- package/dist/parsers/agy-stream-json.js.map +1 -0
- package/dist/parsers/extract.js +5 -1
- package/dist/parsers/extract.js.map +1 -1
- package/dist/parsers/observed-invocation.d.ts +20 -0
- package/dist/parsers/observed-invocation.js +42 -0
- package/dist/parsers/observed-invocation.js.map +1 -0
- package/dist/pipeline.d.ts +13 -0
- package/dist/pipeline.js +60 -10
- package/dist/pipeline.js.map +1 -1
- package/dist/progress-report/lock.d.ts +74 -0
- package/dist/progress-report/lock.js +343 -0
- package/dist/progress-report/lock.js.map +1 -0
- package/dist/progress-report/schema.d.ts +808 -0
- package/dist/progress-report/schema.js +119 -0
- package/dist/progress-report/schema.js.map +1 -0
- package/dist/progress-report/store.d.ts +66 -0
- package/dist/progress-report/store.js +766 -0
- package/dist/progress-report/store.js.map +1 -0
- package/dist/progress-report/tools.d.ts +20 -0
- package/dist/progress-report/tools.js +141 -0
- package/dist/progress-report/tools.js.map +1 -0
- package/dist/prompt-mode.d.ts +1 -1
- package/dist/prompt-mode.js +7 -2
- package/dist/prompt-mode.js.map +1 -1
- package/dist/runner.d.ts +7 -0
- package/dist/runner.js +10 -3
- package/dist/runner.js.map +1 -1
- package/dist/safety.d.ts +50 -0
- package/dist/safety.js +182 -1
- package/dist/safety.js.map +1 -1
- package/dist/schema.d.ts +8 -0
- package/dist/schema.js +20 -0
- package/dist/schema.js.map +1 -1
- package/dist/server.d.ts +6 -1
- package/dist/server.js +94 -8
- package/dist/server.js.map +1 -1
- package/dist/session-log-stream.d.ts +1 -1
- package/dist/session-log-stream.js +280 -33
- package/dist/session-log-stream.js.map +1 -1
- package/dist/stdio-activity.d.ts +28 -0
- package/dist/stdio-activity.js +72 -0
- package/dist/stdio-activity.js.map +1 -0
- package/docs/configuration.md +426 -0
- package/docs/security.md +293 -0
- package/package.json +5 -5
- package/clinkx-workflows/dist/dashboard-ui/assets/index-DOkMXTfB.js +0 -25
- package/clinkx-workflows/dist/dashboard-ui/assets/style-ChJsn0KD.css +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { realpathSync, statSync } from "node:fs";
|
|
3
|
-
import { copyFile, mkdir, readFile, realpath, rename, rm, utimes, } from "node:fs/promises";
|
|
3
|
+
import { copyFile, link, lstat, mkdir, open, readFile, realpath, rename, rm, utimes, } from "node:fs/promises";
|
|
4
4
|
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
5
5
|
// ---------------------------------------------------------------------------
|
|
6
6
|
// Deep `clinkx-workflows/dist` imports (one-way dependency, build-order coupled)
|
|
@@ -36,11 +36,12 @@ import { CONTEXT_BUILDER_RENDERER_VERSION } from "./bundle.js";
|
|
|
36
36
|
import { CONTEXT_DELEGATE_PROMPT_VERSION, CONTEXT_DISCOVERY_ALGORITHM_VERSION, } from "./versions.js";
|
|
37
37
|
import { getSharedContextBuilderSemaphore, resolveContextBuilderRunsDir, } from "./config.js";
|
|
38
38
|
import { handleContextBuilder } from "./handler.js";
|
|
39
|
+
import { CONTEXT_BUILDER_INVOCATION_AUDIT_FILENAME, isContextBuilderInvocationAuditSidecarProvenInvalid, readContextBuilderInvocationAuditSidecar, } from "./invocation-sidecar.js";
|
|
39
40
|
import { CONTEXT_BUILDER_INTENT_PROFILE_DEFAULTS, CONTEXT_BUILDER_INTENT_PROFILES, resolveContextBuilderAdapterBudgetInput, } from "./schema.js";
|
|
40
41
|
import { assertNoHighConfidenceSecretsInTask, resolveAllowSecrets, } from "./secrets.js";
|
|
41
42
|
import { CONTEXT_BUILDER_DELEGATE_SCHEMA_VERSION, CONTEXT_BUILDER_NO_DELEGATE_SCHEMA_VERSION, createContextBuilderReceipt, } from "./receipt.js";
|
|
42
43
|
import { notEvaluatedCoverageReport, } from "./review-coverage.js";
|
|
43
|
-
import {
|
|
44
|
+
import { ContextBuilderActiveRunClaimConflictError, ContextBuilderAncillaryPromotionError, ContextBuilderCommittedRunChangedError, ContextBuilderRunClaimConflictError, evictWorkflowContextRuns, isContextBuilderRunCommitted, resolveContextBuilderRunPaths, withCommittedContextBuilderRunMutationLease, withPromotedContextBuilderRun, } from "./storage.js";
|
|
44
45
|
import { ContextBuilderLifecycleController, ContextBuilderLifecycleObserverError, } from "./lifecycle-observer.js";
|
|
45
46
|
export function createWorkflowContextBuilderRunner(options = {}) {
|
|
46
47
|
const cb = options.handleContextBuilder ?? handleContextBuilder;
|
|
@@ -57,6 +58,7 @@ export function createWorkflowContextBuilderRunner(options = {}) {
|
|
|
57
58
|
const discoveryAlgorithmVersion = options.discoveryAlgorithmVersion ?? CONTEXT_DISCOVERY_ALGORITHM_VERSION;
|
|
58
59
|
const delegatePromptVersion = options.delegatePromptVersion ?? CONTEXT_DELEGATE_PROMPT_VERSION;
|
|
59
60
|
const registry = options.registry;
|
|
61
|
+
const syncInvocationSnapshotDirectory = options.syncInvocationSnapshotDirectory ?? syncDirectoryEntry;
|
|
60
62
|
return {
|
|
61
63
|
assertRootsAllowed(roots) {
|
|
62
64
|
assertExplicitRootsWithinAllowed(roots);
|
|
@@ -138,31 +140,34 @@ export function createWorkflowContextBuilderRunner(options = {}) {
|
|
|
138
140
|
const postSig = await workspaceSignature(mapped.roots);
|
|
139
141
|
throwIfAborted(opts.signal);
|
|
140
142
|
if (postSig === preSig) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
includeSelectedContext,
|
|
163
|
-
...(lifecycle == null ? {} : { lifecycle }),
|
|
143
|
+
let hit;
|
|
144
|
+
try {
|
|
145
|
+
hit = await withCommittedContextBuilderRunMutationLease(cache.targetStorage, async () => {
|
|
146
|
+
// Refresh directory mtime so LRU eviction treats this as recently used.
|
|
147
|
+
try {
|
|
148
|
+
const now = new Date();
|
|
149
|
+
await utimes(cache.targetStorage.runDir, now, now);
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
// best-effort — a hit must not fail because utimes failed
|
|
153
|
+
}
|
|
154
|
+
return await synthesizePreflightResultFromCommittedRun({
|
|
155
|
+
storage: cache.targetStorage,
|
|
156
|
+
runDir: input.runDir,
|
|
157
|
+
keyPrefix: cache.keyPrefix,
|
|
158
|
+
schemaVersion: effectiveSchemaVersion,
|
|
159
|
+
budgetCaps: mapped.budget,
|
|
160
|
+
includeSelectedContext,
|
|
161
|
+
syncInvocationSnapshotDirectory,
|
|
162
|
+
...(lifecycle == null ? {} : { lifecycle }),
|
|
163
|
+
});
|
|
164
164
|
});
|
|
165
|
-
}
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
if (!(error instanceof ContextBuilderCommittedRunChangedError)) {
|
|
168
|
+
throw error;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
166
171
|
if (hit !== undefined) {
|
|
167
172
|
await lifecycle?.complete(workflowLifecycleTerminalStatus(hit), {
|
|
168
173
|
artifactRunId: hit.source_run_id,
|
|
@@ -193,152 +198,188 @@ export function createWorkflowContextBuilderRunner(options = {}) {
|
|
|
193
198
|
});
|
|
194
199
|
const tempId = runIdFactory();
|
|
195
200
|
const tempInput = { ...mapped, run_id: tempId };
|
|
196
|
-
const response = await cb(tempInput, {
|
|
197
|
-
runsDir,
|
|
198
|
-
semaphore,
|
|
199
|
-
...(registry == null ? {} : { registry }),
|
|
200
|
-
...(input.allowRootWideDiscovery == null
|
|
201
|
-
? {}
|
|
202
|
-
: { allowRootWideDiscovery: input.allowRootWideDiscovery }),
|
|
203
|
-
...(opts.signal == null ? {} : { signal: opts.signal }),
|
|
204
|
-
...(lifecycle == null ? {} : { lifecycleController: lifecycle }),
|
|
205
|
-
...(preflightSessionLogContext == null
|
|
206
|
-
? {}
|
|
207
|
-
: { sessionLogContext: preflightSessionLogContext }),
|
|
208
|
-
});
|
|
209
|
-
throwIfAborted(opts.signal);
|
|
210
|
-
const receipt = parseReceiptResponse(response);
|
|
211
201
|
const tempStorage = resolveContextBuilderRunPaths(runsDir, tempId);
|
|
212
202
|
// The id of the run this call will return as its live source. Eviction in
|
|
213
203
|
// the finally must protect it so small/zero retention bounds cannot delete
|
|
214
204
|
// the run whose source_artifact_dir we are about to hand back.
|
|
215
205
|
let liveSourceRunId = tempId;
|
|
216
|
-
|
|
217
|
-
const tempManifest = await readManifest(tempStorage.manifestJson);
|
|
218
|
-
// Degraded fallback selections (delegate failure_policy:"fallback") must
|
|
219
|
-
// NEVER enter the shared wfctx cache: a cached fallback would be replayed
|
|
220
|
-
// for a later fail-closed failure_policy:"fail" request (silently
|
|
221
|
-
// succeeding instead of failing) and would mask genuine delegated
|
|
222
|
-
// successes. Not caching also lets a later identical request retry
|
|
223
|
-
// delegation rather than reusing a stale degraded bundle. The manifest
|
|
224
|
-
// is the authoritative persisted source; fall back to the receipt.
|
|
225
|
-
const fallbackUsed = tempManifest.delegate?.fallback_used === true ||
|
|
226
|
-
receipt.delegate?.fallback_used === true;
|
|
227
|
-
const selectedPaths = await resolveSelectedContextPaths(tempManifest, mapped.roots);
|
|
228
|
-
const gate = await evaluatePostCbPromotionGate({
|
|
229
|
-
roots: mapped.roots,
|
|
230
|
-
selectedPaths,
|
|
231
|
-
workspaceSignature,
|
|
232
|
-
signatureCoveredPaths,
|
|
233
|
-
});
|
|
206
|
+
const consumeCommittedRun = async (response, storageOps) => {
|
|
234
207
|
throwIfAborted(opts.signal);
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
...workflowResultLifecyclePatch(resultBeforeMaterialization, lifecycle),
|
|
277
|
-
});
|
|
208
|
+
const receipt = parseReceiptResponse(response);
|
|
209
|
+
return await withCommittedContextBuilderRunMutationLease(tempStorage, async (sourceOps) => {
|
|
210
|
+
const tempManifest = await readManifest(tempStorage.manifestJson, sourceOps);
|
|
211
|
+
// Degraded fallback selections (delegate failure_policy:"fallback") must
|
|
212
|
+
// NEVER enter the shared wfctx cache: a cached fallback would be replayed
|
|
213
|
+
// for a later fail-closed failure_policy:"fail" request (silently
|
|
214
|
+
// succeeding instead of failing) and would mask genuine delegated
|
|
215
|
+
// successes. Not caching also lets a later identical request retry
|
|
216
|
+
// delegation rather than reusing a stale degraded bundle. The same
|
|
217
|
+
// holds for a delegated selection that proceeded with external
|
|
218
|
+
// evidence gaps (isDelegateDegradedForCache). The manifest is the
|
|
219
|
+
// authoritative persisted source; fall back to the receipt.
|
|
220
|
+
const delegateDegraded = isDelegateDegradedForCache(tempManifest.delegate) ||
|
|
221
|
+
isDelegateDegradedForCache(receipt.delegate);
|
|
222
|
+
const selectedPaths = await resolveSelectedContextPaths(tempManifest, mapped.roots);
|
|
223
|
+
const gate = await evaluatePostCbPromotionGate({
|
|
224
|
+
roots: mapped.roots,
|
|
225
|
+
selectedPaths,
|
|
226
|
+
workspaceSignature,
|
|
227
|
+
signatureCoveredPaths,
|
|
228
|
+
});
|
|
229
|
+
throwIfAborted(opts.signal);
|
|
230
|
+
if (!delegateDegraded
|
|
231
|
+
&& gate?.selectedFilesCovered === true
|
|
232
|
+
&& gate.postSig === preSig) {
|
|
233
|
+
try {
|
|
234
|
+
await lifecycle?.transition("materializing");
|
|
235
|
+
return await withPromotedContextBuilderRun(tempStorage.runDir, cache.wfctxId, async (promoted, targetOps) => {
|
|
236
|
+
// Promotion completed under source→target locks. Keep the target
|
|
237
|
+
// lease through this authoritative manifest read and final copy.
|
|
238
|
+
liveSourceRunId = cache.wfctxId;
|
|
239
|
+
const promotedManifest = await readManifest(promoted.manifestJson, targetOps);
|
|
240
|
+
const resultBeforeMaterialization = buildPreflightResult({
|
|
241
|
+
receipt: createReceiptFromManifest(promotedManifest, promoted),
|
|
242
|
+
sourceRunId: cache.wfctxId,
|
|
243
|
+
sourceArtifactDir: promoted.runDir,
|
|
244
|
+
cache: {
|
|
245
|
+
hit: false,
|
|
246
|
+
write: true,
|
|
247
|
+
target_id: cache.wfctxId,
|
|
248
|
+
key_prefix: cache.keyPrefix,
|
|
278
249
|
},
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
250
|
+
copiedPaths: [],
|
|
251
|
+
schemaVersion: effectiveSchemaVersion,
|
|
252
|
+
observability: preflightObservabilityFromManifest(tempManifest, mapped.budget),
|
|
253
|
+
coverage: coverageFromManifest(tempManifest),
|
|
254
|
+
});
|
|
255
|
+
const copiedPaths = await materializeWorkflowContext({
|
|
256
|
+
artifacts: promotedManifest.artifacts,
|
|
257
|
+
sourceRunDir: promoted.runDir,
|
|
258
|
+
workflowRunDir: input.runDir,
|
|
259
|
+
includeSelectedContext,
|
|
260
|
+
syncInvocationSnapshotDirectory,
|
|
261
|
+
...(lifecycle == null
|
|
262
|
+
? {}
|
|
263
|
+
: { contextRunId: lifecycle.contextRunId }),
|
|
264
|
+
...(lifecycle == null
|
|
265
|
+
? {}
|
|
266
|
+
: {
|
|
267
|
+
beforeManifestCommit: async () => {
|
|
268
|
+
await lifecycle?.transition("committing", {
|
|
269
|
+
artifactRunId: resultBeforeMaterialization.source_run_id,
|
|
270
|
+
cache: {
|
|
271
|
+
lookup: "miss",
|
|
272
|
+
write: "written",
|
|
273
|
+
reason_code: cacheReason,
|
|
274
|
+
},
|
|
275
|
+
...workflowResultLifecyclePatch(resultBeforeMaterialization, lifecycle),
|
|
276
|
+
});
|
|
277
|
+
},
|
|
278
|
+
}),
|
|
279
|
+
});
|
|
280
|
+
const result = {
|
|
281
|
+
...resultBeforeMaterialization,
|
|
282
|
+
copied_paths: copiedPaths,
|
|
283
|
+
};
|
|
284
|
+
await lifecycle?.complete(workflowLifecycleTerminalStatus(result), {
|
|
285
|
+
artifactRunId: result.source_run_id,
|
|
286
|
+
...workflowResultLifecyclePatch(result, lifecycle),
|
|
287
|
+
});
|
|
288
|
+
return result;
|
|
289
|
+
}, sourceOps);
|
|
290
|
+
}
|
|
291
|
+
catch (error) {
|
|
292
|
+
if (error instanceof ContextBuilderAncillaryPromotionError) {
|
|
293
|
+
logger.warn({
|
|
294
|
+
reason_code: error.reasonCode,
|
|
295
|
+
source_run_id: tempId,
|
|
296
|
+
}, "workflow context_builder cache promotion skipped because invocation audit ancillary promotion failed");
|
|
297
|
+
}
|
|
298
|
+
else if (!isPromoteClaimConflict(error)) {
|
|
299
|
+
throw error;
|
|
300
|
+
}
|
|
294
301
|
}
|
|
295
302
|
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
303
|
+
// Non-promote (or promote-claim-conflict) path: copy from the surviving
|
|
304
|
+
// temp run, which is the authoritative source for the returned id.
|
|
305
|
+
await lifecycle?.transition("materializing");
|
|
306
|
+
const resultBeforeMaterialization = buildPreflightResult({
|
|
307
|
+
receipt: createReceiptFromManifest(tempManifest, tempStorage),
|
|
308
|
+
sourceRunId: tempId,
|
|
309
|
+
sourceArtifactDir: tempStorage.runDir,
|
|
310
|
+
cache: {
|
|
311
|
+
hit: false,
|
|
312
|
+
write: false,
|
|
313
|
+
target_id: null,
|
|
314
|
+
key_prefix: cache.keyPrefix,
|
|
315
|
+
},
|
|
316
|
+
copiedPaths: [],
|
|
317
|
+
schemaVersion: effectiveSchemaVersion,
|
|
318
|
+
observability: preflightObservabilityFromManifest(tempManifest, mapped.budget),
|
|
319
|
+
coverage: coverageFromManifest(tempManifest),
|
|
320
|
+
});
|
|
321
|
+
const copiedPaths = await materializeWorkflowContext({
|
|
322
|
+
artifacts: tempManifest.artifacts,
|
|
323
|
+
sourceRunDir: tempStorage.runDir,
|
|
324
|
+
workflowRunDir: input.runDir,
|
|
325
|
+
includeSelectedContext,
|
|
326
|
+
syncInvocationSnapshotDirectory,
|
|
327
|
+
...(lifecycle == null
|
|
328
|
+
? {}
|
|
329
|
+
: { contextRunId: lifecycle.contextRunId }),
|
|
330
|
+
...(lifecycle == null
|
|
331
|
+
? {}
|
|
332
|
+
: {
|
|
333
|
+
beforeManifestCommit: async () => {
|
|
334
|
+
await lifecycle?.transition("committing", {
|
|
335
|
+
artifactRunId: resultBeforeMaterialization.source_run_id,
|
|
336
|
+
cache: {
|
|
337
|
+
lookup: "miss",
|
|
338
|
+
write: "skipped",
|
|
339
|
+
reason_code: cacheReason,
|
|
340
|
+
},
|
|
341
|
+
...workflowResultLifecyclePatch(resultBeforeMaterialization, lifecycle),
|
|
342
|
+
});
|
|
343
|
+
},
|
|
344
|
+
}),
|
|
345
|
+
});
|
|
346
|
+
const result = {
|
|
347
|
+
...resultBeforeMaterialization,
|
|
348
|
+
copied_paths: copiedPaths,
|
|
349
|
+
};
|
|
350
|
+
await lifecycle?.complete(workflowLifecycleTerminalStatus(result), {
|
|
351
|
+
artifactRunId: result.source_run_id,
|
|
352
|
+
...workflowResultLifecyclePatch(result, lifecycle),
|
|
353
|
+
});
|
|
354
|
+
return result;
|
|
355
|
+
}, storageOps);
|
|
356
|
+
};
|
|
357
|
+
let retainedResult;
|
|
358
|
+
try {
|
|
359
|
+
const response = await cb(tempInput, {
|
|
360
|
+
runsDir,
|
|
361
|
+
semaphore,
|
|
362
|
+
...(registry == null ? {} : { registry }),
|
|
363
|
+
...(input.allowRootWideDiscovery == null
|
|
318
364
|
? {}
|
|
319
|
-
: {
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
});
|
|
333
|
-
const result = {
|
|
334
|
-
...resultBeforeMaterialization,
|
|
335
|
-
copied_paths: copiedPaths,
|
|
336
|
-
};
|
|
337
|
-
await lifecycle?.complete(workflowLifecycleTerminalStatus(result), {
|
|
338
|
-
artifactRunId: result.source_run_id,
|
|
339
|
-
...workflowResultLifecyclePatch(result, lifecycle),
|
|
365
|
+
: { allowRootWideDiscovery: input.allowRootWideDiscovery }),
|
|
366
|
+
...(opts.signal == null ? {} : { signal: opts.signal }),
|
|
367
|
+
...(lifecycle == null ? {} : { lifecycleController: lifecycle }),
|
|
368
|
+
...(preflightSessionLogContext == null
|
|
369
|
+
? {}
|
|
370
|
+
: { sessionLogContext: preflightSessionLogContext }),
|
|
371
|
+
retainCommittedRun: async (committedResponse, committedStorage, leasedOps) => {
|
|
372
|
+
if (committedStorage.runId !== tempStorage.runId
|
|
373
|
+
|| committedStorage.runDir !== tempStorage.runDir) {
|
|
374
|
+
throw new ExecutionError("context_builder retained an unexpected workflow temp run");
|
|
375
|
+
}
|
|
376
|
+
retainedResult = await consumeCommittedRun(committedResponse, leasedOps);
|
|
377
|
+
},
|
|
340
378
|
});
|
|
341
|
-
|
|
379
|
+
if (retainedResult !== undefined) {
|
|
380
|
+
return retainedResult;
|
|
381
|
+
}
|
|
382
|
+
return await consumeCommittedRun(response);
|
|
342
383
|
}
|
|
343
384
|
finally {
|
|
344
385
|
// Best-effort, prefix-scoped/TTL-guarded eviction on every completed
|
|
@@ -391,11 +432,141 @@ export function createWorkflowContextBuilderRunner(options = {}) {
|
|
|
391
432
|
};
|
|
392
433
|
}
|
|
393
434
|
/**
|
|
394
|
-
* Subdirectory of the workflow run dir holding
|
|
395
|
-
*
|
|
396
|
-
* session-log subtree and to pair it with the persisted lifecycle context_run_id.
|
|
435
|
+
* Subdirectory of the workflow run dir holding operation-scoped preflight
|
|
436
|
+
* metadata: the session-log generation and immutable invocation snapshots.
|
|
397
437
|
*/
|
|
398
438
|
const PREFLIGHT_SESSION_LOG_DIR = ".context-preflight";
|
|
439
|
+
async function materializeWorkflowContext(input) {
|
|
440
|
+
const copiedPaths = await copyBundleArtifactsIntoRun(input.artifacts, input.workflowRunDir, {
|
|
441
|
+
includeSelectedContext: input.includeSelectedContext,
|
|
442
|
+
...(input.beforeManifestCommit == null
|
|
443
|
+
? {}
|
|
444
|
+
: { beforeManifestCommit: input.beforeManifestCommit }),
|
|
445
|
+
});
|
|
446
|
+
if (input.contextRunId !== undefined) {
|
|
447
|
+
await snapshotWorkflowInvocationAudit({
|
|
448
|
+
sourceRunDir: input.sourceRunDir,
|
|
449
|
+
workflowRunDir: input.workflowRunDir,
|
|
450
|
+
contextRunId: input.contextRunId,
|
|
451
|
+
syncInvocationSnapshotDirectory: input.syncInvocationSnapshotDirectory,
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
return copiedPaths;
|
|
455
|
+
}
|
|
456
|
+
async function snapshotWorkflowInvocationAudit(input) {
|
|
457
|
+
let source;
|
|
458
|
+
try {
|
|
459
|
+
source = await readContextBuilderInvocationAuditSidecar(input.sourceRunDir);
|
|
460
|
+
}
|
|
461
|
+
catch (error) {
|
|
462
|
+
logger.warn({ err: error, source_artifact_dir: input.sourceRunDir }, "workflow context_builder invocation audit snapshot source rejected");
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
if (source === undefined)
|
|
466
|
+
return;
|
|
467
|
+
const workflowRunRoot = await realpath(input.workflowRunDir);
|
|
468
|
+
const preflightDir = await admitExactWorkflowDirectory(workflowRunRoot, PREFLIGHT_SESSION_LOG_DIR, "workflow context_builder invocation audit snapshot directory");
|
|
469
|
+
const admittedSnapshotDir = await admitExactWorkflowDirectory(preflightDir, input.contextRunId, "workflow context_builder invocation audit snapshot directory");
|
|
470
|
+
assertContainedPath(workflowRunRoot, admittedSnapshotDir, "workflow context_builder invocation audit snapshot escaped the workflow run");
|
|
471
|
+
const target = join(admittedSnapshotDir, CONTEXT_BUILDER_INVOCATION_AUDIT_FILENAME);
|
|
472
|
+
const temp = join(admittedSnapshotDir, `.${CONTEXT_BUILDER_INVOCATION_AUDIT_FILENAME}.${process.pid}.${randomUUID()}.tmp`);
|
|
473
|
+
let ownsTemp = false;
|
|
474
|
+
let publicationAccepted = false;
|
|
475
|
+
try {
|
|
476
|
+
let handle;
|
|
477
|
+
try {
|
|
478
|
+
handle = await open(temp, "wx", 0o600);
|
|
479
|
+
ownsTemp = true;
|
|
480
|
+
await handle.writeFile(source.serialized, "utf8");
|
|
481
|
+
await handle.chmod(0o600);
|
|
482
|
+
await handle.sync();
|
|
483
|
+
}
|
|
484
|
+
finally {
|
|
485
|
+
await handle?.close();
|
|
486
|
+
}
|
|
487
|
+
try {
|
|
488
|
+
await link(temp, target);
|
|
489
|
+
}
|
|
490
|
+
catch (error) {
|
|
491
|
+
if (!isNodeError(error) || error.code !== "EEXIST")
|
|
492
|
+
throw error;
|
|
493
|
+
let incumbent;
|
|
494
|
+
try {
|
|
495
|
+
incumbent = await readContextBuilderInvocationAuditSidecar(admittedSnapshotDir);
|
|
496
|
+
}
|
|
497
|
+
catch (error) {
|
|
498
|
+
if (!isContextBuilderInvocationAuditSidecarProvenInvalid(error)) {
|
|
499
|
+
throw error;
|
|
500
|
+
}
|
|
501
|
+
logger.warn({ err: error, incumbent_path: target }, "workflow context_builder invocation audit snapshot incumbent rejected; preserving existing entry");
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
if (incumbent?.serialized !== source.serialized) {
|
|
505
|
+
throw new ExecutionError("workflow context_builder invocation audit snapshot conflicts with existing bytes");
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
publicationAccepted = true;
|
|
509
|
+
}
|
|
510
|
+
finally {
|
|
511
|
+
if (ownsTemp) {
|
|
512
|
+
try {
|
|
513
|
+
await rm(temp, { force: true });
|
|
514
|
+
}
|
|
515
|
+
catch (error) {
|
|
516
|
+
logger.warn({ err: error, temporary_path: temp }, "workflow context_builder invocation audit snapshot temp cleanup failed");
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
if (publicationAccepted) {
|
|
520
|
+
await syncSnapshotDirectoriesBestEffort([admittedSnapshotDir, preflightDir, workflowRunRoot], input.syncInvocationSnapshotDirectory);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
async function syncDirectoryEntry(path) {
|
|
525
|
+
const handle = await open(path, "r");
|
|
526
|
+
try {
|
|
527
|
+
await handle.sync();
|
|
528
|
+
}
|
|
529
|
+
finally {
|
|
530
|
+
await handle.close();
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
async function syncSnapshotDirectoriesBestEffort(directories, syncDirectory) {
|
|
534
|
+
for (const directory of directories) {
|
|
535
|
+
try {
|
|
536
|
+
await syncDirectory(directory);
|
|
537
|
+
}
|
|
538
|
+
catch (error) {
|
|
539
|
+
logger.warn({ err: error, directory }, "workflow context_builder invocation audit snapshot directory sync failed");
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
async function admitExactWorkflowDirectory(parent, name, label) {
|
|
544
|
+
const path = join(parent, name);
|
|
545
|
+
try {
|
|
546
|
+
await mkdir(path, { mode: 0o700 });
|
|
547
|
+
}
|
|
548
|
+
catch (error) {
|
|
549
|
+
if (!isNodeError(error) || error.code !== "EEXIST")
|
|
550
|
+
throw error;
|
|
551
|
+
}
|
|
552
|
+
try {
|
|
553
|
+
const [stats, canonicalPath] = await Promise.all([
|
|
554
|
+
lstat(path),
|
|
555
|
+
realpath(path),
|
|
556
|
+
]);
|
|
557
|
+
if (stats.isSymbolicLink() ||
|
|
558
|
+
!stats.isDirectory() ||
|
|
559
|
+
canonicalPath !== path) {
|
|
560
|
+
throw new ExecutionError(`${label} is unsafe`);
|
|
561
|
+
}
|
|
562
|
+
return path;
|
|
563
|
+
}
|
|
564
|
+
catch (error) {
|
|
565
|
+
if (error instanceof ExecutionError)
|
|
566
|
+
throw error;
|
|
567
|
+
throw new ExecutionError(`${label} is unsafe`);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
399
570
|
/**
|
|
400
571
|
* Create-or-read the preflight session-log generation sidecar under the workflow
|
|
401
572
|
* run dir, then pair it with the controller-minted operation id. Create-or-read
|
|
@@ -405,8 +576,8 @@ const PREFLIGHT_SESSION_LOG_DIR = ".context-preflight";
|
|
|
405
576
|
*/
|
|
406
577
|
async function resolvePreflightSessionLogContext(runDir, contextRunId) {
|
|
407
578
|
try {
|
|
408
|
-
const
|
|
409
|
-
await
|
|
579
|
+
const workflowRunRoot = await realpath(runDir);
|
|
580
|
+
const sidecarDir = await admitExactWorkflowDirectory(workflowRunRoot, PREFLIGHT_SESSION_LOG_DIR, "workflow context_builder preflight metadata directory");
|
|
410
581
|
const existing = await readSessionLogGeneration(sidecarDir);
|
|
411
582
|
const contextGeneration = existing.kind === "available"
|
|
412
583
|
? existing.sessionLogGeneration
|
|
@@ -433,6 +604,17 @@ function workflowLifecycleExecutionConfig(input) {
|
|
|
433
604
|
finalizer: { configured: true, enabled: finalizerEnabled },
|
|
434
605
|
};
|
|
435
606
|
}
|
|
607
|
+
/**
|
|
608
|
+
* A delegate bundle that is degraded — a deterministic fallback, or a
|
|
609
|
+
* delegated selection that proceeded with known external evidence gaps
|
|
610
|
+
* (status "partial", fallback_used false, external_gap_policy "degrade") — is
|
|
611
|
+
* never promoted into or served from the wfctx cache. The gap policy is not
|
|
612
|
+
* in the cache key, so a cached degraded bundle could otherwise satisfy a later
|
|
613
|
+
* fail-closed request.
|
|
614
|
+
*/
|
|
615
|
+
function isDelegateDegradedForCache(delegate) {
|
|
616
|
+
return delegate?.fallback_used === true || delegate?.status === "partial";
|
|
617
|
+
}
|
|
436
618
|
function workflowLifecycleTerminalStatus(result) {
|
|
437
619
|
return result.delegate?.fallback_used === true || result.status === "partial"
|
|
438
620
|
? "partial"
|
|
@@ -624,7 +806,9 @@ async function synthesizePreflightResultFromCommittedRun(input) {
|
|
|
624
806
|
// artifact, or a future code path. Treat it as a cache MISS (return undefined,
|
|
625
807
|
// the same value the ENOENT/not-usable case returns) so runOrReuse falls
|
|
626
808
|
// through and re-runs the builder; a real "fail" policy then fails closed.
|
|
627
|
-
|
|
809
|
+
// A degraded external-gap bundle (status "partial" without fallback) is
|
|
810
|
+
// refused the same way.
|
|
811
|
+
if (isDelegateDegradedForCache(manifest.delegate)) {
|
|
628
812
|
return undefined;
|
|
629
813
|
}
|
|
630
814
|
const receipt = createReceiptFromManifest(manifest, input.storage);
|
|
@@ -649,8 +833,15 @@ async function synthesizePreflightResultFromCommittedRun(input) {
|
|
|
649
833
|
...workflowResultLifecyclePatch(resultBeforeMaterialization, input.lifecycle, true),
|
|
650
834
|
});
|
|
651
835
|
await input.lifecycle?.transition("materializing");
|
|
652
|
-
const copiedPaths = await
|
|
836
|
+
const copiedPaths = await materializeWorkflowContext({
|
|
837
|
+
artifacts: manifest.artifacts,
|
|
838
|
+
sourceRunDir: input.storage.runDir,
|
|
839
|
+
workflowRunDir: input.runDir,
|
|
653
840
|
includeSelectedContext: input.includeSelectedContext,
|
|
841
|
+
syncInvocationSnapshotDirectory: input.syncInvocationSnapshotDirectory,
|
|
842
|
+
...(input.lifecycle == null
|
|
843
|
+
? {}
|
|
844
|
+
: { contextRunId: input.lifecycle.contextRunId }),
|
|
654
845
|
...(input.lifecycle == null
|
|
655
846
|
? {}
|
|
656
847
|
: {
|
|
@@ -853,8 +1044,8 @@ function nonNegativeInteger(value) {
|
|
|
853
1044
|
? value
|
|
854
1045
|
: 0;
|
|
855
1046
|
}
|
|
856
|
-
async function readManifest(manifestPath) {
|
|
857
|
-
return JSON.parse(await readFile(manifestPath, "utf8"));
|
|
1047
|
+
async function readManifest(manifestPath, ops) {
|
|
1048
|
+
return JSON.parse(await (ops?.readFile ?? readFile)(manifestPath, "utf8"));
|
|
858
1049
|
}
|
|
859
1050
|
async function resolveSelectedContextPaths(manifest, roots) {
|
|
860
1051
|
const selected = Array.isArray(manifest["selected_context"])
|
|
@@ -917,9 +1108,8 @@ async function normalizeExistingPath(path) {
|
|
|
917
1108
|
}
|
|
918
1109
|
}
|
|
919
1110
|
function isPromoteClaimConflict(error) {
|
|
920
|
-
return
|
|
921
|
-
|
|
922
|
-
&& error.message.startsWith("context_builder run_id conflicts with an incomplete or active run:"));
|
|
1111
|
+
return error instanceof ContextBuilderRunClaimConflictError
|
|
1112
|
+
|| error instanceof ContextBuilderActiveRunClaimConflictError;
|
|
923
1113
|
}
|
|
924
1114
|
function throwIfAborted(signal) {
|
|
925
1115
|
if (signal?.aborted === true) {
|