@shivaedev/work-fleet 0.2.1 → 0.3.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 +41 -0
- package/README.md +60 -18
- package/dist/DispatchRequest.d.ts +13 -0
- package/dist/DispatchRequest.d.ts.map +1 -0
- package/dist/DispatchRequest.js +12 -0
- package/dist/DispatchRequest.js.map +1 -0
- package/dist/admit.d.ts +11 -0
- package/dist/admit.d.ts.map +1 -1
- package/dist/attention.d.ts +1 -0
- package/dist/attention.d.ts.map +1 -1
- package/dist/attention.js +4 -0
- package/dist/attention.js.map +1 -1
- package/dist/board/fleetField.d.ts +1 -0
- package/dist/board/fleetField.d.ts.map +1 -1
- package/dist/board/fleetField.js +4 -0
- package/dist/board/fleetField.js.map +1 -1
- package/dist/board/markdown.d.ts.map +1 -1
- package/dist/board/markdown.js +7 -2
- package/dist/board/markdown.js.map +1 -1
- package/dist/board/publish.d.ts +2 -0
- package/dist/board/publish.d.ts.map +1 -1
- package/dist/board/publishReport.d.ts +1 -0
- package/dist/board/publishReport.d.ts.map +1 -1
- package/dist/board/readPass.d.ts +1 -0
- package/dist/board/readPass.d.ts.map +1 -1
- package/dist/cli.js +13 -6
- package/dist/cli.js.map +1 -1
- package/dist/engine/abandonStalled.d.ts +1171 -1004
- package/dist/engine/abandonStalled.d.ts.map +1 -1
- package/dist/engine/admissionOrder.d.ts +1091 -0
- package/dist/engine/admissionOrder.d.ts.map +1 -0
- package/dist/engine/admissionOrder.js +15 -0
- package/dist/engine/admissionOrder.js.map +1 -0
- package/dist/engine/applyResolution.d.ts +20 -0
- package/dist/engine/applyResolution.d.ts.map +1 -1
- package/dist/engine/approveBrief.d.ts +31 -0
- package/dist/engine/approveBrief.d.ts.map +1 -1
- package/dist/engine/authorizeResolution.d.ts +1160 -1003
- package/dist/engine/authorizeResolution.d.ts.map +1 -1
- package/dist/engine/boardBrief.d.ts +32 -0
- package/dist/engine/boardBrief.d.ts.map +1 -1
- package/dist/engine/capacityRetry.d.ts +3488 -3007
- package/dist/engine/capacityRetry.d.ts.map +1 -1
- package/dist/engine/closeDecisions.d.ts +20 -0
- package/dist/engine/closeDecisions.d.ts.map +1 -1
- package/dist/engine/completeBoardWork.d.ts +20 -0
- package/dist/engine/completeBoardWork.d.ts.map +1 -1
- package/dist/engine/completeReport.d.ts +21 -0
- package/dist/engine/completeReport.d.ts.map +1 -1
- package/dist/engine/continueCommand.d.ts +10 -0
- package/dist/engine/continueCommand.d.ts.map +1 -1
- package/dist/engine/continueWorker.d.ts +20 -0
- package/dist/engine/continueWorker.d.ts.map +1 -1
- package/dist/engine/deliverPendingAnswers.d.ts +1085 -898
- package/dist/engine/deliverPendingAnswers.d.ts.map +1 -1
- package/dist/engine/dispatchCommand.d.ts +14 -1
- package/dist/engine/dispatchCommand.d.ts.map +1 -1
- package/dist/engine/dispatchCommand.js +25 -5
- package/dist/engine/dispatchCommand.js.map +1 -1
- package/dist/engine/ensureDecisionOwner.d.ts +20 -0
- package/dist/engine/ensureDecisionOwner.d.ts.map +1 -1
- package/dist/engine/ensurePublication.d.ts +20 -0
- package/dist/engine/ensurePublication.d.ts.map +1 -1
- package/dist/engine/failureContext.d.ts +1 -0
- package/dist/engine/failureContext.d.ts.map +1 -1
- package/dist/engine/failureContext.js.map +1 -1
- package/dist/engine/failureMessage.js +11 -1
- package/dist/engine/failureMessage.js.map +1 -1
- package/dist/engine/health.d.ts +10 -0
- package/dist/engine/health.d.ts.map +1 -1
- package/dist/engine/inspectRenewal.d.ts +21 -0
- package/dist/engine/inspectRenewal.d.ts.map +1 -1
- package/dist/engine/launchInput.d.ts +10 -0
- package/dist/engine/launchInput.d.ts.map +1 -1
- package/dist/engine/launchReceipt.d.ts +10 -0
- package/dist/engine/launchReceipt.d.ts.map +1 -1
- package/dist/engine/localOnlyCriteria.d.ts +1 -0
- package/dist/engine/localOnlyCriteria.d.ts.map +1 -1
- package/dist/engine/localOnlyCriteria.js +5 -1
- package/dist/engine/localOnlyCriteria.js.map +1 -1
- package/dist/engine/makeAdopt.d.ts +21 -0
- package/dist/engine/makeAdopt.d.ts.map +1 -1
- package/dist/engine/makeAdvance.d.ts +10 -0
- package/dist/engine/makeAdvance.d.ts.map +1 -1
- package/dist/engine/makeDeliver.d.ts +20 -0
- package/dist/engine/makeDeliver.d.ts.map +1 -1
- package/dist/engine/makeHuman.d.ts +20 -0
- package/dist/engine/makeHuman.d.ts.map +1 -1
- package/dist/engine/makeLaunch.d.ts +20 -0
- package/dist/engine/makeLaunch.d.ts.map +1 -1
- package/dist/engine/makeLaunch.js +4 -13
- package/dist/engine/makeLaunch.js.map +1 -1
- package/dist/engine/makeObserve.d.ts +20 -0
- package/dist/engine/makeObserve.d.ts.map +1 -1
- package/dist/engine/makeReview.d.ts +21 -0
- package/dist/engine/makeReview.d.ts.map +1 -1
- package/dist/engine/makeState.d.ts +1164 -1010
- package/dist/engine/makeState.d.ts.map +1 -1
- package/dist/engine/makeState.js +19 -11
- package/dist/engine/makeState.js.map +1 -1
- package/dist/engine/makeValidate.d.ts +21 -0
- package/dist/engine/makeValidate.d.ts.map +1 -1
- package/dist/engine/mergeReadiness.d.ts +1425 -1764
- package/dist/engine/mergeReadiness.d.ts.map +1 -1
- package/dist/engine/mergeReadiness.js +3 -4
- package/dist/engine/mergeReadiness.js.map +1 -1
- package/dist/engine/observeDeliveryFailure.d.ts +1170 -1003
- package/dist/engine/observeDeliveryFailure.d.ts.map +1 -1
- package/dist/engine/observeRenewal.d.ts +33 -0
- package/dist/engine/observeRenewal.d.ts.map +1 -1
- package/dist/engine/obtainReview.d.ts +11 -0
- package/dist/engine/obtainReview.d.ts.map +1 -1
- package/dist/engine/obtainReview.js +2 -1
- package/dist/engine/obtainReview.js.map +1 -1
- package/dist/engine/operationRecord.d.ts +1898 -1779
- package/dist/engine/operationRecord.d.ts.map +1 -1
- package/dist/engine/persistTerminalReceipts.d.ts +20 -0
- package/dist/engine/persistTerminalReceipts.d.ts.map +1 -1
- package/dist/engine/prepareCommand.d.ts +10 -0
- package/dist/engine/prepareCommand.d.ts.map +1 -1
- package/dist/engine/prepareCommand.js +1 -1
- package/dist/engine/prepareCommand.js.map +1 -1
- package/dist/engine/queueAnswerCommand.d.ts +10 -0
- package/dist/engine/queueAnswerCommand.d.ts.map +1 -1
- package/dist/engine/readOrContinueReview.d.ts +11 -0
- package/dist/engine/readOrContinueReview.d.ts.map +1 -1
- package/dist/engine/readOrContinueReview.js +2 -1
- package/dist/engine/readOrContinueReview.js.map +1 -1
- package/dist/engine/readResolution.d.ts +1 -0
- package/dist/engine/readResolution.d.ts.map +1 -1
- package/dist/engine/readRetry.d.ts +2344 -2010
- package/dist/engine/readRetry.d.ts.map +1 -1
- package/dist/engine/readRetry.js +20 -1
- package/dist/engine/readRetry.js.map +1 -1
- package/dist/engine/reassignCommand.d.ts +10 -0
- package/dist/engine/reassignCommand.d.ts.map +1 -1
- package/dist/engine/reconcileAttempt.d.ts +12 -1
- package/dist/engine/reconcileAttempt.d.ts.map +1 -1
- package/dist/engine/reconcileAttempt.js +2 -1
- package/dist/engine/reconcileAttempt.js.map +1 -1
- package/dist/engine/reconcileCommand.d.ts +10 -0
- package/dist/engine/reconcileCommand.d.ts.map +1 -1
- package/dist/engine/recordResponseCommand.d.ts +551 -0
- package/dist/engine/recordResponseCommand.d.ts.map +1 -0
- package/dist/engine/recordResponseCommand.js +30 -0
- package/dist/engine/recordResponseCommand.js.map +1 -0
- package/dist/engine/recoverStall.d.ts +1172 -1004
- package/dist/engine/recoverStall.d.ts.map +1 -1
- package/dist/engine/recoverStall.js +1 -1
- package/dist/engine/recoverStall.js.map +1 -1
- package/dist/engine/recoverUnobservable.d.ts +1172 -1004
- package/dist/engine/recoverUnobservable.d.ts.map +1 -1
- package/dist/engine/refreshBrief.d.ts +2344 -2009
- package/dist/engine/refreshBrief.d.ts.map +1 -1
- package/dist/engine/refreshReviewResult.d.ts +21 -0
- package/dist/engine/refreshReviewResult.d.ts.map +1 -1
- package/dist/engine/releaseClosedPreparation.d.ts +1171 -1003
- package/dist/engine/releaseClosedPreparation.d.ts.map +1 -1
- package/dist/engine/releaseExecution.d.ts +1170 -1003
- package/dist/engine/releaseExecution.d.ts.map +1 -1
- package/dist/engine/releaseFinishedWork.d.ts +10 -0
- package/dist/engine/releaseFinishedWork.d.ts.map +1 -1
- package/dist/engine/repository.d.ts +1115 -1003
- package/dist/engine/repository.d.ts.map +1 -1
- package/dist/engine/repository.js +12 -12
- package/dist/engine/repository.js.map +1 -1
- package/dist/engine/requestConflictRepair.d.ts +1170 -1003
- package/dist/engine/requestConflictRepair.d.ts.map +1 -1
- package/dist/engine/requestRework.d.ts +20 -0
- package/dist/engine/requestRework.d.ts.map +1 -1
- package/dist/engine/resolveCommand.d.ts +10 -0
- package/dist/engine/resolveCommand.d.ts.map +1 -1
- package/dist/engine/resolveExecution.d.ts +1170 -1003
- package/dist/engine/resolveExecution.d.ts.map +1 -1
- package/dist/engine/resumeAttempt.d.ts +1171 -1003
- package/dist/engine/resumeAttempt.d.ts.map +1 -1
- package/dist/engine/retireUnacknowledged.d.ts +20 -0
- package/dist/engine/retireUnacknowledged.d.ts.map +1 -1
- package/dist/engine/retryTerminal.d.ts +1160 -1003
- package/dist/engine/retryTerminal.d.ts.map +1 -1
- package/dist/engine/saveLaunch.d.ts +10598 -0
- package/dist/engine/saveLaunch.d.ts.map +1 -0
- package/dist/engine/saveLaunch.js +30 -0
- package/dist/engine/saveLaunch.js.map +1 -0
- package/dist/engine/scheduler.d.ts +21 -1
- package/dist/engine/scheduler.d.ts.map +1 -1
- package/dist/engine/scheduler.js +3 -5
- package/dist/engine/scheduler.js.map +1 -1
- package/dist/engine/sessionCleanup.d.ts +20 -0
- package/dist/engine/sessionCleanup.d.ts.map +1 -1
- package/dist/engine/settleMergedDelivery.d.ts +1170 -1003
- package/dist/engine/settleMergedDelivery.d.ts.map +1 -1
- package/dist/engine/steerBrief.d.ts +1075 -898
- package/dist/engine/steerBrief.d.ts.map +1 -1
- package/dist/engine/submissionFailure.d.ts +1150 -1003
- package/dist/engine/submissionFailure.d.ts.map +1 -1
- package/dist/engine/submitLaunch.d.ts +1160 -1003
- package/dist/engine/submitLaunch.d.ts.map +1 -1
- package/dist/engine/views.d.ts.map +1 -1
- package/dist/engine/views.js +4 -0
- package/dist/engine/views.js.map +1 -1
- package/dist/engine/workerReport.d.ts +30 -0
- package/dist/engine/workerReport.d.ts.map +1 -1
- package/dist/fleet.d.ts +2716 -983
- package/dist/fleet.d.ts.map +1 -1
- package/dist/fleet.js +4 -0
- package/dist/fleet.js.map +1 -1
- package/dist/host/actionCommands.d.ts.map +1 -1
- package/dist/host/actionCommands.js +7 -6
- package/dist/host/actionCommands.js.map +1 -1
- package/dist/host/admission.d.ts +24 -1
- package/dist/host/admission.d.ts.map +1 -1
- package/dist/host/admission.js +2 -2
- package/dist/host/admission.js.map +1 -1
- package/dist/host/answerWork.d.ts +12 -2
- package/dist/host/answerWork.d.ts.map +1 -1
- package/dist/host/answerWork.js +19 -23
- package/dist/host/answerWork.js.map +1 -1
- package/dist/host/commands.d.ts +28 -4
- package/dist/host/commands.d.ts.map +1 -1
- package/dist/host/commands.js +19 -5
- package/dist/host/commands.js.map +1 -1
- package/dist/host/config.d.ts +77 -1
- package/dist/host/config.d.ts.map +1 -1
- package/dist/host/config.js +37 -9
- package/dist/host/config.js.map +1 -1
- package/dist/host/configSettings.d.ts +486 -0
- package/dist/host/configSettings.d.ts.map +1 -0
- package/dist/host/configSettings.js +113 -0
- package/dist/host/configSettings.js.map +1 -0
- package/dist/host/daemon.d.ts +880 -1185
- package/dist/host/daemon.d.ts.map +1 -1
- package/dist/host/daemon.js +2 -1
- package/dist/host/daemon.js.map +1 -1
- package/dist/host/daemonClient.d.ts +300 -605
- package/dist/host/daemonClient.d.ts.map +1 -1
- package/dist/host/daemonClient.js +28 -7
- package/dist/host/daemonClient.js.map +1 -1
- package/dist/host/daemonContract.d.ts +1974 -3079
- package/dist/host/daemonContract.d.ts.map +1 -1
- package/dist/host/daemonContract.js +12 -4
- package/dist/host/daemonContract.js.map +1 -1
- package/dist/host/daemonDiagnostics.d.ts.map +1 -1
- package/dist/host/daemonDiagnostics.js +9 -3
- package/dist/host/daemonDiagnostics.js.map +1 -1
- package/dist/host/daemonHandlers.d.ts +2 -1
- package/dist/host/daemonHandlers.d.ts.map +1 -1
- package/dist/host/daemonHandlers.js +20 -7
- package/dist/host/daemonHandlers.js.map +1 -1
- package/dist/host/daemonSnapshots.d.ts.map +1 -1
- package/dist/host/daemonSnapshots.js +21 -1
- package/dist/host/daemonSnapshots.js.map +1 -1
- package/dist/host/dispatchRequests.d.ts +30 -0
- package/dist/host/dispatchRequests.d.ts.map +1 -0
- package/dist/host/dispatchRequests.js +40 -0
- package/dist/host/dispatchRequests.js.map +1 -0
- package/dist/host/follow.js +1 -1
- package/dist/host/follow.js.map +1 -1
- package/dist/host/followState.d.ts.map +1 -1
- package/dist/host/followState.js +5 -4
- package/dist/host/followState.js.map +1 -1
- package/dist/host/github.d.ts +5 -6
- package/dist/host/github.d.ts.map +1 -1
- package/dist/host/github.js +3 -4
- package/dist/host/github.js.map +1 -1
- package/dist/host/githubApi.d.ts +15 -0
- package/dist/host/githubApi.d.ts.map +1 -0
- package/dist/host/githubApi.js +117 -0
- package/dist/host/githubApi.js.map +1 -0
- package/dist/host/githubChecks.d.ts +13 -3
- package/dist/host/githubChecks.d.ts.map +1 -1
- package/dist/host/githubChecks.js +5 -5
- package/dist/host/githubChecks.js.map +1 -1
- package/dist/host/githubDelivery.d.ts +13 -1
- package/dist/host/githubDelivery.d.ts.map +1 -1
- package/dist/host/githubDelivery.js +39 -6
- package/dist/host/githubDelivery.js.map +1 -1
- package/dist/host/githubRateLimit.d.ts +23 -0
- package/dist/host/githubRateLimit.d.ts.map +1 -0
- package/dist/host/githubRateLimit.js +70 -0
- package/dist/host/githubRateLimit.js.map +1 -0
- package/dist/host/githubRequiredChecks.d.ts +1 -2
- package/dist/host/githubRequiredChecks.d.ts.map +1 -1
- package/dist/host/githubRequiredChecks.js +2 -2
- package/dist/host/githubRequiredChecks.js.map +1 -1
- package/dist/host/githubResponse.d.ts +10 -0
- package/dist/host/githubResponse.d.ts.map +1 -0
- package/dist/host/githubResponse.js +29 -0
- package/dist/host/githubResponse.js.map +1 -0
- package/dist/host/githubResult.d.ts +3 -2
- package/dist/host/githubResult.d.ts.map +1 -1
- package/dist/host/githubResult.js +9 -12
- package/dist/host/githubResult.js.map +1 -1
- package/dist/host/githubTransport.d.ts +13 -0
- package/dist/host/githubTransport.d.ts.map +1 -0
- package/dist/host/{githubRead.js → githubTransport.js} +9 -10
- package/dist/host/githubTransport.js.map +1 -0
- package/dist/host/integrations.d.ts +6 -0
- package/dist/host/integrations.d.ts.map +1 -0
- package/dist/host/integrations.js +34 -0
- package/dist/host/integrations.js.map +1 -0
- package/dist/host/liveConfig.d.ts +21 -0
- package/dist/host/liveConfig.d.ts.map +1 -0
- package/dist/host/liveConfig.js +74 -0
- package/dist/host/liveConfig.js.map +1 -0
- package/dist/host/providers.d.ts.map +1 -1
- package/dist/host/providers.js +2 -2
- package/dist/host/providers.js.map +1 -1
- package/dist/host/readWaitStates.d.ts.map +1 -1
- package/dist/host/readWaitStates.js +8 -18
- package/dist/host/readWaitStates.js.map +1 -1
- package/dist/host/reassignWork.d.ts +10 -0
- package/dist/host/reassignWork.d.ts.map +1 -1
- package/dist/host/recordDecisionResponse.d.ts +1 -0
- package/dist/host/recordDecisionResponse.d.ts.map +1 -1
- package/dist/host/releaseWork.d.ts +24 -3
- package/dist/host/releaseWork.d.ts.map +1 -1
- package/dist/host/releaseWork.js +11 -7
- package/dist/host/releaseWork.js.map +1 -1
- package/dist/host/renderStatus.d.ts +2 -2
- package/dist/host/renderStatus.d.ts.map +1 -1
- package/dist/host/renderStatus.js +8 -2
- package/dist/host/renderStatus.js.map +1 -1
- package/dist/host/reportBoard.d.ts +1 -1
- package/dist/host/reportBoard.d.ts.map +1 -1
- package/dist/host/reportBoard.js +6 -3
- package/dist/host/reportBoard.js.map +1 -1
- package/dist/host/reportPublication.d.ts +2 -1
- package/dist/host/reportPublication.d.ts.map +1 -1
- package/dist/host/reportPublication.js +5 -2
- package/dist/host/reportPublication.js.map +1 -1
- package/dist/host/runtime.d.ts +8 -6
- package/dist/host/runtime.d.ts.map +1 -1
- package/dist/host/runtime.js +37 -46
- package/dist/host/runtime.js.map +1 -1
- package/dist/host/snapshotStream.d.ts.map +1 -1
- package/dist/host/snapshotStream.js +4 -1
- package/dist/host/snapshotStream.js.map +1 -1
- package/dist/host/status.d.ts +22 -2
- package/dist/host/status.d.ts.map +1 -1
- package/dist/host/status.js +19 -5
- package/dist/host/status.js.map +1 -1
- package/dist/host/statusLayer.d.ts +3 -3
- package/dist/host/statusLayer.d.ts.map +1 -1
- package/dist/host/statusLayer.js +13 -3
- package/dist/host/statusLayer.js.map +1 -1
- package/dist/host/waitOutcome.d.ts.map +1 -1
- package/dist/host/waitOutcome.js +5 -2
- package/dist/host/waitOutcome.js.map +1 -1
- package/dist/model.d.ts +39 -0
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +5 -0
- package/dist/model.js.map +1 -1
- package/dist/operations.d.ts +270 -0
- package/dist/operations.d.ts.map +1 -1
- package/dist/packageInfo.d.ts +1 -1
- package/dist/packageInfo.js +1 -1
- package/dist/policy.d.ts +7 -0
- package/dist/policy.d.ts.map +1 -1
- package/dist/policy.js +2 -0
- package/dist/policy.js.map +1 -1
- package/dist/providers/codexCloud.d.ts +2 -0
- package/dist/providers/codexCloud.d.ts.map +1 -1
- package/dist/providers/codexCloud.js +2 -1
- package/dist/providers/codexCloud.js.map +1 -1
- package/dist/qualifyDependencies.d.ts +10 -0
- package/dist/qualifyDependencies.d.ts.map +1 -1
- package/dist/scheduling/admission.d.ts +1635 -0
- package/dist/scheduling/admission.d.ts.map +1 -0
- package/dist/scheduling/admission.js +11 -0
- package/dist/scheduling/admission.js.map +1 -0
- package/dist/scheduling/areas.d.ts +30 -0
- package/dist/scheduling/areas.d.ts.map +1 -1
- package/dist/scheduling/backPressure.d.ts +1637 -0
- package/dist/scheduling/backPressure.d.ts.map +1 -0
- package/dist/scheduling/backPressure.js +44 -0
- package/dist/scheduling/backPressure.js.map +1 -0
- package/dist/storage/FleetStoreOptions.d.ts +2 -2
- package/dist/storage/FleetStoreOptions.d.ts.map +1 -1
- package/dist/storage/addShapeColumns.d.ts +5 -0
- package/dist/storage/addShapeColumns.d.ts.map +1 -0
- package/dist/storage/addShapeColumns.js +24 -0
- package/dist/storage/addShapeColumns.js.map +1 -0
- package/dist/storage/dispatchStore.d.ts +47 -0
- package/dist/storage/dispatchStore.d.ts.map +1 -0
- package/dist/storage/dispatchStore.js +89 -0
- package/dist/storage/dispatchStore.js.map +1 -0
- package/dist/storage/errors.d.ts +2 -1
- package/dist/storage/errors.d.ts.map +1 -1
- package/dist/storage/errors.js +2 -1
- package/dist/storage/errors.js.map +1 -1
- package/dist/storage/fleetMigrations.d.ts +1 -1
- package/dist/storage/fleetMigrations.d.ts.map +1 -1
- package/dist/storage/fleetMigrations.js +24 -17
- package/dist/storage/fleetMigrations.js.map +1 -1
- package/dist/storage/listedRecords.d.ts +9 -0
- package/dist/storage/listedRecords.d.ts.map +1 -0
- package/dist/storage/listedRecords.js +40 -0
- package/dist/storage/listedRecords.js.map +1 -0
- package/dist/storage/makePostgresFleetStore.d.ts +2 -6
- package/dist/storage/makePostgresFleetStore.d.ts.map +1 -1
- package/dist/storage/makePostgresFleetStore.js +4 -10
- package/dist/storage/makePostgresFleetStore.js.map +1 -1
- package/dist/storage/model.d.ts +9 -0
- package/dist/storage/model.d.ts.map +1 -1
- package/dist/storage/model.js.map +1 -1
- package/dist/storage/shapeV14.d.ts +808 -0
- package/dist/storage/shapeV14.d.ts.map +1 -0
- package/dist/storage/shapeV14.js +18 -0
- package/dist/storage/shapeV14.js.map +1 -0
- package/package.json +6 -6
- package/src/DispatchRequest.ts +13 -0
- package/src/attention.ts +5 -0
- package/src/board/fleetField.ts +5 -0
- package/src/board/markdown.ts +7 -2
- package/src/cli.ts +24 -10
- package/src/engine/admissionOrder.ts +25 -0
- package/src/engine/dispatchCommand.ts +29 -5
- package/src/engine/failureContext.ts +1 -0
- package/src/engine/failureMessage.ts +12 -1
- package/src/engine/localOnlyCriteria.ts +6 -1
- package/src/engine/makeLaunch.ts +4 -17
- package/src/engine/makeState.ts +30 -26
- package/src/engine/mergeReadiness.ts +6 -5
- package/src/engine/obtainReview.ts +2 -1
- package/src/engine/prepareCommand.ts +1 -1
- package/src/engine/readOrContinueReview.ts +2 -1
- package/src/engine/readRetry.ts +23 -1
- package/src/engine/reconcileAttempt.ts +2 -1
- package/src/engine/recordResponseCommand.ts +38 -0
- package/src/engine/recoverStall.ts +1 -1
- package/src/engine/repository.ts +17 -16
- package/src/engine/saveLaunch.ts +45 -0
- package/src/engine/scheduler.ts +4 -6
- package/src/engine/views.ts +5 -0
- package/src/fleet.ts +4 -0
- package/src/host/actionCommands.ts +22 -7
- package/src/host/admission.ts +3 -3
- package/src/host/answerWork.ts +28 -27
- package/src/host/commands.ts +29 -8
- package/src/host/config.ts +46 -9
- package/src/host/configSettings.ts +124 -0
- package/src/host/daemon.ts +2 -1
- package/src/host/daemonClient.ts +42 -7
- package/src/host/daemonContract.ts +12 -4
- package/src/host/daemonDiagnostics.ts +11 -3
- package/src/host/daemonHandlers.ts +24 -7
- package/src/host/daemonSnapshots.ts +24 -1
- package/src/host/dispatchRequests.ts +53 -0
- package/src/host/follow.ts +1 -1
- package/src/host/followState.ts +6 -6
- package/src/host/github.ts +8 -6
- package/src/host/githubApi.ts +142 -0
- package/src/host/githubChecks.ts +6 -5
- package/src/host/githubDelivery.ts +47 -10
- package/src/host/githubRateLimit.ts +91 -0
- package/src/host/githubRequiredChecks.ts +2 -2
- package/src/host/githubResponse.ts +37 -0
- package/src/host/githubResult.ts +15 -17
- package/src/host/githubTransport.ts +31 -0
- package/src/host/integrations.ts +40 -0
- package/src/host/liveConfig.ts +134 -0
- package/src/host/providers.ts +4 -2
- package/src/host/readWaitStates.ts +8 -20
- package/src/host/releaseWork.ts +12 -9
- package/src/host/renderStatus.ts +10 -3
- package/src/host/reportBoard.ts +6 -3
- package/src/host/reportPublication.ts +6 -4
- package/src/host/runtime.ts +48 -56
- package/src/host/snapshotStream.ts +6 -1
- package/src/host/status.ts +24 -7
- package/src/host/statusLayer.ts +21 -5
- package/src/host/waitOutcome.ts +5 -2
- package/src/model.ts +6 -0
- package/src/packageInfo.ts +1 -1
- package/src/policy.ts +7 -0
- package/src/providers/codexCloud.ts +2 -1
- package/src/scheduling/admission.ts +19 -0
- package/src/scheduling/backPressure.ts +55 -0
- package/src/storage/FleetStoreOptions.ts +7 -2
- package/src/storage/addShapeColumns.ts +24 -0
- package/src/storage/dispatchStore.ts +104 -0
- package/src/storage/errors.ts +2 -1
- package/src/storage/fleetMigrations.ts +24 -17
- package/src/storage/listedRecords.ts +53 -0
- package/src/storage/makePostgresFleetStore.ts +4 -10
- package/src/storage/model.ts +7 -0
- package/src/storage/shapeV14.ts +19 -0
- package/dist/host/githubRead.d.ts +0 -5
- package/dist/host/githubRead.d.ts.map +0 -1
- package/dist/host/githubRead.js.map +0 -1
- package/dist/host/recordPayloads.d.ts +0 -4
- package/dist/host/recordPayloads.d.ts.map +0 -1
- package/dist/host/recordPayloads.js +0 -21
- package/dist/host/recordPayloads.js.map +0 -1
- package/dist/storage/migrateFleet.d.ts +0 -3
- package/dist/storage/migrateFleet.d.ts.map +0 -1
- package/dist/storage/migrateFleet.js +0 -11
- package/dist/storage/migrateFleet.js.map +0 -1
- package/src/host/githubRead.ts +0 -20
- package/src/host/recordPayloads.ts +0 -24
- package/src/storage/migrateFleet.ts +0 -11
package/src/host/githubChecks.ts
CHANGED
|
@@ -2,8 +2,9 @@ import { Effect, Schema } from "effect";
|
|
|
2
2
|
import { ServiceUnavailable } from "@shivaedev/platform/errors/taxonomy.ts";
|
|
3
3
|
import { withFailureContext } from "#engine/failureContext.ts";
|
|
4
4
|
import type { FleetError } from "#errors.ts";
|
|
5
|
+
import type { GithubRead } from "#host/github.ts";
|
|
5
6
|
import { CheckPages, githubCheckState, StatusPages } from "#host/githubCheckState.ts";
|
|
6
|
-
import {
|
|
7
|
+
import { githubFailure } from "#host/githubRateLimit.ts";
|
|
7
8
|
import { githubRequiredChecks } from "#host/githubRequiredChecks.ts";
|
|
8
9
|
import type { WorkResult } from "#policy.ts";
|
|
9
10
|
|
|
@@ -30,11 +31,11 @@ export function makeGithubChecks<R>(read: (endpoint: string) => Effect.Effect<st
|
|
|
30
31
|
const commit = `repos/${owner}/${repository}/commits/${result.head}`;
|
|
31
32
|
const checks = yield* read(`${commit}/check-runs?per_page=100&filter=latest`).pipe(
|
|
32
33
|
Effect.flatMap(Schema.decodeUnknownEffect(Schema.fromJsonString(CheckPages))),
|
|
33
|
-
Effect.mapError((
|
|
34
|
+
Effect.mapError(githubFailure("GitHub check runs are unavailable or invalid")),
|
|
34
35
|
);
|
|
35
36
|
const statuses = yield* read(`${commit}/status?per_page=100`).pipe(
|
|
36
37
|
Effect.flatMap(Schema.decodeUnknownEffect(Schema.fromJsonString(StatusPages))),
|
|
37
|
-
Effect.mapError((
|
|
38
|
+
Effect.mapError(githubFailure("GitHub commit statuses are unavailable or invalid")),
|
|
38
39
|
);
|
|
39
40
|
if (
|
|
40
41
|
statuses.length === 0
|
|
@@ -48,6 +49,6 @@ export function makeGithubChecks<R>(read: (endpoint: string) => Effect.Effect<st
|
|
|
48
49
|
});
|
|
49
50
|
}
|
|
50
51
|
|
|
51
|
-
export function githubChecks(
|
|
52
|
-
return makeGithubChecks(
|
|
52
|
+
export function githubChecks(read: GithubRead, branch = "main") {
|
|
53
|
+
return makeGithubChecks(read.pages, branch);
|
|
53
54
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import * as NodeServices from "@effect/platform-node/NodeServices";
|
|
2
1
|
import { Effect, Schema } from "effect";
|
|
3
2
|
import { BadRequest, ServiceUnavailable } from "@shivaedev/platform/errors/taxonomy.ts";
|
|
4
3
|
import { conflictingPr, movedPrHead } from "#engine/deliveryFailure.ts";
|
|
5
4
|
import { withFailureContext } from "#engine/failureContext.ts";
|
|
6
5
|
import type { FleetError } from "#errors.ts";
|
|
7
|
-
import {
|
|
6
|
+
import type { GithubRead } from "#host/github.ts";
|
|
7
|
+
import { githubFailure } from "#host/githubRateLimit.ts";
|
|
8
8
|
import type { ChangeResult } from "#policy.ts";
|
|
9
9
|
|
|
10
10
|
const PullRequest = Schema.Struct({
|
|
@@ -21,20 +21,57 @@ function failure(message: string, reason: "integration" | "invalid" = "invalid")
|
|
|
21
21
|
return reason === "integration" ? new ServiceUnavailable({ message }) : new BadRequest({ message });
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
)
|
|
24
|
+
const Sha = Schema.String.check(Schema.isPattern(/^[a-f\d]{40}$/u));
|
|
25
|
+
const RestPullRequest = Schema.Struct({
|
|
26
|
+
base: Schema.Struct({ sha: Sha }),
|
|
27
|
+
head: Schema.Struct({ sha: Sha }),
|
|
28
|
+
htmlUrl: Schema.NonEmptyString,
|
|
29
|
+
mergeable: Schema.NullOr(Schema.Boolean),
|
|
30
|
+
mergeCommitSha: Schema.NullOr(Schema.String),
|
|
31
|
+
merged: Schema.Boolean,
|
|
32
|
+
mergedAt: Schema.NullOr(Schema.NonEmptyString),
|
|
33
|
+
state: Schema.Literals(["open", "closed"]),
|
|
34
|
+
}).pipe(Schema.encodeKeys({ htmlUrl: "html_url", mergeCommitSha: "merge_commit_sha", mergedAt: "merged_at" }));
|
|
35
|
+
|
|
36
|
+
function mergeability(mergeable: boolean | null) {
|
|
37
|
+
if (mergeable === null) {
|
|
38
|
+
return "UNKNOWN";
|
|
39
|
+
}
|
|
40
|
+
return mergeable ? "MERGEABLE" : "CONFLICTING";
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function deliveryState(observed: typeof RestPullRequest.Type) {
|
|
44
|
+
if (observed.merged) {
|
|
45
|
+
return "MERGED";
|
|
46
|
+
}
|
|
47
|
+
return observed.state === "open" ? "OPEN" : "CLOSED";
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function readPullRequest(read: GithubRead["get"]) {
|
|
51
|
+
return (pr: string) => {
|
|
52
|
+
const match = /^https:\/\/github\.com\/(?<repository>[^/]+\/[^/]+)\/pull\/(?<number>[1-9]\d*)$/u.exec(pr)?.groups;
|
|
53
|
+
return read(`repos/${match?.repository}/pulls/${match?.number}`).pipe(
|
|
54
|
+
Effect.flatMap(Schema.decodeUnknownEffect(Schema.fromJsonString(RestPullRequest))),
|
|
55
|
+
Effect.map((observed): typeof PullRequest.Encoded => ({
|
|
56
|
+
baseRefOid: observed.base.sha,
|
|
57
|
+
headRefOid: observed.head.sha,
|
|
58
|
+
mergeable: mergeability(observed.mergeable),
|
|
59
|
+
mergeCommit: observed.merged && observed.mergeCommitSha !== null ? { oid: observed.mergeCommitSha } : null,
|
|
60
|
+
mergedAt: observed.mergedAt,
|
|
61
|
+
state: deliveryState(observed),
|
|
62
|
+
url: observed.htmlUrl,
|
|
63
|
+
})),
|
|
64
|
+
Effect.mapError(githubFailure("PR delivery observation failed; check GitHub CLI access and response")),
|
|
65
|
+
);
|
|
66
|
+
};
|
|
30
67
|
}
|
|
31
68
|
|
|
32
|
-
export function githubDelivery(
|
|
69
|
+
export function githubDelivery(read: (pr: string) => Effect.Effect<unknown, FleetError>) {
|
|
33
70
|
return Effect.fn("FleetHost.githubDelivery")(function* (result: typeof ChangeResult.Type) {
|
|
34
71
|
if (result.pr.match(/^https:\/\/github\.com\/[^/]+\/[^/]+\/pull\/[1-9]\d*$/u) === null) {
|
|
35
72
|
return yield* withFailureContext(new BadRequest({ message: "Delivery requires the adopted GitHub PR URL" }), { code: "delivery-pr-required" });
|
|
36
73
|
}
|
|
37
|
-
const pr = yield* Schema.decodeUnknownEffect(PullRequest)(yield* read(
|
|
74
|
+
const pr = yield* Schema.decodeUnknownEffect(PullRequest)(yield* read(result.pr)).pipe(
|
|
38
75
|
Effect.mapError(() => failure("PR delivery observation returned an unknown shape", "integration")),
|
|
39
76
|
);
|
|
40
77
|
yield* validateDelivery(pr, result);
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { ServiceUnavailable } from "@shivaedev/platform/errors/taxonomy.ts";
|
|
2
|
+
import { failureContext, withFailureContext } from "#engine/failureContext.ts";
|
|
3
|
+
import { headerCount, type ParsedResponse } from "#host/githubResponse.ts";
|
|
4
|
+
|
|
5
|
+
export type GithubPause = "rate-limit" | "reserve";
|
|
6
|
+
export interface GithubObservation {
|
|
7
|
+
readonly limit: number;
|
|
8
|
+
readonly limitedBy: GithubPause | null;
|
|
9
|
+
readonly limitedUntil: number | null;
|
|
10
|
+
readonly observedAt: number;
|
|
11
|
+
readonly remaining: number;
|
|
12
|
+
readonly reset: number;
|
|
13
|
+
readonly resource: string;
|
|
14
|
+
readonly used: number;
|
|
15
|
+
}
|
|
16
|
+
export type RecordedObservation = Omit<GithubObservation, "limitedBy" | "limitedUntil">;
|
|
17
|
+
|
|
18
|
+
// Every local tool shares one GitHub token, so Fleet leaves the last fifth of each budget to agents and people.
|
|
19
|
+
export const RESERVE_SHARE = 0.2;
|
|
20
|
+
const FULL_SPEED_SHARE = 0.5;
|
|
21
|
+
const SLOWEST_PACE_MS = 5 * 60_000;
|
|
22
|
+
const BACKOFF_MS = 60_000;
|
|
23
|
+
const BACKOFF_LIMIT_MS = 15 * 60_000;
|
|
24
|
+
|
|
25
|
+
export function githubRateLimited(error: unknown): error is ServiceUnavailable {
|
|
26
|
+
return error instanceof ServiceUnavailable && failureContext(error).retryAt !== undefined;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function githubFailure(message: string) {
|
|
30
|
+
return (error: unknown): ServiceUnavailable => (githubRateLimited(error) ? error : new ServiceUnavailable({ message }));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const PAUSE_MESSAGES: Readonly<Record<GithubPause, string>> = {
|
|
34
|
+
"rate-limit": "GitHub is rate-limited until",
|
|
35
|
+
reserve: `GitHub paused below the ${RESERVE_SHARE * 100}% reserve until`,
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export function githubPaused(by: GithubPause, until: number) {
|
|
39
|
+
return withFailureContext(new ServiceUnavailable({ message: `${PAUSE_MESSAGES[by]} ${new Date(until).toISOString()}` }), {
|
|
40
|
+
attentionOwner: "automation",
|
|
41
|
+
retryAt: until,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function reservedUntil(observation: RecordedObservation | undefined, now: number) {
|
|
46
|
+
if (observation === undefined || observation.reset * 1000 <= now) {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
return observation.remaining < observation.limit * RESERVE_SHARE ? observation.reset * 1000 : undefined;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function readObservation(headers: ReadonlyMap<string, string>, observedAt: number): RecordedObservation | undefined {
|
|
53
|
+
const resource = headers.get("x-ratelimit-resource");
|
|
54
|
+
const limit = headerCount(headers, "x-ratelimit-limit");
|
|
55
|
+
const remaining = headerCount(headers, "x-ratelimit-remaining");
|
|
56
|
+
const reset = headerCount(headers, "x-ratelimit-reset");
|
|
57
|
+
if (resource === undefined || limit === undefined || remaining === undefined || reset === undefined) {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
return { limit, observedAt, remaining, reset, resource, used: headerCount(headers, "x-ratelimit-used") ?? limit - remaining };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function rateLimitWait(response: ParsedResponse, observation: RecordedObservation | undefined, now: number, failures: number) {
|
|
64
|
+
const retryAfter = headerCount(response.headers, "retry-after");
|
|
65
|
+
const exhausted = observation?.remaining === 0 && observation.reset * 1000 > now ? observation.reset * 1000 : undefined;
|
|
66
|
+
const limited = observation?.remaining === 0 || retryAfter !== undefined || /rate limit/iu.test(response.body);
|
|
67
|
+
if (!([403, 429].includes(response.status) && limited)) {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
if (retryAfter !== undefined) {
|
|
71
|
+
return now + retryAfter * 1000;
|
|
72
|
+
}
|
|
73
|
+
return exhausted ?? now + Math.min(BACKOFF_LIMIT_MS, BACKOFF_MS * 2 ** failures);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function pace(observation: GithubObservation | undefined, intervalMs: number, now: number) {
|
|
77
|
+
if (observation === undefined) {
|
|
78
|
+
return intervalMs;
|
|
79
|
+
}
|
|
80
|
+
if (observation.limitedUntil !== null && observation.limitedUntil > now) {
|
|
81
|
+
return Math.max(intervalMs, observation.limitedUntil - now);
|
|
82
|
+
}
|
|
83
|
+
const reset = observation.reset * 1000;
|
|
84
|
+
const share = observation.remaining / Math.max(1, observation.limit);
|
|
85
|
+
if (reset <= now || share >= FULL_SPEED_SHARE) {
|
|
86
|
+
return intervalMs;
|
|
87
|
+
}
|
|
88
|
+
const stretch = Math.min(1, (FULL_SPEED_SHARE - share) / (FULL_SPEED_SHARE - RESERVE_SHARE)) ** 2;
|
|
89
|
+
const paced = intervalMs + (Math.max(intervalMs, SLOWEST_PACE_MS) - intervalMs) * stretch;
|
|
90
|
+
return Math.round(Math.max(intervalMs, Math.min(paced, reset - now)));
|
|
91
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Effect, Schema } from "effect";
|
|
2
|
-
import { ServiceUnavailable } from "@shivaedev/platform/errors/taxonomy.ts";
|
|
3
2
|
import type { FleetError } from "#errors.ts";
|
|
3
|
+
import { githubFailure } from "#host/githubRateLimit.ts";
|
|
4
4
|
|
|
5
5
|
const RulePages = Schema.Array(Schema.Array(Schema.Struct({ parameters: Schema.optional(Schema.Unknown), type: Schema.String })));
|
|
6
6
|
const RequiredParameters = Schema.Struct({ requiredStatusChecks: Schema.Array(Schema.Struct({ context: Schema.String })) }).pipe(
|
|
@@ -15,5 +15,5 @@ export function githubRequiredChecks<R>(read: (endpoint: string) => Effect.Effec
|
|
|
15
15
|
const rules = pages.flat().filter((rule) => rule.type === "required_status_checks");
|
|
16
16
|
const parameters = yield* Effect.forEach(rules, (rule) => Schema.decodeUnknownEffect(RequiredParameters)(rule.parameters));
|
|
17
17
|
return [...new Set(parameters.flatMap((rule) => rule.requiredStatusChecks.map((check) => check.context)))];
|
|
18
|
-
}).pipe(Effect.mapError((
|
|
18
|
+
}).pipe(Effect.mapError(githubFailure("GitHub required status checks are unavailable or invalid")));
|
|
19
19
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export interface ParsedResponse {
|
|
2
|
+
readonly body: string;
|
|
3
|
+
readonly headers: ReadonlyMap<string, string>;
|
|
4
|
+
readonly status: number;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function parseResponse(output: string): ParsedResponse | undefined {
|
|
8
|
+
const split = /\r?\n\r?\n/u.exec(output);
|
|
9
|
+
const head = split === null ? output : output.slice(0, split.index);
|
|
10
|
+
const [statusLine = "", ...lines] = head.split(/\r?\n/u);
|
|
11
|
+
const status = Number(/^HTTP\/\S+ (?<status>\d{3})/u.exec(statusLine)?.groups?.status);
|
|
12
|
+
if (!Number.isInteger(status)) {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
const headers = new Map<string, string>();
|
|
16
|
+
for (const line of lines) {
|
|
17
|
+
const colon = line.indexOf(":");
|
|
18
|
+
if (colon > 0) {
|
|
19
|
+
headers.set(line.slice(0, colon).trim().toLowerCase(), line.slice(colon + 1).trim());
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return { body: split === null ? "" : output.slice(split.index + split[0].length), headers, status };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function headerCount(headers: ReadonlyMap<string, string>, name: string) {
|
|
26
|
+
const value = headers.get(name);
|
|
27
|
+
return value !== undefined && /^\d+$/u.test(value) ? Number(value) : undefined;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function nextLink(headers: ReadonlyMap<string, string>) {
|
|
31
|
+
return /<(?<url>[^>]+)>;\s*rel="next"/u.exec(headers.get("link") ?? "")?.groups?.url;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function requestResource(endpoint: string) {
|
|
35
|
+
const path = endpoint.replace(/^https:\/\/api\.github\.com\//u, "");
|
|
36
|
+
return path.startsWith("search/") ? "search" : "core";
|
|
37
|
+
}
|
package/src/host/githubResult.ts
CHANGED
|
@@ -1,21 +1,14 @@
|
|
|
1
|
-
import * as NodeServices from "@effect/platform-node/NodeServices";
|
|
2
1
|
import { Effect } from "effect";
|
|
3
2
|
import { BadRequest, Conflict, ServiceUnavailable } from "@shivaedev/platform/errors/taxonomy.ts";
|
|
4
3
|
import { withFailureContext } from "#engine/failureContext.ts";
|
|
5
4
|
import type { FleetError } from "#errors.ts";
|
|
6
5
|
import type { FleetHost } from "#host/config.ts";
|
|
7
|
-
import { FilePages, type GithubRead, githubJson, PullRequest
|
|
8
|
-
import { githubRead } from "#host/githubRead.ts";
|
|
9
|
-
import type { MainSource } from "#host/mainSource.ts";
|
|
6
|
+
import { FilePages, type GithubRead, githubJson, PullRequest } from "#host/github.ts";
|
|
10
7
|
import { resultReport } from "#host/resultReport.ts";
|
|
11
8
|
import type { BoardWork, WorkResult } from "#policy.ts";
|
|
12
9
|
import type { SessionObservation } from "#session/schema.ts";
|
|
13
10
|
|
|
14
|
-
export function githubResult(
|
|
15
|
-
host: FleetHost,
|
|
16
|
-
main: MainSource["Service"],
|
|
17
|
-
read: GithubRead = (args) => githubRead(args, main.repositoryRoot).pipe(Effect.provide(NodeServices.layer)),
|
|
18
|
-
) {
|
|
11
|
+
export function githubResult(host: FleetHost, read: GithubRead, repository: Effect.Effect<string, FleetError>) {
|
|
19
12
|
return Effect.fn("FleetHost.githubResult")(function* (_work: BoardWork, observation: SessionObservation): Effect.fn.Return<WorkResult, FleetError> {
|
|
20
13
|
if (observation.execution !== "completed") {
|
|
21
14
|
return yield* new BadRequest({ message: "Result adoption requires completed worker execution" });
|
|
@@ -24,25 +17,30 @@ export function githubResult(
|
|
|
24
17
|
if (report.pr.kind === "none") {
|
|
25
18
|
return { evidence: [observation.output], head: report.head, kind: "no-change" };
|
|
26
19
|
}
|
|
27
|
-
return yield* adoptPullRequest(host, read, report.head, report.pr.url);
|
|
20
|
+
return yield* adoptPullRequest(host, read, yield* repository, report.head, report.pr.url);
|
|
28
21
|
});
|
|
29
22
|
}
|
|
30
23
|
|
|
31
|
-
const adoptPullRequest = Effect.fn("FleetHost.adoptPullRequest")(function* (
|
|
32
|
-
|
|
24
|
+
const adoptPullRequest = Effect.fn("FleetHost.adoptPullRequest")(function* (
|
|
25
|
+
host: FleetHost,
|
|
26
|
+
read: GithubRead,
|
|
27
|
+
repository: string,
|
|
28
|
+
head: string,
|
|
29
|
+
prUrl: string,
|
|
30
|
+
) {
|
|
33
31
|
const url = new URL(prUrl);
|
|
34
32
|
const parts = url.pathname.split("/");
|
|
35
33
|
const owner = parts[1];
|
|
36
34
|
const name = parts[2];
|
|
37
35
|
const number = Number(parts[4]);
|
|
38
|
-
if (!Number.isSafeInteger(number) || `${owner}/${name}`.toLowerCase() !== repository.
|
|
36
|
+
if (!Number.isSafeInteger(number) || `${owner}/${name}`.toLowerCase() !== repository.toLowerCase()) {
|
|
39
37
|
return yield* withFailureContext(new BadRequest({ message: "Reported PR must belong to the host repository" }), { code: "foreign-pr" });
|
|
40
38
|
}
|
|
41
|
-
const endpoint = `repos/${repository
|
|
42
|
-
const before = yield* githubJson(PullRequest, read
|
|
39
|
+
const endpoint = `repos/${repository}/pulls/${number}`;
|
|
40
|
+
const before = yield* githubJson(PullRequest, read.get(endpoint));
|
|
43
41
|
yield* validatePullRequest(before, head, number, prUrl, host.repository.branch);
|
|
44
|
-
const files = (yield* githubJson(FilePages, read
|
|
45
|
-
const after = yield* githubJson(PullRequest, read
|
|
42
|
+
const files = (yield* githubJson(FilePages, read.pages(`${endpoint}/files?per_page=100`))).flat();
|
|
43
|
+
const after = yield* githubJson(PullRequest, read.get(endpoint));
|
|
46
44
|
yield* validatePullRequest(after, head, number, prUrl, host.repository.branch);
|
|
47
45
|
if (before.changedFiles !== after.changedFiles) {
|
|
48
46
|
return yield* new Conflict({ message: "PR changed paths moved during observation" });
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Context, Effect, Layer, Stream } from "effect";
|
|
2
|
+
import { ChildProcess, ChildProcessSpawner } from "effect/process";
|
|
3
|
+
import { ServiceUnavailable } from "@shivaedev/platform/errors/taxonomy.ts";
|
|
4
|
+
import type { FleetError } from "#errors.ts";
|
|
5
|
+
|
|
6
|
+
export interface GithubResponse {
|
|
7
|
+
readonly exitCode: number;
|
|
8
|
+
readonly output: string;
|
|
9
|
+
}
|
|
10
|
+
export class GithubTransport extends Context.Service<GithubTransport, (args: readonly string[]) => Effect.Effect<GithubResponse, FleetError>>()(
|
|
11
|
+
"Fleet/GithubTransport",
|
|
12
|
+
) {}
|
|
13
|
+
|
|
14
|
+
export const ghTransport = Layer.effect(GithubTransport)(
|
|
15
|
+
Effect.gen(function* () {
|
|
16
|
+
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
17
|
+
return (args: readonly string[]) =>
|
|
18
|
+
Effect.scoped(
|
|
19
|
+
Effect.gen(function* () {
|
|
20
|
+
const process = yield* spawner.spawn(ChildProcess.make("gh", args));
|
|
21
|
+
const output = yield* process.stdout.pipe(Stream.decodeText, Stream.mkString);
|
|
22
|
+
return { exitCode: Number(yield* process.exitCode), output };
|
|
23
|
+
}),
|
|
24
|
+
).pipe(
|
|
25
|
+
Effect.timeout("60 seconds"),
|
|
26
|
+
Effect.mapError(
|
|
27
|
+
() => new ServiceUnavailable({ message: "GitHub evidence could not be read; check gh authentication and repository access" }),
|
|
28
|
+
),
|
|
29
|
+
);
|
|
30
|
+
}),
|
|
31
|
+
);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as NodeServices from "@effect/platform-node/NodeServices";
|
|
2
|
+
import { Effect, Layer } from "effect";
|
|
3
|
+
import { defineService } from "@shivaedev/effect-service/define-service.ts";
|
|
4
|
+
import { ServiceUnavailable } from "@shivaedev/platform/errors/taxonomy.ts";
|
|
5
|
+
import type { DecisionCode } from "#DecisionCode.ts";
|
|
6
|
+
import { withFailureContext } from "#engine/failureContext.ts";
|
|
7
|
+
import type { FleetHost } from "#host/config.ts";
|
|
8
|
+
import { GithubApi } from "#host/githubApi.ts";
|
|
9
|
+
import { githubChecks } from "#host/githubChecks.ts";
|
|
10
|
+
import { githubDelivery, readPullRequest } from "#host/githubDelivery.ts";
|
|
11
|
+
import { githubResult } from "#host/githubResult.ts";
|
|
12
|
+
import { MainSource } from "#host/mainSource.ts";
|
|
13
|
+
import { reportRepository } from "#host/reportPublication.ts";
|
|
14
|
+
import { FleetIntegrations } from "#policy.ts";
|
|
15
|
+
|
|
16
|
+
function unconfigured(message: string, code: DecisionCode = "fleet-integration") {
|
|
17
|
+
return Effect.fail(withFailureContext(new ServiceUnavailable({ message }), { attentionOwner: "automation", code, retryable: false }));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function hostIntegrations(host: FleetHost) {
|
|
21
|
+
const HostIntegrations = defineService({
|
|
22
|
+
id: "Fleet/HostIntegrations",
|
|
23
|
+
initialize: Effect.all({ github: GithubApi, main: MainSource }),
|
|
24
|
+
methods: ({ github, main }) =>
|
|
25
|
+
FleetIntegrations.of({
|
|
26
|
+
checks: (_work, result) =>
|
|
27
|
+
result.kind === "no-change"
|
|
28
|
+
? unconfigured("No-change validation is not configured in this Fleet host; inspect the worker session", "no-change-checks-unconfigured")
|
|
29
|
+
: githubChecks(github, host.repository.branch)(result),
|
|
30
|
+
delivery: githubDelivery(readPullRequest(github.get)),
|
|
31
|
+
main: main.observe,
|
|
32
|
+
result:
|
|
33
|
+
host.result === "github"
|
|
34
|
+
? githubResult(host, github, reportRepository(main.repositoryRoot, host.repository.remote).pipe(Effect.provide(NodeServices.layer)))
|
|
35
|
+
: () => unconfigured("Worker result adoption is not configured in this Fleet host; inspect the worker session"),
|
|
36
|
+
}),
|
|
37
|
+
requires: [MainSource, GithubApi],
|
|
38
|
+
});
|
|
39
|
+
return Layer.effect(FleetIntegrations)(HostIntegrations).pipe(Layer.provide(HostIntegrations.layer));
|
|
40
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import * as NodeServices from "@effect/platform-node/NodeServices";
|
|
2
|
+
import {
|
|
3
|
+
Clock,
|
|
4
|
+
Context,
|
|
5
|
+
Deferred,
|
|
6
|
+
Effect,
|
|
7
|
+
Equal,
|
|
8
|
+
Fiber,
|
|
9
|
+
FileSystem,
|
|
10
|
+
Layer,
|
|
11
|
+
Result,
|
|
12
|
+
Schedule,
|
|
13
|
+
Schema,
|
|
14
|
+
Semaphore,
|
|
15
|
+
Stream,
|
|
16
|
+
SubscriptionRef,
|
|
17
|
+
} from "effect";
|
|
18
|
+
import { type FleetHost, HostConfig, HostConfigRejected, type HostFailure, readHostConfig, resolveHost } from "#host/config.ts";
|
|
19
|
+
import { changedSettings, withReloadable } from "#host/configSettings.ts";
|
|
20
|
+
import { hostGuidance } from "#host/guidance.ts";
|
|
21
|
+
|
|
22
|
+
type Role = "reviewer" | "worker";
|
|
23
|
+
type Guidance = Effect.Effect<string | undefined, HostFailure>;
|
|
24
|
+
|
|
25
|
+
export interface AppliedConfig {
|
|
26
|
+
readonly guidance: Readonly<Record<Role, Guidance>>;
|
|
27
|
+
readonly host: FleetHost;
|
|
28
|
+
readonly loadedAt: number;
|
|
29
|
+
readonly rejected?: HostConfigRejected;
|
|
30
|
+
readonly restartRequired: readonly string[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export class LiveConfig extends Context.Service<
|
|
34
|
+
LiveConfig,
|
|
35
|
+
{ readonly changes: Stream.Stream<AppliedConfig>; readonly current: Effect.Effect<AppliedConfig> }
|
|
36
|
+
>()("@shivaedev/work-fleet/LiveConfig") {}
|
|
37
|
+
|
|
38
|
+
const SETTLE = "100 millis";
|
|
39
|
+
const RETRY = Schedule.min([Schedule.exponential("100 millis"), Schedule.spaced("5 seconds")]);
|
|
40
|
+
|
|
41
|
+
const applyHost = Effect.fn("FleetHost.applyHost")(function* <E>(host: FleetHost, rejected: (role: Role, failure: HostFailure) => E) {
|
|
42
|
+
const guidance = yield* Effect.all({
|
|
43
|
+
reviewer: hostGuidance(host, "reviewer").pipe(Effect.mapError((failure) => rejected("reviewer", failure))),
|
|
44
|
+
worker: hostGuidance(host, "worker").pipe(Effect.mapError((failure) => rejected("worker", failure))),
|
|
45
|
+
});
|
|
46
|
+
const applied: AppliedConfig = { guidance, host, loadedAt: yield* Clock.currentTimeMillis, restartRequired: [] };
|
|
47
|
+
return applied;
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
function served(ref: SubscriptionRef.SubscriptionRef<AppliedConfig>) {
|
|
51
|
+
return LiveConfig.of({ changes: SubscriptionRef.changes(ref), current: SubscriptionRef.get(ref) });
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function staticConfig(host: FleetHost) {
|
|
55
|
+
return Layer.effect(LiveConfig)(applyHost(host, (_role, failure) => failure).pipe(Effect.flatMap(SubscriptionRef.make), Effect.map(served)));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function watchedConfig(host: FleetHost) {
|
|
59
|
+
const file = host.configFile;
|
|
60
|
+
return file === undefined ? staticConfig(host) : Layer.effect(LiveConfig)(watchConfig(host, file)).pipe(Layer.provide(NodeServices.layer));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const watchConfig = Effect.fn("FleetHost.watchConfig")(function* (host: FleetHost, file: string) {
|
|
64
|
+
const fs = yield* FileSystem.FileSystem;
|
|
65
|
+
const ref = yield* SubscriptionRef.make(yield* applyHost(host, (_role, failure) => failure));
|
|
66
|
+
const lock = yield* Semaphore.make(1);
|
|
67
|
+
let seen = host.config;
|
|
68
|
+
const loadEdit = Effect.fn("FleetHost.loadEdit")(function* (previous: AppliedConfig, next: HostConfig) {
|
|
69
|
+
const config = yield* Schema.decodeUnknownEffect(HostConfig)(withReloadable(previous.host.config, next)).pipe(
|
|
70
|
+
Effect.mapError((error) => new HostConfigRejected({ file, message: `Fleet host configuration ${file} cannot be applied: ${error.message}` })),
|
|
71
|
+
);
|
|
72
|
+
const applied = yield* applyHost(
|
|
73
|
+
resolveHost(previous.host.boardDir, config, file),
|
|
74
|
+
(role, failure) => new HostConfigRejected({ field: `worker.${role}Guidance`, file, message: failure.message }),
|
|
75
|
+
);
|
|
76
|
+
return { ...applied, restartRequired: changedSettings(config, next) };
|
|
77
|
+
});
|
|
78
|
+
const reload = lock.withPermits(1)(
|
|
79
|
+
Effect.gen(function* () {
|
|
80
|
+
const previous = yield* SubscriptionRef.get(ref);
|
|
81
|
+
const outcome = yield* readHostConfig(file).pipe(
|
|
82
|
+
Effect.flatMap((edited) =>
|
|
83
|
+
Equal.equals(edited, seen) && previous.rejected === undefined
|
|
84
|
+
? Effect.succeed(undefined)
|
|
85
|
+
: Effect.map(loadEdit(previous, edited), (loaded) => ({ applied: loaded, next: edited })),
|
|
86
|
+
),
|
|
87
|
+
Effect.result,
|
|
88
|
+
);
|
|
89
|
+
if (Result.isFailure(outcome)) {
|
|
90
|
+
if (previous.rejected?.message !== outcome.failure.message) {
|
|
91
|
+
yield* Effect.logWarning("Fleet kept its last good config after a rejected edit", outcome.failure);
|
|
92
|
+
yield* SubscriptionRef.set(ref, { ...previous, rejected: outcome.failure });
|
|
93
|
+
}
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (outcome.success === undefined) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const { applied, next } = outcome.success;
|
|
100
|
+
seen = next;
|
|
101
|
+
if (applied.restartRequired.length > 0 && !Equal.equals(applied.restartRequired, previous.restartRequired)) {
|
|
102
|
+
yield* Effect.logWarning(`Fleet keeps its running values until a daemon restart for: ${applied.restartRequired.join(", ")}`);
|
|
103
|
+
}
|
|
104
|
+
yield* SubscriptionRef.set(ref, applied);
|
|
105
|
+
}),
|
|
106
|
+
);
|
|
107
|
+
const ready = yield* Deferred.make<void>();
|
|
108
|
+
// An editor that saves by renaming replaces the watched file, so each replacement starts a new watch on the new file.
|
|
109
|
+
const watching = Effect.scoped(
|
|
110
|
+
Effect.gen(function* () {
|
|
111
|
+
const events = yield* fs.watch(file).pipe(
|
|
112
|
+
Stream.takeUntil((event) => event._tag !== "Update"),
|
|
113
|
+
Stream.debounce(SETTLE),
|
|
114
|
+
Stream.runForEach(() => reload),
|
|
115
|
+
Effect.forkScoped,
|
|
116
|
+
);
|
|
117
|
+
// The watch registers once its fiber runs; reading after that applies an edit made while no watch was active.
|
|
118
|
+
yield* Effect.sleep(SETTLE);
|
|
119
|
+
yield* reload;
|
|
120
|
+
yield* Deferred.succeed(ready, undefined);
|
|
121
|
+
yield* Fiber.join(events);
|
|
122
|
+
}),
|
|
123
|
+
);
|
|
124
|
+
yield* watching.pipe(
|
|
125
|
+
Effect.tapError((error) =>
|
|
126
|
+
Deferred.succeed(ready, undefined).pipe(Effect.andThen(Effect.logWarning("Watching the Fleet config failed; retrying", error))),
|
|
127
|
+
),
|
|
128
|
+
Effect.retry(RETRY),
|
|
129
|
+
Effect.forever,
|
|
130
|
+
Effect.forkScoped,
|
|
131
|
+
);
|
|
132
|
+
yield* Deferred.await(ready);
|
|
133
|
+
return served(ref);
|
|
134
|
+
});
|
package/src/host/providers.ts
CHANGED
|
@@ -23,8 +23,10 @@ export function hostProvider(host: FleetHost) {
|
|
|
23
23
|
Effect.fail(new HostFailure({ message: 'provider "cloud" needs cloud settings in the host configuration' })),
|
|
24
24
|
);
|
|
25
25
|
}
|
|
26
|
-
const { requestTimeoutMs = 60_000, ...cloud } = host.cloud;
|
|
27
|
-
return codexCloudLayer.pipe(
|
|
26
|
+
const { recoveryGraceMs = 5000, requestTimeoutMs = 60_000, ...cloud } = host.cloud;
|
|
27
|
+
return codexCloudLayer.pipe(
|
|
28
|
+
Layer.provide([Layer.succeed(CodexCloudConfig)({ ...cloud, recoveryGraceMs, requestTimeoutMs }), NodeServices.layer]),
|
|
29
|
+
);
|
|
28
30
|
}
|
|
29
31
|
}
|
|
30
32
|
}
|
|
@@ -16,25 +16,13 @@ export const readWaitStates = Effect.fn("FleetReader.readWaitStates")(function*
|
|
|
16
16
|
...Object.fromEntries(Object.entries(shapeColumns(shape)).map(([name, kind]) => [name, columnSchema(kind)])),
|
|
17
17
|
"work_id": Schema.String,
|
|
18
18
|
}) {}
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
tableName: `${options.namespace}_records`,
|
|
24
|
-
});
|
|
25
|
-
const rows = yield* repository
|
|
26
|
-
.findMany({
|
|
27
|
-
orderBy: { direction: "asc", field: "work_id" },
|
|
28
|
-
})
|
|
29
|
-
.pipe(
|
|
30
|
-
Effect.catchTag("SqlError", (error) => {
|
|
31
|
-
const cause = error.reason.cause;
|
|
32
|
-
return typeof cause === "object" && cause !== null && "code" in cause && cause.code === "42P01" ? Effect.succeed([]) : Effect.fail(error);
|
|
33
|
-
}),
|
|
34
|
-
);
|
|
35
|
-
const selected = rows.filter((row) => ids === undefined || ids.includes(row.work_id));
|
|
36
|
-
const states = yield* Schema.decodeUnknownEffect(Schema.Array(State))(yield* recordValues(selected, shape, options.namespace));
|
|
37
|
-
return states.map((state) => ({ ...state, outcome: state.outcome ?? {} }));
|
|
19
|
+
const repository = yield* makeRepository(SnapshotRow, {
|
|
20
|
+
idColumn: "work_id",
|
|
21
|
+
spanPrefix: "FleetReader",
|
|
22
|
+
tableName: `${options.namespace}_records`,
|
|
38
23
|
});
|
|
39
|
-
|
|
24
|
+
const rows = yield* repository.findMany({ orderBy: { direction: "asc", field: "work_id" } });
|
|
25
|
+
const selected = rows.filter((row) => ids === undefined || ids.includes(row.work_id));
|
|
26
|
+
const states = yield* Schema.decodeUnknownEffect(Schema.Array(State))(yield* recordValues(selected, shape, options.namespace));
|
|
27
|
+
return states.map((state) => ({ ...state, outcome: state.outcome ?? {} }));
|
|
40
28
|
});
|
package/src/host/releaseWork.ts
CHANGED
|
@@ -13,26 +13,29 @@ const { searchSnapshot, watchChanges } = board;
|
|
|
13
13
|
const { ResponseConfig, Responses } = responses;
|
|
14
14
|
|
|
15
15
|
export function releaseWork(host: FleetHost, workIds: readonly string[], parts: HostParts = productionParts(host)) {
|
|
16
|
-
return releaseItems(host, workIds).pipe(Effect.provide(hostLayer(host, parts)));
|
|
16
|
+
return withDecisionResponses(host, releaseItems(host, workIds)).pipe(Effect.provide(hostLayer(host, parts)));
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export function releaseItems(host: FleetHost, workIds: readonly string[]) {
|
|
20
|
-
return
|
|
20
|
+
return Effect.forEach(workIds, releaseItem(host.boardDir));
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
// Indexing a large Board takes seconds, so the watched index starts warming at once and later responses read only changed files.
|
|
24
|
+
export function decisionResponses(host: FleetHost) {
|
|
25
|
+
return Layer.unwrap(
|
|
25
26
|
Effect.gen(function* () {
|
|
26
27
|
const changes = yield* watchChanges(host.boardDir);
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
return
|
|
30
|
-
Effect.provide(Responses.layer.pipe(Layer.provide(Layer.succeed(ResponseConfig, { changes, enabled: true, index, root: host.boardDir })))),
|
|
31
|
-
);
|
|
28
|
+
const index = (yield* searchSnapshot(host.boardDir, undefined, changes)).pipe(Effect.provide(NodeServices.layer));
|
|
29
|
+
yield* index.pipe(Effect.ignore, Effect.forkScoped);
|
|
30
|
+
return Responses.layer.pipe(Layer.provide(Layer.succeed(ResponseConfig, { changes, enabled: true, index, root: host.boardDir })));
|
|
32
31
|
}),
|
|
33
32
|
);
|
|
34
33
|
}
|
|
35
34
|
|
|
35
|
+
export function withDecisionResponses<A, E, R>(host: FleetHost, effect: Effect.Effect<A, E, R>) {
|
|
36
|
+
return effect.pipe(Effect.provide(decisionResponses(host)));
|
|
37
|
+
}
|
|
38
|
+
|
|
36
39
|
function releaseItem(root: string) {
|
|
37
40
|
return Effect.fn("FleetHost.releaseItem")(function* (workId: string) {
|
|
38
41
|
const fleet = yield* Fleet;
|