clinkx 0.2.3 → 1.0.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/CHANGELOG.md +33 -0
- package/LICENSE +10 -0
- package/README.md +113 -18
- package/clinkx-workflows/dist/allowed-roots.d.ts +1 -0
- package/clinkx-workflows/dist/allowed-roots.js +5 -0
- package/clinkx-workflows/dist/allowed-roots.js.map +1 -0
- package/clinkx-workflows/dist/artifacts.d.ts +20 -1
- package/clinkx-workflows/dist/artifacts.js +38 -9
- package/clinkx-workflows/dist/artifacts.js.map +1 -1
- package/clinkx-workflows/dist/backend.d.ts +4 -0
- package/clinkx-workflows/dist/citation-check.d.ts +40 -0
- package/clinkx-workflows/dist/citation-check.js +348 -0
- package/clinkx-workflows/dist/citation-check.js.map +1 -0
- package/clinkx-workflows/dist/clink-client.d.ts +2 -1
- package/clinkx-workflows/dist/clink-client.js +17 -4
- package/clinkx-workflows/dist/clink-client.js.map +1 -1
- package/clinkx-workflows/dist/config.d.ts +145 -16
- package/clinkx-workflows/dist/config.js +384 -26
- package/clinkx-workflows/dist/config.js.map +1 -1
- package/clinkx-workflows/dist/contained-file.d.ts +172 -0
- package/clinkx-workflows/dist/contained-file.js +483 -0
- package/clinkx-workflows/dist/contained-file.js.map +1 -0
- package/clinkx-workflows/dist/context-builder-lifecycle-contract.d.ts +416 -0
- package/clinkx-workflows/dist/context-builder-lifecycle-contract.js +328 -0
- package/clinkx-workflows/dist/context-builder-lifecycle-contract.js.map +1 -0
- package/clinkx-workflows/dist/context-builder-lifecycle-router.d.ts +24 -0
- package/clinkx-workflows/dist/context-builder-lifecycle-router.js +39 -0
- package/clinkx-workflows/dist/context-builder-lifecycle-router.js.map +1 -0
- package/clinkx-workflows/dist/context-cache-key.d.ts +53 -0
- package/clinkx-workflows/dist/context-cache-key.js +91 -0
- package/clinkx-workflows/dist/context-cache-key.js.map +1 -0
- package/clinkx-workflows/dist/context-mode-resolver.d.ts +27 -0
- package/clinkx-workflows/dist/context-mode-resolver.js +126 -0
- package/clinkx-workflows/dist/context-mode-resolver.js.map +1 -0
- package/clinkx-workflows/dist/context-preflight.d.ts +184 -0
- package/clinkx-workflows/dist/context-preflight.js +91 -0
- package/clinkx-workflows/dist/context-preflight.js.map +1 -0
- package/clinkx-workflows/dist/council-expander.d.ts +1 -1
- package/clinkx-workflows/dist/council-expander.js +2 -1
- package/clinkx-workflows/dist/council-expander.js.map +1 -1
- package/clinkx-workflows/dist/dashboard/activity-contract.d.ts +165 -0
- package/clinkx-workflows/dist/dashboard/activity-contract.js +105 -0
- package/clinkx-workflows/dist/dashboard/activity-contract.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/activity-lease.d.ts +25 -0
- package/clinkx-workflows/dist/dashboard/activity-lease.js +34 -0
- package/clinkx-workflows/dist/dashboard/activity-lease.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/activity-reader.d.ts +86 -0
- package/clinkx-workflows/dist/dashboard/activity-reader.js +480 -0
- package/clinkx-workflows/dist/dashboard/activity-reader.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/api-routes.d.ts +36 -0
- package/clinkx-workflows/dist/dashboard/api-routes.js +1047 -0
- package/clinkx-workflows/dist/dashboard/api-routes.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/artifact-index.d.ts +37 -0
- package/clinkx-workflows/dist/dashboard/artifact-index.js +145 -0
- package/clinkx-workflows/dist/dashboard/artifact-index.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/auth/challenge-store.d.ts +31 -0
- package/clinkx-workflows/dist/dashboard/auth/challenge-store.js +65 -0
- package/clinkx-workflows/dist/dashboard/auth/challenge-store.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/auth/controller.d.ts +26 -0
- package/clinkx-workflows/dist/dashboard/auth/controller.js +596 -0
- package/clinkx-workflows/dist/dashboard/auth/controller.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/auth/credential-store.d.ts +60 -0
- package/clinkx-workflows/dist/dashboard/auth/credential-store.js +776 -0
- package/clinkx-workflows/dist/dashboard/auth/credential-store.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/auth/enrollment-gate.d.ts +9 -0
- package/clinkx-workflows/dist/dashboard/auth/enrollment-gate.js +44 -0
- package/clinkx-workflows/dist/dashboard/auth/enrollment-gate.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/auth/session-store.d.ts +17 -0
- package/clinkx-workflows/dist/dashboard/auth/session-store.js +77 -0
- package/clinkx-workflows/dist/dashboard/auth/session-store.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/auth/webauthn-service.d.ts +25 -0
- package/clinkx-workflows/dist/dashboard/auth/webauthn-service.js +71 -0
- package/clinkx-workflows/dist/dashboard/auth/webauthn-service.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/context-run-liveness.d.ts +37 -0
- package/clinkx-workflows/dist/dashboard/context-run-liveness.js +49 -0
- package/clinkx-workflows/dist/dashboard/context-run-liveness.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/context-run-reader.d.ts +222 -0
- package/clinkx-workflows/dist/dashboard/context-run-reader.js +1178 -0
- package/clinkx-workflows/dist/dashboard/context-run-reader.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/contracts.d.ts +8936 -0
- package/clinkx-workflows/dist/dashboard/contracts.js +1157 -0
- package/clinkx-workflows/dist/dashboard/contracts.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/generation.d.ts +14 -0
- package/clinkx-workflows/dist/dashboard/generation.js +41 -0
- package/clinkx-workflows/dist/dashboard/generation.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/index.d.ts +28 -0
- package/clinkx-workflows/dist/dashboard/index.js +16 -0
- package/clinkx-workflows/dist/dashboard/index.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/lazy-content.d.ts +101 -0
- package/clinkx-workflows/dist/dashboard/lazy-content.js +748 -0
- package/clinkx-workflows/dist/dashboard/lazy-content.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/progress-report-contract.d.ts +303 -0
- package/clinkx-workflows/dist/dashboard/progress-report-contract.js +221 -0
- package/clinkx-workflows/dist/dashboard/progress-report-contract.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/progress-report-reader.d.ts +50 -0
- package/clinkx-workflows/dist/dashboard/progress-report-reader.js +581 -0
- package/clinkx-workflows/dist/dashboard/progress-report-reader.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/progress-report-status-overlay.d.ts +89 -0
- package/clinkx-workflows/dist/dashboard/progress-report-status-overlay.js +71 -0
- package/clinkx-workflows/dist/dashboard/progress-report-status-overlay.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/progress-report-status-store.d.ts +28 -0
- package/clinkx-workflows/dist/dashboard/progress-report-status-store.js +110 -0
- package/clinkx-workflows/dist/dashboard/progress-report-status-store.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/read-model.d.ts +86 -0
- package/clinkx-workflows/dist/dashboard/read-model.js +440 -0
- package/clinkx-workflows/dist/dashboard/read-model.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/request-admission.d.ts +31 -0
- package/clinkx-workflows/dist/dashboard/request-admission.js +126 -0
- package/clinkx-workflows/dist/dashboard/request-admission.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/scanner.d.ts +75 -0
- package/clinkx-workflows/dist/dashboard/scanner.js +1110 -0
- package/clinkx-workflows/dist/dashboard/scanner.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/server-factory.d.ts +50 -0
- package/clinkx-workflows/dist/dashboard/server-factory.js +431 -0
- package/clinkx-workflows/dist/dashboard/server-factory.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/session-log-contract.d.ts +2611 -0
- package/clinkx-workflows/dist/dashboard/session-log-contract.js +480 -0
- package/clinkx-workflows/dist/dashboard/session-log-contract.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/session-log-identity.d.ts +21 -0
- package/clinkx-workflows/dist/dashboard/session-log-identity.js +101 -0
- package/clinkx-workflows/dist/dashboard/session-log-identity.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/session-log-journal.d.ts +43 -0
- package/clinkx-workflows/dist/dashboard/session-log-journal.js +522 -0
- package/clinkx-workflows/dist/dashboard/session-log-journal.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/session-log-reader.d.ts +61 -0
- package/clinkx-workflows/dist/dashboard/session-log-reader.js +378 -0
- package/clinkx-workflows/dist/dashboard/session-log-reader.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/session-log-redaction.d.ts +6 -0
- package/clinkx-workflows/dist/dashboard/session-log-redaction.js +367 -0
- package/clinkx-workflows/dist/dashboard/session-log-redaction.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/session-log-retention.d.ts +23 -0
- package/clinkx-workflows/dist/dashboard/session-log-retention.js +212 -0
- package/clinkx-workflows/dist/dashboard/session-log-retention.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/static-responses.d.ts +10 -0
- package/clinkx-workflows/dist/dashboard/static-responses.js +94 -0
- package/clinkx-workflows/dist/dashboard/static-responses.js.map +1 -0
- package/clinkx-workflows/dist/dashboard/worker-lock-observer.d.ts +28 -0
- package/clinkx-workflows/dist/dashboard/worker-lock-observer.js +241 -0
- package/clinkx-workflows/dist/dashboard/worker-lock-observer.js.map +1 -0
- package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
- package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
- package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-mono-latin-500-normal-CB9ihrfo.woff +0 -0
- package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
- package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-sans-latin-400-normal-CDDApCn2.woff2 +0 -0
- package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-sans-latin-400-normal-CYLoc0-x.woff +0 -0
- package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-sans-latin-500-normal-6ng42L7E.woff2 +0 -0
- package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-sans-latin-500-normal-BgVn5rGT.woff +0 -0
- package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-sans-latin-600-normal-Cu4Hd6ag.woff +0 -0
- package/clinkx-workflows/dist/dashboard-ui/assets/ibm-plex-sans-latin-600-normal-CuJfVYMP.woff2 +0 -0
- package/clinkx-workflows/dist/dashboard-ui/assets/index-DOkMXTfB.js +25 -0
- package/clinkx-workflows/dist/dashboard-ui/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
- package/clinkx-workflows/dist/dashboard-ui/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
- package/clinkx-workflows/dist/dashboard-ui/assets/jetbrains-mono-latin-500-normal-BWZEU5yA.woff2 +0 -0
- package/clinkx-workflows/dist/dashboard-ui/assets/jetbrains-mono-latin-500-normal-CJOVTJB7.woff +0 -0
- package/clinkx-workflows/dist/dashboard-ui/assets/style-ChJsn0KD.css +1 -0
- package/clinkx-workflows/dist/dashboard-ui/contracts/council-plan-review-input-v1.json +158 -0
- package/clinkx-workflows/dist/dashboard-ui/index.html +15 -0
- package/clinkx-workflows/dist/dashboard-ui/licenses/IBM-Plex-Mono-OFL.txt +93 -0
- package/clinkx-workflows/dist/dashboard-ui/licenses/IBM-Plex-Sans-OFL.txt +93 -0
- package/clinkx-workflows/dist/dashboard-ui/licenses/JetBrains-Mono-OFL.txt +93 -0
- package/clinkx-workflows/dist/dashboard-ui/licenses/NOTICE.md +32 -0
- package/clinkx-workflows/dist/dashboard-ui/theme-init.js +8 -0
- package/clinkx-workflows/dist/definition-normalizer.d.ts +19 -0
- package/clinkx-workflows/dist/definition-normalizer.js.map +1 -1
- package/clinkx-workflows/dist/delegate-validate.d.ts +78 -0
- package/clinkx-workflows/dist/delegate-validate.js +97 -0
- package/clinkx-workflows/dist/delegate-validate.js.map +1 -0
- package/clinkx-workflows/dist/engine.d.ts +141 -0
- package/clinkx-workflows/dist/engine.js +882 -28
- package/clinkx-workflows/dist/engine.js.map +1 -1
- package/clinkx-workflows/dist/errors.d.ts +2 -0
- package/clinkx-workflows/dist/errors.js.map +1 -1
- package/clinkx-workflows/dist/fingerprint.d.ts +1 -1
- package/clinkx-workflows/dist/fingerprint.js +1 -1
- package/clinkx-workflows/dist/index.d.ts +19 -0
- package/clinkx-workflows/dist/index.js +15 -0
- package/clinkx-workflows/dist/index.js.map +1 -1
- package/clinkx-workflows/dist/loader.d.ts +9 -3
- package/clinkx-workflows/dist/loader.js +92 -21
- package/clinkx-workflows/dist/loader.js.map +1 -1
- package/clinkx-workflows/dist/plan-review/admission.d.ts +160 -0
- package/clinkx-workflows/dist/plan-review/admission.js +290 -0
- package/clinkx-workflows/dist/plan-review/admission.js.map +1 -0
- package/clinkx-workflows/dist/plan-review/context-policy.d.ts +55 -0
- package/clinkx-workflows/dist/plan-review/context-policy.js +146 -0
- package/clinkx-workflows/dist/plan-review/context-policy.js.map +1 -0
- package/clinkx-workflows/dist/plan-review/contract.d.ts +763 -0
- package/clinkx-workflows/dist/plan-review/contract.js +289 -0
- package/clinkx-workflows/dist/plan-review/contract.js.map +1 -0
- package/clinkx-workflows/dist/plan-review/digest.d.ts +68 -0
- package/clinkx-workflows/dist/plan-review/digest.js +241 -0
- package/clinkx-workflows/dist/plan-review/digest.js.map +1 -0
- package/clinkx-workflows/dist/plan-review/discovery.d.ts +45 -0
- package/clinkx-workflows/dist/plan-review/discovery.js +36 -0
- package/clinkx-workflows/dist/plan-review/discovery.js.map +1 -0
- package/clinkx-workflows/dist/plan-review/execution-contract.d.ts +298 -0
- package/clinkx-workflows/dist/plan-review/execution-contract.js +194 -0
- package/clinkx-workflows/dist/plan-review/execution-contract.js.map +1 -0
- package/clinkx-workflows/dist/plan-review/expander.d.ts +48 -0
- package/clinkx-workflows/dist/plan-review/expander.js +243 -0
- package/clinkx-workflows/dist/plan-review/expander.js.map +1 -0
- package/clinkx-workflows/dist/plan-review/projector.d.ts +126 -0
- package/clinkx-workflows/dist/plan-review/projector.js +437 -0
- package/clinkx-workflows/dist/plan-review/projector.js.map +1 -0
- package/clinkx-workflows/dist/plan-review/publication.d.ts +95 -0
- package/clinkx-workflows/dist/plan-review/publication.js +182 -0
- package/clinkx-workflows/dist/plan-review/publication.js.map +1 -0
- package/clinkx-workflows/dist/plan-review/ranking-reducer.d.ts +34 -0
- package/clinkx-workflows/dist/plan-review/ranking-reducer.js +139 -0
- package/clinkx-workflows/dist/plan-review/ranking-reducer.js.map +1 -0
- package/clinkx-workflows/dist/plan-review/resume.d.ts +38 -0
- package/clinkx-workflows/dist/plan-review/resume.js +122 -0
- package/clinkx-workflows/dist/plan-review/resume.js.map +1 -0
- package/clinkx-workflows/dist/plan-review/rubric.d.ts +7 -0
- package/clinkx-workflows/dist/plan-review/rubric.js +24 -0
- package/clinkx-workflows/dist/plan-review/rubric.js.map +1 -0
- package/clinkx-workflows/dist/plan-review/run-state.d.ts +398 -0
- package/clinkx-workflows/dist/plan-review/run-state.js +183 -0
- package/clinkx-workflows/dist/plan-review/run-state.js.map +1 -0
- package/clinkx-workflows/dist/plan-review/runtime-policy.d.ts +74 -0
- package/clinkx-workflows/dist/plan-review/runtime-policy.js +186 -0
- package/clinkx-workflows/dist/plan-review/runtime-policy.js.map +1 -0
- package/clinkx-workflows/dist/plan-review/snapshot.d.ts +81 -0
- package/clinkx-workflows/dist/plan-review/snapshot.js +170 -0
- package/clinkx-workflows/dist/plan-review/snapshot.js.map +1 -0
- package/clinkx-workflows/dist/plan-review/stage-error.d.ts +19 -0
- package/clinkx-workflows/dist/plan-review/stage-error.js +20 -0
- package/clinkx-workflows/dist/plan-review/stage-error.js.map +1 -0
- package/clinkx-workflows/dist/post-processors/index.d.ts +20 -0
- package/clinkx-workflows/dist/post-processors/index.js +21 -0
- package/clinkx-workflows/dist/post-processors/index.js.map +1 -0
- package/clinkx-workflows/dist/prompt-budget.d.ts +7 -0
- package/clinkx-workflows/dist/prompt-budget.js +7 -1
- package/clinkx-workflows/dist/prompt-budget.js.map +1 -1
- package/clinkx-workflows/dist/reducers/index.js +2 -0
- package/clinkx-workflows/dist/reducers/index.js.map +1 -1
- package/clinkx-workflows/dist/run-lock-heartbeat.d.ts +2 -0
- package/clinkx-workflows/dist/run-lock-heartbeat.js +3 -0
- package/clinkx-workflows/dist/run-lock-heartbeat.js.map +1 -0
- package/clinkx-workflows/dist/run-summary/cards/council-plan-review.d.ts +34 -0
- package/clinkx-workflows/dist/run-summary/cards/council-plan-review.js +74 -0
- package/clinkx-workflows/dist/run-summary/cards/council-plan-review.js.map +1 -0
- package/clinkx-workflows/dist/run-summary/cards/index.js +5 -0
- package/clinkx-workflows/dist/run-summary/cards/index.js.map +1 -1
- package/clinkx-workflows/dist/run-summary.d.ts +13 -0
- package/clinkx-workflows/dist/run-summary.js +29 -1
- package/clinkx-workflows/dist/run-summary.js.map +1 -1
- package/clinkx-workflows/dist/schema.d.ts +76 -21
- package/clinkx-workflows/dist/schema.js +10 -1
- package/clinkx-workflows/dist/schema.js.map +1 -1
- package/clinkx-workflows/dist/seed-terms.d.ts +30 -0
- package/clinkx-workflows/dist/seed-terms.js +176 -0
- package/clinkx-workflows/dist/seed-terms.js.map +1 -0
- package/clinkx-workflows/dist/server.d.ts +5 -2
- package/clinkx-workflows/dist/server.js +82 -52
- package/clinkx-workflows/dist/server.js.map +1 -1
- package/clinkx-workflows/dist/shutdown.d.ts +18 -20
- package/clinkx-workflows/dist/shutdown.js +43 -61
- package/clinkx-workflows/dist/shutdown.js.map +1 -1
- package/clinkx-workflows/dist/state-schema.d.ts +38 -0
- package/clinkx-workflows/dist/state.d.ts +170 -3
- package/clinkx-workflows/dist/state.js +1275 -28
- package/clinkx-workflows/dist/state.js.map +1 -1
- package/clinkx-workflows/dist/transport.d.ts +15 -0
- package/clinkx-workflows/dist/transport.js +19 -10
- package/clinkx-workflows/dist/transport.js.map +1 -1
- package/clinkx-workflows/dist/types.d.ts +14 -2
- package/clinkx-workflows/dist/validators/council.d.ts +318 -85
- package/clinkx-workflows/dist/validators/council.js +52 -13
- package/clinkx-workflows/dist/validators/council.js.map +1 -1
- package/clinkx-workflows/dist/validators/index.d.ts +1 -0
- package/clinkx-workflows/dist/validators/index.js +3 -0
- package/clinkx-workflows/dist/validators/index.js.map +1 -1
- package/clinkx-workflows/dist/validators/plan-review.d.ts +398 -0
- package/clinkx-workflows/dist/validators/plan-review.js +316 -0
- package/clinkx-workflows/dist/validators/plan-review.js.map +1 -0
- package/clinkx-workflows/dist/workflow-receipt.js +188 -4
- package/clinkx-workflows/dist/workflow-receipt.js.map +1 -1
- package/clinkx-workflows/dist/workflow-tools.d.ts +48 -3
- package/clinkx-workflows/dist/workflow-tools.js +1402 -59
- package/clinkx-workflows/dist/workflow-tools.js.map +1 -1
- package/clinkx-workflows/dist/workspace-signature.d.ts +16 -0
- package/clinkx-workflows/dist/workspace-signature.js +388 -0
- package/clinkx-workflows/dist/workspace-signature.js.map +1 -0
- package/clinkx-workflows/templates/council/answer-specialist.txt +2 -1
- package/clinkx-workflows/templates/council/code-review-chairman.txt +13 -0
- package/clinkx-workflows/templates/council/code-review-cross-reviewer.txt +4 -1
- package/clinkx-workflows/templates/council/code-review-reviewer.txt +19 -3
- package/clinkx-workflows/templates/council/debug-debugger.txt +2 -1
- package/clinkx-workflows/templates/council/discover-analyst.txt +2 -1
- package/clinkx-workflows/templates/council/member.txt +2 -1
- package/clinkx-workflows/templates/council/plan-review-chairman.txt +68 -0
- package/clinkx-workflows/templates/council/plan-review-cross-reviewer.txt +51 -0
- package/clinkx-workflows/templates/council/plan-review-reviewer.txt +60 -0
- package/clinkx-workflows/templates/plan-review/chairman.txt +48 -0
- package/clinkx-workflows/templates/plan-review/cross-review.txt +52 -0
- package/clinkx-workflows/templates/plan-review/ranking.txt +16 -0
- package/clinkx-workflows/templates/plan-review/reviewer.txt +57 -0
- package/clinkx-workflows/workflows/council-answer.yaml +97 -8
- package/clinkx-workflows/workflows/council-code-review.yaml +103 -8
- package/clinkx-workflows/workflows/council-debug.yaml +97 -8
- package/clinkx-workflows/workflows/council-default.yaml +97 -8
- package/clinkx-workflows/workflows/council-discover.yaml +97 -8
- package/clinkx-workflows/workflows/council-plan-review.yaml +250 -0
- package/clinkx-workflows/workflows/plan-review-receipts.yaml +230 -0
- package/conf/adapters/agy.json +49 -0
- package/conf/adapters/claude.json +5 -0
- package/conf/adapters/codex-app-server.json +44 -0
- package/conf/adapters/codex.json +7 -2
- package/conf/adapters/glm.json +5 -0
- package/conf/adapters/grok.json +60 -0
- package/conf/adapters/hapi/agy.json +52 -0
- package/conf/adapters/hapi/claude.json +5 -0
- package/conf/adapters/hapi/codex.json +7 -2
- package/conf/adapters/hapi/glm.json +5 -0
- package/conf/prompts/json-codereviewer.txt +1 -0
- package/conf/prompts/json.txt +1 -0
- package/dist/activity-journal.d.ts +42 -0
- package/dist/activity-journal.js +381 -0
- package/dist/activity-journal.js.map +1 -0
- package/dist/allowed-roots.d.ts +53 -0
- package/dist/allowed-roots.js +216 -0
- package/dist/allowed-roots.js.map +1 -0
- package/dist/codex/activity-session-log.d.ts +14 -0
- package/dist/codex/activity-session-log.js +206 -0
- package/dist/codex/activity-session-log.js.map +1 -0
- package/dist/codex/agent-tools.d.ts +23 -0
- package/dist/codex/agent-tools.js +1270 -0
- package/dist/codex/agent-tools.js.map +1 -0
- package/dist/codex/app-server-client.d.ts +76 -0
- package/dist/codex/app-server-client.js +582 -0
- package/dist/codex/app-server-client.js.map +1 -0
- package/dist/codex/app-server-registry.d.ts +389 -0
- package/dist/codex/app-server-registry.js +1407 -0
- package/dist/codex/app-server-registry.js.map +1 -0
- package/dist/codex/client-types.d.ts +109 -0
- package/dist/codex/client-types.js +2 -0
- package/dist/codex/client-types.js.map +1 -0
- package/dist/codex/protocol.d.ts +5375 -0
- package/dist/codex/protocol.js +614 -0
- package/dist/codex/protocol.js.map +1 -0
- package/dist/codex/session.d.ts +263 -0
- package/dist/codex/session.js +466 -0
- package/dist/codex/session.js.map +1 -0
- package/dist/config.d.ts +185 -19
- package/dist/config.js +82 -16
- package/dist/config.js.map +1 -1
- package/dist/context-builder/anchors.d.ts +12 -0
- package/dist/context-builder/anchors.js +22 -0
- package/dist/context-builder/anchors.js.map +1 -0
- package/dist/context-builder/bundle.d.ts +109 -0
- package/dist/context-builder/bundle.js +1498 -0
- package/dist/context-builder/bundle.js.map +1 -0
- package/dist/context-builder/codemap.d.ts +22 -0
- package/dist/context-builder/codemap.js +675 -0
- package/dist/context-builder/codemap.js.map +1 -0
- package/dist/context-builder/config.d.ts +61 -0
- package/dist/context-builder/config.js +216 -0
- package/dist/context-builder/config.js.map +1 -0
- package/dist/context-builder/context-run-catalog.d.ts +17 -0
- package/dist/context-builder/context-run-catalog.js +99 -0
- package/dist/context-builder/context-run-catalog.js.map +1 -0
- package/dist/context-builder/delegate-packet.d.ts +219 -0
- package/dist/context-builder/delegate-packet.js +1190 -0
- package/dist/context-builder/delegate-packet.js.map +1 -0
- package/dist/context-builder/delegate-reconstruction.d.ts +13 -0
- package/dist/context-builder/delegate-reconstruction.js +220 -0
- package/dist/context-builder/delegate-reconstruction.js.map +1 -0
- package/dist/context-builder/delegate-validation.d.ts +27 -0
- package/dist/context-builder/delegate-validation.js +479 -0
- package/dist/context-builder/delegate-validation.js.map +1 -0
- package/dist/context-builder/delegate.d.ts +26 -0
- package/dist/context-builder/delegate.js +134 -0
- package/dist/context-builder/delegate.js.map +1 -0
- package/dist/context-builder/diagnostics.d.ts +36 -0
- package/dist/context-builder/diagnostics.js +107 -0
- package/dist/context-builder/diagnostics.js.map +1 -0
- package/dist/context-builder/discovery.d.ts +146 -0
- package/dist/context-builder/discovery.js +2129 -0
- package/dist/context-builder/discovery.js.map +1 -0
- package/dist/context-builder/globs.d.ts +14 -0
- package/dist/context-builder/globs.js +175 -0
- package/dist/context-builder/globs.js.map +1 -0
- package/dist/context-builder/handler.d.ts +41 -0
- package/dist/context-builder/handler.js +2590 -0
- package/dist/context-builder/handler.js.map +1 -0
- package/dist/context-builder/lifecycle-contract.d.ts +424 -0
- package/dist/context-builder/lifecycle-contract.js +523 -0
- package/dist/context-builder/lifecycle-contract.js.map +1 -0
- package/dist/context-builder/lifecycle-journal.d.ts +62 -0
- package/dist/context-builder/lifecycle-journal.js +88 -0
- package/dist/context-builder/lifecycle-journal.js.map +1 -0
- package/dist/context-builder/lifecycle-observer.d.ts +102 -0
- package/dist/context-builder/lifecycle-observer.js +258 -0
- package/dist/context-builder/lifecycle-observer.js.map +1 -0
- package/dist/context-builder/lifecycle-reconcile.d.ts +32 -0
- package/dist/context-builder/lifecycle-reconcile.js +191 -0
- package/dist/context-builder/lifecycle-reconcile.js.map +1 -0
- package/dist/context-builder/lifecycle-recovery.d.ts +2 -0
- package/dist/context-builder/lifecycle-recovery.js +14 -0
- package/dist/context-builder/lifecycle-recovery.js.map +1 -0
- package/dist/context-builder/path-signals.d.ts +7 -0
- package/dist/context-builder/path-signals.js +70 -0
- package/dist/context-builder/path-signals.js.map +1 -0
- package/dist/context-builder/paths.d.ts +30 -0
- package/dist/context-builder/paths.js +153 -0
- package/dist/context-builder/paths.js.map +1 -0
- package/dist/context-builder/progress.d.ts +17 -0
- package/dist/context-builder/progress.js +93 -0
- package/dist/context-builder/progress.js.map +1 -0
- package/dist/context-builder/receipt.d.ts +91 -0
- package/dist/context-builder/receipt.js +180 -0
- package/dist/context-builder/receipt.js.map +1 -0
- package/dist/context-builder/refine-handler.d.ts +14 -0
- package/dist/context-builder/refine-handler.js +790 -0
- package/dist/context-builder/refine-handler.js.map +1 -0
- package/dist/context-builder/review-coverage.d.ts +84 -0
- package/dist/context-builder/review-coverage.js +437 -0
- package/dist/context-builder/review-coverage.js.map +1 -0
- package/dist/context-builder/run-id.d.ts +7 -0
- package/dist/context-builder/run-id.js +31 -0
- package/dist/context-builder/run-id.js.map +1 -0
- package/dist/context-builder/schema.d.ts +669 -0
- package/dist/context-builder/schema.js +399 -0
- package/dist/context-builder/schema.js.map +1 -0
- package/dist/context-builder/secrets.d.ts +41 -0
- package/dist/context-builder/secrets.js +1651 -0
- package/dist/context-builder/secrets.js.map +1 -0
- package/dist/context-builder/selection.d.ts +56 -0
- package/dist/context-builder/selection.js +1111 -0
- package/dist/context-builder/selection.js.map +1 -0
- package/dist/context-builder/session-log-identity.d.ts +1 -0
- package/dist/context-builder/session-log-identity.js +66 -0
- package/dist/context-builder/session-log-identity.js.map +1 -0
- package/dist/context-builder/slice-range-math.d.ts +16 -0
- package/dist/context-builder/slice-range-math.js +137 -0
- package/dist/context-builder/slice-range-math.js.map +1 -0
- package/dist/context-builder/status.d.ts +66 -0
- package/dist/context-builder/status.js +160 -0
- package/dist/context-builder/status.js.map +1 -0
- package/dist/context-builder/storage.d.ts +118 -0
- package/dist/context-builder/storage.js +1003 -0
- package/dist/context-builder/storage.js.map +1 -0
- package/dist/context-builder/token-estimate.d.ts +19 -0
- package/dist/context-builder/token-estimate.js +90 -0
- package/dist/context-builder/token-estimate.js.map +1 -0
- package/dist/context-builder/versions.d.ts +29 -0
- package/dist/context-builder/versions.js +30 -0
- package/dist/context-builder/versions.js.map +1 -0
- package/dist/context-builder/workflow-runner.d.ts +69 -0
- package/dist/context-builder/workflow-runner.js +1051 -0
- package/dist/context-builder/workflow-runner.js.map +1 -0
- package/dist/context-builder/write-watchdog.d.ts +14 -0
- package/dist/context-builder/write-watchdog.js +38 -0
- package/dist/context-builder/write-watchdog.js.map +1 -0
- package/dist/dashboard-adapter-catalog.d.ts +9 -0
- package/dist/dashboard-adapter-catalog.js +46 -0
- package/dist/dashboard-adapter-catalog.js.map +1 -0
- package/dist/dashboard-cli.d.ts +79 -0
- package/dist/dashboard-cli.js +585 -0
- package/dist/dashboard-cli.js.map +1 -0
- package/dist/dashboard-companion/client.d.ts +36 -0
- package/dist/dashboard-companion/client.js +210 -0
- package/dist/dashboard-companion/client.js.map +1 -0
- package/dist/dashboard-companion/config.d.ts +8 -0
- package/dist/dashboard-companion/config.js +52 -0
- package/dist/dashboard-companion/config.js.map +1 -0
- package/dist/dashboard-companion/http-proxy.d.ts +10 -0
- package/dist/dashboard-companion/http-proxy.js +234 -0
- package/dist/dashboard-companion/http-proxy.js.map +1 -0
- package/dist/dashboard-companion/protocol.d.ts +80 -0
- package/dist/dashboard-companion/protocol.js +455 -0
- package/dist/dashboard-companion/protocol.js.map +1 -0
- package/dist/dashboard-companion/standalone-assets.d.ts +12 -0
- package/dist/dashboard-companion/standalone-assets.js +72 -0
- package/dist/dashboard-companion/standalone-assets.js.map +1 -0
- package/dist/dashboard-companion/standalone-entry.d.ts +1 -0
- package/dist/dashboard-companion/standalone-entry.js +17 -0
- package/dist/dashboard-companion/standalone-entry.js.map +1 -0
- package/dist/dashboard-gateway/config.d.ts +9 -0
- package/dist/dashboard-gateway/config.js +44 -0
- package/dist/dashboard-gateway/config.js.map +1 -0
- package/dist/dashboard-gateway/index.d.ts +11 -0
- package/dist/dashboard-gateway/index.js +755 -0
- package/dist/dashboard-gateway/index.js.map +1 -0
- package/dist/dashboard-gateway/main.d.ts +1 -0
- package/dist/dashboard-gateway/main.js +25 -0
- package/dist/dashboard-gateway/main.js.map +1 -0
- package/dist/dashboard-pairing-token.d.ts +1 -0
- package/dist/dashboard-pairing-token.js +5 -0
- package/dist/dashboard-pairing-token.js.map +1 -0
- package/dist/elaris/client.d.ts +73 -0
- package/dist/elaris/client.js +825 -0
- package/dist/elaris/client.js.map +1 -0
- package/dist/elaris/config.d.ts +18 -0
- package/dist/elaris/config.js +75 -0
- package/dist/elaris/config.js.map +1 -0
- package/dist/elaris/errors.d.ts +41 -0
- package/dist/elaris/errors.js +205 -0
- package/dist/elaris/errors.js.map +1 -0
- package/dist/elaris/github-repo.d.ts +18 -0
- package/dist/elaris/github-repo.js +89 -0
- package/dist/elaris/github-repo.js.map +1 -0
- package/dist/elaris/index.d.ts +10 -0
- package/dist/elaris/index.js +11 -0
- package/dist/elaris/index.js.map +1 -0
- package/dist/elaris/redact.d.ts +89 -0
- package/dist/elaris/redact.js +423 -0
- package/dist/elaris/redact.js.map +1 -0
- package/dist/elaris/run-id.d.ts +5 -0
- package/dist/elaris/run-id.js +20 -0
- package/dist/elaris/run-id.js.map +1 -0
- package/dist/elaris/status.d.ts +45 -0
- package/dist/elaris/status.js +122 -0
- package/dist/elaris/status.js.map +1 -0
- package/dist/elaris/tool-schemas.d.ts +314 -0
- package/dist/elaris/tool-schemas.js +208 -0
- package/dist/elaris/tool-schemas.js.map +1 -0
- package/dist/elaris/tools.d.ts +73 -0
- package/dist/elaris/tools.js +1065 -0
- package/dist/elaris/tools.js.map +1 -0
- package/dist/elaris/types.d.ts +1541 -0
- package/dist/elaris/types.js +252 -0
- package/dist/elaris/types.js.map +1 -0
- package/dist/errors.d.ts +16 -0
- package/dist/errors.js +19 -0
- package/dist/errors.js.map +1 -1
- package/dist/handler.d.ts +4 -0
- package/dist/handler.js +10 -1
- package/dist/handler.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +13 -3
- package/dist/index.js.map +1 -1
- package/dist/local-clink-backend.d.ts +3 -0
- package/dist/local-clink-backend.js +4 -0
- package/dist/local-clink-backend.js.map +1 -1
- package/dist/package-info.d.ts +2 -0
- package/dist/package-info.js +18 -0
- package/dist/package-info.js.map +1 -0
- package/dist/parsers/codex-jsonl.js +48 -3
- package/dist/parsers/codex-jsonl.js.map +1 -1
- package/dist/parsers/extract.d.ts +10 -1
- package/dist/parsers/extract.js +11 -3
- package/dist/parsers/extract.js.map +1 -1
- package/dist/paths.d.ts +8 -0
- package/dist/paths.js +31 -43
- package/dist/paths.js.map +1 -1
- package/dist/pipeline.d.ts +51 -3
- package/dist/pipeline.js +264 -47
- package/dist/pipeline.js.map +1 -1
- package/dist/run-dir.d.ts +24 -0
- package/dist/run-dir.js +201 -2
- package/dist/run-dir.js.map +1 -1
- package/dist/runner.d.ts +13 -0
- package/dist/runner.js +184 -15
- package/dist/runner.js.map +1 -1
- package/dist/safety.d.ts +4 -4
- package/dist/safety.js +4 -4
- package/dist/schema.d.ts +7 -7
- package/dist/server.d.ts +2 -0
- package/dist/server.js +396 -24
- package/dist/server.js.map +1 -1
- package/dist/session-log-stream.d.ts +18 -0
- package/dist/session-log-stream.js +319 -0
- package/dist/session-log-stream.js.map +1 -0
- package/package.json +47 -5
- package/conf/adapters/gemini.json +0 -44
- package/conf/adapters/hapi/gemini.json +0 -47
- package/dist/artifacts.d.ts +0 -9
- package/dist/artifacts.js +0 -24
- package/dist/artifacts.js.map +0 -1
- package/dist/parsers/gemini-json.d.ts +0 -2
- package/dist/parsers/gemini-json.js +0 -72
- package/dist/parsers/gemini-json.js.map +0 -1
package/dist/run-dir.js
CHANGED
|
@@ -1,8 +1,22 @@
|
|
|
1
|
-
import { mkdtempSync, mkdirSync, rmSync } from "node:fs";
|
|
2
|
-
import { join } from "node:path";
|
|
1
|
+
import { chmodSync, closeSync, lstatSync, mkdtempSync, mkdirSync, openSync, readdirSync, readSync, rmSync, statSync, writeFileSync, } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
5
5
|
import { logger } from "./logger.js";
|
|
6
|
+
/** Cap on retained (idle-killed) run dirs kept under the runs base dir. */
|
|
7
|
+
const MAX_RETAINED_RUN_DIRS = 20;
|
|
8
|
+
const RETAINED_MARKER = ".retained";
|
|
9
|
+
const STDERR_LOG = "stderr.log";
|
|
10
|
+
/** Payload cap on retained stderr.log bytes (head + tail slices only); the truncation marker line adds ~50 bytes on top. */
|
|
11
|
+
export const RETAINED_STDERR_MAX_BYTES = 1_048_576; // 1 MiB
|
|
12
|
+
export const RETAINED_STDERR_HEAD_BYTES = 524_288; // 512 KiB
|
|
13
|
+
export const RETAINED_STDERR_TAIL_BYTES = 524_288; // 512 KiB
|
|
14
|
+
function isEnoent(err) {
|
|
15
|
+
return err?.code === "ENOENT";
|
|
16
|
+
}
|
|
17
|
+
function errMessage(err) {
|
|
18
|
+
return err instanceof Error ? err.message : String(err);
|
|
19
|
+
}
|
|
6
20
|
/**
|
|
7
21
|
* Create a per-run temp directory under ${TMPDIR}/clinkx/runs/<run_id>.
|
|
8
22
|
*
|
|
@@ -29,4 +43,189 @@ export function createRunDir() {
|
|
|
29
43
|
},
|
|
30
44
|
};
|
|
31
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Retain an idle-killed run dir as diagnostic evidence:
|
|
48
|
+
* - keep ONLY stderr.log; delete everything else (PROMPT.txt must not persist
|
|
49
|
+
* without explicit debug_keep_artifacts opt-in, RESULT.md is absent or
|
|
50
|
+
* incomplete on an idle kill, and CLI-created files are unbounded)
|
|
51
|
+
* - cap stderr.log at RETAINED_STDERR_MAX_BYTES via a head+tail slice
|
|
52
|
+
* - drop a `.retained` marker so retained dirs are identifiable
|
|
53
|
+
* - prune the oldest retained dirs beyond MAX_RETAINED_RUN_DIRS
|
|
54
|
+
*
|
|
55
|
+
* Runs post-termination, so there are no live-fd concerns. Fails CLOSED: if
|
|
56
|
+
* sanitization cannot complete for any non-ENOENT reason, the whole dir is
|
|
57
|
+
* removed instead of retained.
|
|
58
|
+
*
|
|
59
|
+
* @returns "retained" when the sanitized dir survives on disk, "cleaned" when
|
|
60
|
+
* the dir is confirmed gone instead (fail-closed removal or a race that
|
|
61
|
+
* deleted it), "cleanup_failed" when fail-closed removal could not be
|
|
62
|
+
* confirmed and the dir may still exist unsanitized.
|
|
63
|
+
*/
|
|
64
|
+
export function retainRunDir(path) {
|
|
65
|
+
try {
|
|
66
|
+
for (const entry of readdirSync(path, { withFileTypes: true })) {
|
|
67
|
+
if (entry.name === STDERR_LOG) {
|
|
68
|
+
// Reserved-name type check: keep stderr.log ONLY as a regular,
|
|
69
|
+
// non-symlink file. A directory or symlink under that name would
|
|
70
|
+
// bypass sanitization and the byte cap (lstat: isFile() is false
|
|
71
|
+
// for symlinks), so any other type falls through to deletion.
|
|
72
|
+
const st = lstatSync(join(path, entry.name), { throwIfNoEntry: false });
|
|
73
|
+
if (st?.isFile())
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
// Everything else is deleted — including a type-confused stderr.log
|
|
77
|
+
// and any pre-existing `.retained` entry; the marker is written fresh
|
|
78
|
+
// below so it is always a regular file created by us.
|
|
79
|
+
rmSync(join(path, entry.name), { recursive: true, force: true });
|
|
80
|
+
}
|
|
81
|
+
// Runs only on the lstat-verified regular file (or a no-op when absent)
|
|
82
|
+
capRetainedStderr(join(path, STDERR_LOG));
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
if (isEnoent(err)) {
|
|
86
|
+
// Run dir raced away entirely — nothing to retain, nothing left on disk
|
|
87
|
+
logger.debug({ run_dir: path }, "run dir disappeared before retention");
|
|
88
|
+
return "cleaned";
|
|
89
|
+
}
|
|
90
|
+
return failClosed(path, "sanitize", err);
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
writeFileSync(join(path, RETAINED_MARKER), "");
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
if (isEnoent(err)) {
|
|
97
|
+
// Dir raced away — nothing retained, nothing to prune for
|
|
98
|
+
logger.debug({ run_dir: path }, "run dir disappeared before retention marker write");
|
|
99
|
+
return "cleaned";
|
|
100
|
+
}
|
|
101
|
+
// An unmarked dir would evade the pruner's accounting — fail closed too
|
|
102
|
+
return failClosed(path, "write_marker", err);
|
|
103
|
+
}
|
|
104
|
+
pruneRetainedRunDirs(dirname(path));
|
|
105
|
+
return "retained";
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Remove the run dir instead of retaining it. Reports the verified outcome:
|
|
109
|
+
* "cleaned" only when the dir is confirmed gone, else "cleanup_failed".
|
|
110
|
+
*/
|
|
111
|
+
function failClosed(path, operation, err) {
|
|
112
|
+
logger.warn({ run_dir: path, operation, err: errMessage(err) }, "retention sanitization failed — cleaning run dir instead of retaining");
|
|
113
|
+
let lastRmErr;
|
|
114
|
+
try {
|
|
115
|
+
rmSync(path, { recursive: true, force: true });
|
|
116
|
+
}
|
|
117
|
+
catch (rmErr) {
|
|
118
|
+
lastRmErr = rmErr;
|
|
119
|
+
// Sanitization failures are often permission damage (e.g. a read-only
|
|
120
|
+
// run dir) — repair the dir mode and retry removal once.
|
|
121
|
+
try {
|
|
122
|
+
chmodSync(path, 0o700);
|
|
123
|
+
rmSync(path, { recursive: true, force: true });
|
|
124
|
+
lastRmErr = undefined;
|
|
125
|
+
}
|
|
126
|
+
catch (retryErr) {
|
|
127
|
+
lastRmErr = retryErr;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// Verify removal with lstat, not existsSync: existsSync returns false when
|
|
131
|
+
// the path is merely INACCESSIBLE (e.g. parent dir mode 000 → EACCES on
|
|
132
|
+
// traversal), which would misreport a surviving dir as "cleaned". Only a
|
|
133
|
+
// definitive ENOENT confirms the dir is gone; any successful lstat or any
|
|
134
|
+
// other error (EACCES, EPERM, ...) means removal is unconfirmed.
|
|
135
|
+
try {
|
|
136
|
+
lstatSync(path);
|
|
137
|
+
}
|
|
138
|
+
catch (verifyErr) {
|
|
139
|
+
if (isEnoent(verifyErr))
|
|
140
|
+
return "cleaned";
|
|
141
|
+
lastRmErr ??= verifyErr;
|
|
142
|
+
}
|
|
143
|
+
logger.warn({ run_dir: path, err: errMessage(lastRmErr ?? "run dir still present after rmSync") }, "failed to remove run dir after retention sanitization failure");
|
|
144
|
+
return "cleanup_failed";
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Rewrite an oversized stderr.log as first RETAINED_STDERR_HEAD_BYTES +
|
|
148
|
+
* truncation marker + last RETAINED_STDERR_TAIL_BYTES. Missing file (ENOENT)
|
|
149
|
+
* is fine — the child may never have written stderr. Other errors propagate
|
|
150
|
+
* to the fail-closed path in retainRunDir.
|
|
151
|
+
*/
|
|
152
|
+
function capRetainedStderr(stderrPath) {
|
|
153
|
+
let size;
|
|
154
|
+
try {
|
|
155
|
+
size = statSync(stderrPath).size;
|
|
156
|
+
}
|
|
157
|
+
catch (err) {
|
|
158
|
+
if (isEnoent(err))
|
|
159
|
+
return;
|
|
160
|
+
throw err;
|
|
161
|
+
}
|
|
162
|
+
if (size <= RETAINED_STDERR_MAX_BYTES)
|
|
163
|
+
return;
|
|
164
|
+
const fd = openSync(stderrPath, "r");
|
|
165
|
+
let head;
|
|
166
|
+
let tail;
|
|
167
|
+
try {
|
|
168
|
+
head = readSlice(fd, 0, RETAINED_STDERR_HEAD_BYTES);
|
|
169
|
+
tail = readSlice(fd, size - RETAINED_STDERR_TAIL_BYTES, RETAINED_STDERR_TAIL_BYTES);
|
|
170
|
+
}
|
|
171
|
+
finally {
|
|
172
|
+
closeSync(fd);
|
|
173
|
+
}
|
|
174
|
+
const dropped = size - head.length - tail.length;
|
|
175
|
+
const marker = `\n... [clinkx: truncated ${dropped} bytes for retention] ...\n`;
|
|
176
|
+
writeFileSync(stderrPath, Buffer.concat([head, Buffer.from(marker), tail]));
|
|
177
|
+
}
|
|
178
|
+
function readSlice(fd, position, length) {
|
|
179
|
+
const buf = Buffer.alloc(length);
|
|
180
|
+
let offset = 0;
|
|
181
|
+
while (offset < length) {
|
|
182
|
+
const n = readSync(fd, buf, offset, length - offset, position + offset);
|
|
183
|
+
if (n === 0)
|
|
184
|
+
break;
|
|
185
|
+
offset += n;
|
|
186
|
+
}
|
|
187
|
+
return buf.subarray(0, offset);
|
|
188
|
+
}
|
|
189
|
+
function pruneRetainedRunDirs(base) {
|
|
190
|
+
let entries;
|
|
191
|
+
try {
|
|
192
|
+
entries = readdirSync(base, { withFileTypes: true });
|
|
193
|
+
}
|
|
194
|
+
catch (err) {
|
|
195
|
+
if (!isEnoent(err)) {
|
|
196
|
+
logger.debug({ base, err: errMessage(err) }, "failed to list runs base for retention pruning");
|
|
197
|
+
}
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
const retained = [];
|
|
201
|
+
for (const entry of entries) {
|
|
202
|
+
if (!entry.isDirectory())
|
|
203
|
+
continue;
|
|
204
|
+
const dirPath = join(base, entry.name);
|
|
205
|
+
try {
|
|
206
|
+
// Marker mtime = retention time — the pruning sort key
|
|
207
|
+
retained.push({ path: dirPath, mtimeMs: statSync(join(dirPath, RETAINED_MARKER)).mtimeMs });
|
|
208
|
+
}
|
|
209
|
+
catch (err) {
|
|
210
|
+
// Not a retained dir (ENOENT), or raced away — skip
|
|
211
|
+
if (!isEnoent(err)) {
|
|
212
|
+
logger.debug({ dir: dirPath, err: errMessage(err) }, "failed to stat retention marker during pruning");
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (retained.length <= MAX_RETAINED_RUN_DIRS)
|
|
217
|
+
return;
|
|
218
|
+
retained.sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
219
|
+
for (const victim of retained.slice(MAX_RETAINED_RUN_DIRS)) {
|
|
220
|
+
try {
|
|
221
|
+
rmSync(victim.path, { recursive: true, force: true });
|
|
222
|
+
}
|
|
223
|
+
catch (err) {
|
|
224
|
+
// Raced with another prune (ENOENT) — fine
|
|
225
|
+
if (!isEnoent(err)) {
|
|
226
|
+
logger.debug({ dir: victim.path, err: errMessage(err) }, "failed to prune retained run dir");
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
32
231
|
//# sourceMappingURL=run-dir.js.map
|
package/dist/run-dir.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-dir.js","sourceRoot":"","sources":["../src/run-dir.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"run-dir.js","sourceRoot":"","sources":["../src/run-dir.ts"],"names":[],"mappings":"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"}
|
package/dist/runner.d.ts
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
import { type ChildProcess } from "node:child_process";
|
|
2
2
|
import type { CliAdapterConfig } from "./config.js";
|
|
3
|
+
import type { SessionLogOwnerV1 } from "../clinkx-workflows/dist/dashboard/session-log-contract.js";
|
|
3
4
|
/** Active subprocess registry for graceful shutdown. */
|
|
4
5
|
export declare const activeProcesses: Set<ChildProcess>;
|
|
6
|
+
/** Synchronously prevent every future generic subprocess admission. */
|
|
7
|
+
export declare function latchSubprocessAdmissionForShutdown(): void;
|
|
8
|
+
/**
|
|
9
|
+
* Test-only reset for the process-wide admission latch and deterministic race
|
|
10
|
+
* hook. Tests that call this own the cleanup and must leave no active child.
|
|
11
|
+
*/
|
|
12
|
+
export declare function resetSubprocessAdmissionForTest(): void;
|
|
13
|
+
/** Test-only seam for forcing the post-spawn shutdown race deterministically. */
|
|
14
|
+
export declare function setAfterSpawnRegisteredForTest(hook: ((child: ChildProcess) => void) | undefined): void;
|
|
5
15
|
/** Kill all subprocesses tracked when shutdown begins. */
|
|
6
16
|
export declare function killAllActive(): Promise<void>;
|
|
7
17
|
export interface RunOptions {
|
|
@@ -12,6 +22,9 @@ export interface RunOptions {
|
|
|
12
22
|
idleTimeoutSeconds?: number | undefined;
|
|
13
23
|
idleTimeoutStartupSeconds?: number | undefined;
|
|
14
24
|
signal?: AbortSignal | undefined;
|
|
25
|
+
sessionLogOwner?: SessionLogOwnerV1 | undefined;
|
|
26
|
+
/** Internal storage-root override for focused tests. */
|
|
27
|
+
sessionLogRootDir?: string | undefined;
|
|
15
28
|
}
|
|
16
29
|
export interface RunResult {
|
|
17
30
|
exitCode: number | null;
|
package/dist/runner.js
CHANGED
|
@@ -3,44 +3,76 @@ import { openSync, closeSync, readSync, statSync } from "node:fs";
|
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { logger } from "./logger.js";
|
|
5
5
|
import { ExecutionError } from "./errors.js";
|
|
6
|
+
import { getStateDir } from "../clinkx-workflows/dist/config.js";
|
|
6
7
|
import { buildEnv, redactSecrets } from "./env.js";
|
|
7
8
|
import { preparePromptDelivery } from "./prompt-mode.js";
|
|
8
9
|
import { assertNoTtyRequired, resolveArgs } from "./safety.js";
|
|
10
|
+
import { createProviderSessionLogProducer } from "./session-log-stream.js";
|
|
9
11
|
/** Active subprocess registry for graceful shutdown. */
|
|
10
12
|
export const activeProcesses = new Set();
|
|
13
|
+
let subprocessAdmissionClosed = false;
|
|
14
|
+
let afterSpawnRegisteredForTest;
|
|
15
|
+
/** Synchronously prevent every future generic subprocess admission. */
|
|
16
|
+
export function latchSubprocessAdmissionForShutdown() {
|
|
17
|
+
subprocessAdmissionClosed = true;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Test-only reset for the process-wide admission latch and deterministic race
|
|
21
|
+
* hook. Tests that call this own the cleanup and must leave no active child.
|
|
22
|
+
*/
|
|
23
|
+
export function resetSubprocessAdmissionForTest() {
|
|
24
|
+
subprocessAdmissionClosed = false;
|
|
25
|
+
afterSpawnRegisteredForTest = undefined;
|
|
26
|
+
}
|
|
27
|
+
/** Test-only seam for forcing the post-spawn shutdown race deterministically. */
|
|
28
|
+
export function setAfterSpawnRegisteredForTest(hook) {
|
|
29
|
+
afterSpawnRegisteredForTest = hook;
|
|
30
|
+
}
|
|
31
|
+
function shutdownAdmissionError() {
|
|
32
|
+
return new ExecutionError("Server is shutting down; subprocess admission is closed");
|
|
33
|
+
}
|
|
11
34
|
const ROOT_SHUTDOWN_GRACE_MS = 3_000;
|
|
12
35
|
/** Kill all subprocesses tracked when shutdown begins. */
|
|
13
36
|
export async function killAllActive() {
|
|
14
|
-
const
|
|
15
|
-
|
|
37
|
+
const deadline = Date.now() + ROOT_SHUTDOWN_GRACE_MS;
|
|
38
|
+
const initialSnapshot = [...activeProcesses];
|
|
39
|
+
if (initialSnapshot.length === 0)
|
|
16
40
|
return;
|
|
17
|
-
for (const child of
|
|
41
|
+
for (const child of initialSnapshot) {
|
|
18
42
|
killProcessGroup(child, "SIGTERM");
|
|
19
43
|
}
|
|
20
44
|
// Wait for grace period, but resolve early if all children have exited
|
|
21
45
|
await new Promise((resolve) => {
|
|
22
|
-
const timer = setTimeout(resolve,
|
|
46
|
+
const timer = setTimeout(resolve, Math.max(0, deadline - Date.now()));
|
|
23
47
|
const interval = setInterval(() => {
|
|
24
|
-
if (
|
|
48
|
+
if (activeProcesses.size === 0) {
|
|
25
49
|
clearTimeout(timer);
|
|
26
50
|
clearInterval(interval);
|
|
27
51
|
resolve();
|
|
28
52
|
}
|
|
29
53
|
}, 50);
|
|
30
|
-
setTimeout(() => clearInterval(interval),
|
|
54
|
+
setTimeout(() => clearInterval(interval), Math.max(0, deadline - Date.now())).unref();
|
|
31
55
|
});
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
56
|
+
// Drain the live registry, not the initial snapshot: a child registered
|
|
57
|
+
// during shutdown is still owned and must not survive the sweep.
|
|
58
|
+
// Escalate every group observed at shutdown entry as well as children still
|
|
59
|
+
// registered now. The direct child can exit after SIGTERM while a descendant
|
|
60
|
+
// forked at that boundary remains in its process group; dropping the initial
|
|
61
|
+
// handle here would orphan that descendant.
|
|
62
|
+
const escalationSnapshot = new Set([...initialSnapshot, ...activeProcesses]);
|
|
63
|
+
for (const child of escalationSnapshot) {
|
|
64
|
+
killProcessGroup(child, "SIGKILL");
|
|
36
65
|
}
|
|
37
66
|
}
|
|
38
67
|
const DEFAULT_MAX_PROMPT_BYTES = 1_048_576; // 1 MB
|
|
39
68
|
const DEFAULT_TIMEOUT_SECONDS = 600;
|
|
40
69
|
const DEFAULT_MAX_CAPTURE_BYTES = 2_097_152; // 2 MB default capture retention
|
|
41
70
|
const GRACE_PERIOD_MS = 5_000;
|
|
71
|
+
const STDERR_POLL_INTERVAL_MS = 1_000;
|
|
42
72
|
const DEFAULT_IDLE_TIMEOUT_SECONDS = 0;
|
|
43
73
|
const DEFAULT_IDLE_TIMEOUT_STARTUP_SECONDS = 180;
|
|
74
|
+
// Per-line cap for the provider session-log stream, in characters.
|
|
75
|
+
const DEFAULT_SESSION_LOG_MAX_LINE_CHARS = 1024 * 1024;
|
|
44
76
|
function safeParseInt(val, fallback) {
|
|
45
77
|
if (val == null || val === "")
|
|
46
78
|
return fallback;
|
|
@@ -132,22 +164,28 @@ function killProcessGroup(child, sig) {
|
|
|
132
164
|
*/
|
|
133
165
|
export function runSubprocess(options) {
|
|
134
166
|
const { adapter, prompt, runDirPath, signal } = options;
|
|
167
|
+
if (subprocessAdmissionClosed) {
|
|
168
|
+
return Promise.reject(shutdownAdmissionError());
|
|
169
|
+
}
|
|
135
170
|
const timeoutSeconds = options.timeoutSeconds ??
|
|
136
171
|
adapter.timeout_seconds ??
|
|
137
172
|
safeParseInt(process.env["CLINKX_TIMEOUT_SECONDS"], DEFAULT_TIMEOUT_SECONDS);
|
|
138
173
|
// Idle timeout resolution: RunOptions > adapter config > env var > default
|
|
139
|
-
// Suppress-stdout guard: when stdout is suppressed
|
|
140
|
-
|
|
141
|
-
|
|
174
|
+
// Suppress-stdout guard: when stdout is suppressed there is no stdout to
|
|
175
|
+
// observe, but stderr_to_file polling still provides a byte-activity
|
|
176
|
+
// channel — only zero the idle timeouts when no observable channel remains.
|
|
177
|
+
const noObservableChannel = adapter.suppress_stdout === true && adapter.stderr_to_file !== true;
|
|
178
|
+
const idleTimeoutSeconds = noObservableChannel ? 0 :
|
|
142
179
|
(options.idleTimeoutSeconds ??
|
|
143
180
|
adapter.idle_timeout_seconds ??
|
|
144
181
|
safeParseIntNonNeg(process.env["CLINKX_IDLE_TIMEOUT_SECONDS"], DEFAULT_IDLE_TIMEOUT_SECONDS));
|
|
145
|
-
const idleStartupSeconds =
|
|
182
|
+
const idleStartupSeconds = noObservableChannel ? 0 :
|
|
146
183
|
(options.idleTimeoutStartupSeconds ??
|
|
147
184
|
adapter.idle_timeout_startup_seconds ??
|
|
148
185
|
safeParseIntNonNeg(process.env["CLINKX_IDLE_TIMEOUT_STARTUP_SECONDS"], DEFAULT_IDLE_TIMEOUT_STARTUP_SECONDS));
|
|
149
186
|
const maxPromptBytes = safeParseInt(process.env["CLINKX_MAX_PROMPT_BYTES"], DEFAULT_MAX_PROMPT_BYTES);
|
|
150
187
|
const maxCaptureBytes = safeParseInt(process.env["CLINKX_MAX_CAPTURE_BYTES"] ?? process.env["CLINKX_MAX_OUTPUT_BYTES"], DEFAULT_MAX_CAPTURE_BYTES);
|
|
188
|
+
const sessionLogMaxLineChars = safeParseInt(process.env["CLINKX_SESSION_LOG_MAX_LINE_CHARS"], DEFAULT_SESSION_LOG_MAX_LINE_CHARS);
|
|
151
189
|
// Bound input size
|
|
152
190
|
const promptBuf = Buffer.from(prompt, "utf-8");
|
|
153
191
|
if (promptBuf.length > maxPromptBytes) {
|
|
@@ -160,7 +198,6 @@ export function runSubprocess(options) {
|
|
|
160
198
|
catch (err) {
|
|
161
199
|
return Promise.reject(err);
|
|
162
200
|
}
|
|
163
|
-
// Build args
|
|
164
201
|
const args = resolveArgs(adapter.args, adapter.unsafe_args);
|
|
165
202
|
if (adapter.native_output_file_flag && adapter.result_contract.enabled) {
|
|
166
203
|
args.push(adapter.native_output_file_flag, join(runDirPath, adapter.result_contract.filename));
|
|
@@ -191,6 +228,7 @@ export function runSubprocess(options) {
|
|
|
191
228
|
let timeoutHandle;
|
|
192
229
|
let graceHandle;
|
|
193
230
|
let idleHandle;
|
|
231
|
+
let stderrPollHandle;
|
|
194
232
|
let stderrFd;
|
|
195
233
|
const stderrFilePath = adapter.stderr_to_file
|
|
196
234
|
? join(runDirPath, "stderr.log")
|
|
@@ -198,6 +236,14 @@ export function runSubprocess(options) {
|
|
|
198
236
|
if (stderrFilePath != null) {
|
|
199
237
|
stderrFd = openSync(stderrFilePath, "w");
|
|
200
238
|
}
|
|
239
|
+
// Load-bearing second check: argument/env preparation can race shutdown.
|
|
240
|
+
// This is the final point before the OS process can be created.
|
|
241
|
+
if (subprocessAdmissionClosed) {
|
|
242
|
+
if (stderrFd != null)
|
|
243
|
+
closeSync(stderrFd);
|
|
244
|
+
reject(shutdownAdmissionError());
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
201
247
|
let child;
|
|
202
248
|
try {
|
|
203
249
|
child = spawn(adapter.command, args, {
|
|
@@ -224,6 +270,27 @@ export function runSubprocess(options) {
|
|
|
224
270
|
stderrFd = undefined;
|
|
225
271
|
}
|
|
226
272
|
activeProcesses.add(child);
|
|
273
|
+
// Test-only synchronization point. Production has no callback here.
|
|
274
|
+
afterSpawnRegisteredForTest?.(child);
|
|
275
|
+
// Shutdown can latch in the narrow spawn->registration window. Kill the
|
|
276
|
+
// entire newly-created group, retain registry ownership until close/error,
|
|
277
|
+
// and reject the request instead of admitting work after the drain began.
|
|
278
|
+
if (subprocessAdmissionClosed) {
|
|
279
|
+
const releaseRacingChild = () => {
|
|
280
|
+
// Re-sweep after the direct child exits: a shell can fork a descendant
|
|
281
|
+
// at the same instant the first group signal selects its recipients.
|
|
282
|
+
killProcessGroup(child, "SIGKILL");
|
|
283
|
+
activeProcesses.delete(child);
|
|
284
|
+
};
|
|
285
|
+
child.once("error", releaseRacingChild);
|
|
286
|
+
child.once("close", releaseRacingChild);
|
|
287
|
+
killProcessGroup(child, "SIGKILL");
|
|
288
|
+
child.stdin?.destroy();
|
|
289
|
+
child.stdout?.destroy();
|
|
290
|
+
child.stderr?.destroy();
|
|
291
|
+
reject(shutdownAdmissionError());
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
227
294
|
// Shared kill guard — prevents double-SIGTERM races across wall/idle/cancel paths
|
|
228
295
|
function initiateKill(reason) {
|
|
229
296
|
if (killInitiated)
|
|
@@ -234,6 +301,7 @@ export function runSubprocess(options) {
|
|
|
234
301
|
clearTimeout(timeoutHandle);
|
|
235
302
|
clearTimeout(idleHandle);
|
|
236
303
|
clearTimeout(graceHandle); // clear stale grace handle (killInitiated prevents re-entry)
|
|
304
|
+
clearInterval(stderrPollHandle);
|
|
237
305
|
if (reason === "wall")
|
|
238
306
|
timedOut = true;
|
|
239
307
|
if (reason === "idle")
|
|
@@ -247,6 +315,41 @@ export function runSubprocess(options) {
|
|
|
247
315
|
killProcessGroup(child, "SIGKILL");
|
|
248
316
|
}, GRACE_PERIOD_MS);
|
|
249
317
|
}
|
|
318
|
+
const stderrPollingEnabled = stderrFilePath != null && (idleStartupSeconds > 0 || idleTimeoutSeconds > 0);
|
|
319
|
+
let lastStderrSize = 0;
|
|
320
|
+
// Set when an idle-expiry stat failed once. Cleared ONLY by observed byte
|
|
321
|
+
// activity (any probe) or a successful stat AT expiry time — a quiet
|
|
322
|
+
// interval tick must not clear it, or an alternating expiry-failure /
|
|
323
|
+
// quiet-tick pattern would re-arm the idle timer forever. A second
|
|
324
|
+
// unresolved expiry failure proceeds with the kill so a permanently
|
|
325
|
+
// unreadable stderr file cannot make the child unkillable.
|
|
326
|
+
// Deferred regression coverage: deterministically proving the
|
|
327
|
+
// quiet-tick-must-NOT-clear semantics needs an injectable stat probe or
|
|
328
|
+
// fake timers; a revert of that semantics would pass the current suite.
|
|
329
|
+
let idleExpiryStatFailed = false;
|
|
330
|
+
// Shared by the poll tick and the idle-expiry last-chance check so the two
|
|
331
|
+
// activity detectors cannot drift. Any size change (growth or truncation)
|
|
332
|
+
// counts as byte activity.
|
|
333
|
+
function probeStderrFile() {
|
|
334
|
+
if (stderrFilePath == null)
|
|
335
|
+
return "quiet";
|
|
336
|
+
let size;
|
|
337
|
+
try {
|
|
338
|
+
size = statSync(stderrFilePath).size;
|
|
339
|
+
}
|
|
340
|
+
catch {
|
|
341
|
+
// stat failure this tick is non-fatal — try again next tick
|
|
342
|
+
return "stat_failed";
|
|
343
|
+
}
|
|
344
|
+
if (size !== lastStderrSize) {
|
|
345
|
+
lastStderrSize = size;
|
|
346
|
+
receivedFirstByte = true;
|
|
347
|
+
// Byte activity anywhere is conclusive — safe to disarm fail-open
|
|
348
|
+
idleExpiryStatFailed = false;
|
|
349
|
+
return "active";
|
|
350
|
+
}
|
|
351
|
+
return "quiet";
|
|
352
|
+
}
|
|
250
353
|
// Idle timer: resets on any data from stdout or stderr
|
|
251
354
|
function resetIdleTimer() {
|
|
252
355
|
if (killInitiated)
|
|
@@ -260,6 +363,30 @@ export function runSubprocess(options) {
|
|
|
260
363
|
idleHandle = setTimeout(() => {
|
|
261
364
|
if (killInitiated)
|
|
262
365
|
return;
|
|
366
|
+
// Last-chance re-check: with an idle timeout <= poll interval, the
|
|
367
|
+
// expiry can fire before the next poll tick observes fresh stderr
|
|
368
|
+
// bytes — never kill a child on a stale size reading.
|
|
369
|
+
if (stderrPollingEnabled) {
|
|
370
|
+
const probe = probeStderrFile();
|
|
371
|
+
if (probe === "active") {
|
|
372
|
+
resetIdleTimer();
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
if (probe === "quiet") {
|
|
376
|
+
// A successful stat AT expiry is conclusive (genuinely no
|
|
377
|
+
// activity) — disarm the fail-open flag so it cannot linger and
|
|
378
|
+
// be consumed by a later, unrelated expiry failure.
|
|
379
|
+
idleExpiryStatFailed = false;
|
|
380
|
+
}
|
|
381
|
+
if (probe === "stat_failed" && !idleExpiryStatFailed) {
|
|
382
|
+
// A transient stat failure is inconclusive, not "no activity" —
|
|
383
|
+
// don't kill a possibly-active child on it. Give it exactly one
|
|
384
|
+
// more idle window; a second consecutive failure proceeds.
|
|
385
|
+
idleExpiryStatFailed = true;
|
|
386
|
+
resetIdleTimer();
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
263
390
|
idlePhase = receivedFirstByte ? "inter_byte" : "startup";
|
|
264
391
|
idleTimeoutEffective = receivedFirstByte ? idleTimeoutSeconds : idleStartupSeconds;
|
|
265
392
|
initiateKill("idle");
|
|
@@ -269,19 +396,42 @@ export function runSubprocess(options) {
|
|
|
269
396
|
? { capture: { head: Buffer.alloc(0), tail: Buffer.alloc(0), totalBytes: 0, truncated: false }, onData(_chunk) { } }
|
|
270
397
|
: createStreamCapture(maxCaptureBytes);
|
|
271
398
|
const stderrCapture = createStreamCapture(maxCaptureBytes);
|
|
399
|
+
let sessionLogProducer;
|
|
400
|
+
if (options.sessionLogOwner !== undefined &&
|
|
401
|
+
(adapter.parser === "codex_jsonl" || adapter.parser === "claude_stream_json")) {
|
|
402
|
+
try {
|
|
403
|
+
sessionLogProducer = createProviderSessionLogProducer({
|
|
404
|
+
parser: adapter.parser,
|
|
405
|
+
owner: options.sessionLogOwner,
|
|
406
|
+
rootDir: options.sessionLogRootDir ?? join(getStateDir(), "session-logs"),
|
|
407
|
+
prompt,
|
|
408
|
+
maxPartialLineChars: sessionLogMaxLineChars,
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
catch {
|
|
412
|
+
logger.debug({ producerFamily: options.sessionLogOwner.family }, "provider session-log admission failed open");
|
|
413
|
+
}
|
|
414
|
+
}
|
|
272
415
|
child.stdout?.on("data", (chunk) => {
|
|
273
416
|
if (chunk.length === 0)
|
|
274
417
|
return;
|
|
275
418
|
if (!receivedFirstByte)
|
|
276
419
|
receivedFirstByte = true;
|
|
420
|
+
// Pipe bytes are conclusive activity — restore the one-shot
|
|
421
|
+
// expiry-stat-failure grace window, matching probeStderrFile()
|
|
422
|
+
idleExpiryStatFailed = false;
|
|
277
423
|
resetIdleTimer();
|
|
278
424
|
stdoutCapture.onData(chunk);
|
|
425
|
+
sessionLogProducer?.onStdout(chunk);
|
|
279
426
|
});
|
|
280
427
|
child.stderr?.on("data", (chunk) => {
|
|
281
428
|
if (chunk.length === 0)
|
|
282
429
|
return;
|
|
283
430
|
if (!receivedFirstByte)
|
|
284
431
|
receivedFirstByte = true;
|
|
432
|
+
// Pipe bytes are conclusive activity — restore the one-shot
|
|
433
|
+
// expiry-stat-failure grace window, matching probeStderrFile()
|
|
434
|
+
idleExpiryStatFailed = false;
|
|
285
435
|
resetIdleTimer();
|
|
286
436
|
stderrCapture.onData(chunk);
|
|
287
437
|
});
|
|
@@ -300,6 +450,17 @@ export function runSubprocess(options) {
|
|
|
300
450
|
}, timeoutSeconds * 1_000);
|
|
301
451
|
// Arm idle timer immediately after spawn
|
|
302
452
|
resetIdleTimer();
|
|
453
|
+
// File-backed stderr produces no 'data' events, so the idle timer would
|
|
454
|
+
// only see stdout — for CLIs that write stdout at the very end, that makes
|
|
455
|
+
// startup-idle detection kill healthy turns. Poll stderr file size growth
|
|
456
|
+
// as the byte-activity signal instead (size only, contents never read).
|
|
457
|
+
if (stderrPollingEnabled) {
|
|
458
|
+
stderrPollHandle = setInterval(() => {
|
|
459
|
+
if (probeStderrFile() === "active")
|
|
460
|
+
resetIdleTimer();
|
|
461
|
+
}, STDERR_POLL_INTERVAL_MS);
|
|
462
|
+
stderrPollHandle.unref();
|
|
463
|
+
}
|
|
303
464
|
// Cancellation via AbortSignal
|
|
304
465
|
const onAbort = () => {
|
|
305
466
|
initiateKill("cancel");
|
|
@@ -316,16 +477,24 @@ export function runSubprocess(options) {
|
|
|
316
477
|
clearTimeout(timeoutHandle);
|
|
317
478
|
clearTimeout(idleHandle);
|
|
318
479
|
clearTimeout(graceHandle);
|
|
480
|
+
clearInterval(stderrPollHandle);
|
|
319
481
|
signal?.removeEventListener("abort", onAbort);
|
|
320
482
|
activeProcesses.delete(child);
|
|
483
|
+
sessionLogProducer?.finish("failed");
|
|
321
484
|
reject(new ExecutionError(`Failed to spawn "${adapter.command}": ${err.message}`));
|
|
322
485
|
});
|
|
323
486
|
child.on("close", (code, exitSignal) => {
|
|
324
487
|
clearTimeout(timeoutHandle);
|
|
325
488
|
clearTimeout(idleHandle);
|
|
326
489
|
clearTimeout(graceHandle);
|
|
490
|
+
clearInterval(stderrPollHandle);
|
|
327
491
|
signal?.removeEventListener("abort", onAbort);
|
|
328
492
|
activeProcesses.delete(child);
|
|
493
|
+
sessionLogProducer?.finish(terminationReason === "cancel"
|
|
494
|
+
? "cancelled"
|
|
495
|
+
: terminationReason === "wall" || terminationReason === "idle"
|
|
496
|
+
? "timeout"
|
|
497
|
+
: code === 0 ? "completed" : "failed");
|
|
329
498
|
// Post-mortem stderr hydration from file-backed capture
|
|
330
499
|
if (stderrFilePath != null) {
|
|
331
500
|
try {
|