@shivaedev/work-fleet 0.2.0 → 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 +47 -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 +302 -607
- 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 +882 -1987
- 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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shapeV14.d.ts","sourceRoot":"","sources":["../../src/storage/shapeV14.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAJR,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wCAJ2C,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2CACsB,QAAQ;;;;;;qBAKpF,MAAM;yBAAI,WAAW,EAAE,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iCAFnC,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iCAEF,MAAM;qCAAI,WAAW,EAAE,SAAS;;;yCAKM,QAAQ;;;;;CAEpC,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { attemptV12 } from "#storage/attemptV12.ts";
|
|
2
|
+
import { cycleV12 } from "#storage/cycleV12.ts";
|
|
3
|
+
import { decisionV12 } from "#storage/typedDecisionsV12.ts";
|
|
4
|
+
const attempt = { fields: { ...attemptV12.fields, overLimit: "boolean" } };
|
|
5
|
+
const publicationWork = { fields: { ...decisionV12.fields.publicationWork.fields, priority: "string" } };
|
|
6
|
+
const cycle = {
|
|
7
|
+
...cycleV12.fields,
|
|
8
|
+
attempts: { array: attempt },
|
|
9
|
+
decision: { fields: { ...decisionV12.fields, publicationWork } },
|
|
10
|
+
dispatchNow: { fields: { ignoreAreas: "boolean" } },
|
|
11
|
+
};
|
|
12
|
+
export const shapeV14 = {
|
|
13
|
+
fields: {
|
|
14
|
+
...cycle,
|
|
15
|
+
history: { array: { fields: { ...cycle, archivedAt: "number" } } },
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=shapeV14.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shapeV14.js","sourceRoot":"","sources":["../../src/storage/shapeV14.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEhD,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAE5D,MAAM,OAAO,GAAG,EAAE,MAAM,EAAE,EAAE,GAAG,UAAU,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,EAAW,CAAC;AACpF,MAAM,eAAe,GAAG,EAAE,MAAM,EAAE,EAAE,GAAG,WAAW,CAAC,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAW,CAAC;AAClH,MAAM,KAAK,GAAG;IACb,GAAG,QAAQ,CAAC,MAAM;IAClB,QAAQ,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE;IAC5B,QAAQ,EAAE,EAAE,MAAM,EAAE,EAAE,GAAG,WAAW,CAAC,MAAM,EAAE,eAAe,EAAE,EAAE;IAChE,WAAW,EAAE,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE,EAAE;CAC1C,CAAC;AACX,MAAM,CAAC,MAAM,QAAQ,GAAG;IACvB,MAAM,EAAE;QACP,GAAG,KAAK;QACR,OAAO,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,GAAG,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,EAAE;KAClE;CACwB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shivaedev/work-fleet",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Optional Board-backed execution, review and authorized delivery",
|
|
5
5
|
"homepage": "https://github.com/ShivaeDev/platform/tree/main/packages/work-fleet#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -48,8 +48,8 @@
|
|
|
48
48
|
"@shivaedev/effect-contract": "0.5.1",
|
|
49
49
|
"@shivaedev/effect-service": "0.3.0",
|
|
50
50
|
"@shivaedev/effect-sql": "0.5.0",
|
|
51
|
-
"@shivaedev/platform": "0.14.
|
|
52
|
-
"@shivaedev/work-board": "0.
|
|
51
|
+
"@shivaedev/platform": "0.14.2",
|
|
52
|
+
"@shivaedev/work-board": "0.15.0",
|
|
53
53
|
"yaml": "2.9.1"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
@@ -57,9 +57,9 @@
|
|
|
57
57
|
"@effect/platform-node-shared": "4.0.4",
|
|
58
58
|
"@effect/vitest": "4.0.4",
|
|
59
59
|
"@shivaedev/effect-test": "0.5.0",
|
|
60
|
-
"@shivaedev/effect-test-sql": "0.
|
|
61
|
-
"@shivaedev/quality": "0.
|
|
62
|
-
"@types/node": "24.19.
|
|
60
|
+
"@shivaedev/effect-test-sql": "0.5.2",
|
|
61
|
+
"@shivaedev/quality": "0.23.0",
|
|
62
|
+
"@types/node": "24.19.2",
|
|
63
63
|
"@typescript/native": "npm:typescript@7.0.2",
|
|
64
64
|
"effect": "4.0.4",
|
|
65
65
|
"typescript": "npm:@typescript/typescript6@6.0.2",
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
|
|
3
|
+
export const DispatchRequest = Schema.Struct({
|
|
4
|
+
acceptedAt: Schema.Number,
|
|
5
|
+
completedAt: Schema.optional(Schema.Number),
|
|
6
|
+
error: Schema.optional(Schema.String),
|
|
7
|
+
id: Schema.String,
|
|
8
|
+
ignoreAreas: Schema.optional(Schema.Boolean),
|
|
9
|
+
now: Schema.optional(Schema.Boolean),
|
|
10
|
+
status: Schema.Literals(["pending", "completed", "failed"]),
|
|
11
|
+
workId: Schema.String,
|
|
12
|
+
});
|
|
13
|
+
export type DispatchRequest = typeof DispatchRequest.Type;
|
package/src/attention.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { Schema } from "effect";
|
|
|
3
3
|
export const AttentionOwner = Schema.Literals(["maintainer", "orchestrator", "automation"]);
|
|
4
4
|
export type AttentionOwner = typeof AttentionOwner.Type;
|
|
5
5
|
|
|
6
|
+
export const ANSWER_RECORDED = "Answer recorded; applying in the background";
|
|
7
|
+
|
|
6
8
|
export function waitingOwner(record: {
|
|
7
9
|
readonly attentionOwner?: AttentionOwner | undefined;
|
|
8
10
|
readonly blocker?: string | undefined;
|
|
@@ -11,6 +13,9 @@ export function waitingOwner(record: {
|
|
|
11
13
|
readonly launchRetry?: { readonly retryAt: number } | undefined;
|
|
12
14
|
readonly stage: string;
|
|
13
15
|
}): AttentionOwner | undefined {
|
|
16
|
+
if (record.blocker === ANSWER_RECORDED) {
|
|
17
|
+
return "automation";
|
|
18
|
+
}
|
|
14
19
|
if (record.launchRetry !== undefined || (record.stage === "prepared" && record.blocker?.startsWith("waiting for dependency "))) {
|
|
15
20
|
return "automation";
|
|
16
21
|
}
|
package/src/board/fleetField.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { ParsedMetadata } from "@shivaedev/work-board/integration/board.ts"
|
|
|
4
4
|
const APPROVAL = "fleet";
|
|
5
5
|
const LAUNCH = "fleet-launch";
|
|
6
6
|
const DELIVERABLE = "fleet-deliverable";
|
|
7
|
+
const PRIORITY = "fleet-priority";
|
|
7
8
|
const parsedFields = new WeakMap<ParsedMetadata, ReadonlyMap<string, unknown>>();
|
|
8
9
|
|
|
9
10
|
function fleetField(parsed: ParsedMetadata, field: string): unknown {
|
|
@@ -33,3 +34,7 @@ export function fleetLaunch(parsed: ParsedMetadata): unknown {
|
|
|
33
34
|
export function fleetDeliverable(parsed: ParsedMetadata): unknown {
|
|
34
35
|
return fleetField(parsed, DELIVERABLE);
|
|
35
36
|
}
|
|
37
|
+
|
|
38
|
+
export function fleetPriority(parsed: ParsedMetadata): unknown {
|
|
39
|
+
return fleetField(parsed, PRIORITY);
|
|
40
|
+
}
|
package/src/board/markdown.ts
CHANGED
|
@@ -6,13 +6,13 @@ import { briefRevision } from "#board/briefRevision.ts";
|
|
|
6
6
|
import { completionMarkdown } from "#board/completionMarkdown.ts";
|
|
7
7
|
import { decisionReading } from "#board/decisionReading.ts";
|
|
8
8
|
import { boundDocuments, boundSnapshot, refreshSnapshotDocument, snapshotDocument } from "#board/documents.ts";
|
|
9
|
-
import { fleetApproved, fleetDeliverable } from "#board/fleetField.ts";
|
|
9
|
+
import { fleetApproved, fleetDeliverable, fleetPriority } from "#board/fleetField.ts";
|
|
10
10
|
import { publishBoard } from "#board/publish.ts";
|
|
11
11
|
import { publishReport } from "#board/publishReport.ts";
|
|
12
12
|
import { workMetadata } from "#board/readPass.ts";
|
|
13
13
|
import { workRevision } from "#board/workRevision.ts";
|
|
14
14
|
import { writeCompletion } from "#board/writeCompletion.ts";
|
|
15
|
-
import { BoardFailure, BoardGateway } from "#policy.ts";
|
|
15
|
+
import { BoardFailure, BoardGateway, Priority } from "#policy.ts";
|
|
16
16
|
import { RepositoryPath } from "#preparation/schema.ts";
|
|
17
17
|
|
|
18
18
|
class BoardRoot extends Context.Service<BoardRoot, string>()("Fleet/BoardRoot") {}
|
|
@@ -38,6 +38,10 @@ const MarkdownBoard = defineService({
|
|
|
38
38
|
if (deliverable !== undefined && deliverable !== "report") {
|
|
39
39
|
return yield* Effect.fail(new BoardFailure({ message: "Invalid fleet-deliverable; use report or omit the field for pull requests." }));
|
|
40
40
|
}
|
|
41
|
+
const priority = fleetPriority(found.parsed);
|
|
42
|
+
if (priority !== undefined && !Schema.is(Priority)(priority)) {
|
|
43
|
+
return yield* Effect.fail(new BoardFailure({ message: "Invalid fleet-priority; use urgent, high or normal, or omit the field." }));
|
|
44
|
+
}
|
|
41
45
|
return {
|
|
42
46
|
approved: fleetApproved(found.parsed),
|
|
43
47
|
areas: found.parsed.fields.areas,
|
|
@@ -45,6 +49,7 @@ const MarkdownBoard = defineService({
|
|
|
45
49
|
...(deliverable === "report" ? { deliverable: "report" as const } : {}),
|
|
46
50
|
context: found.source,
|
|
47
51
|
dependsOn: (found.parsed.fields.relationships ?? []).filter((relation) => relation.kind === "depends_on").map((relation) => relation.target),
|
|
52
|
+
...(priority === undefined ? {} : { priority }),
|
|
48
53
|
revision: briefRevision(found.parsed),
|
|
49
54
|
sourcePath: path.join(realRoot, found.file),
|
|
50
55
|
workId,
|
package/src/cli.ts
CHANGED
|
@@ -26,13 +26,25 @@ const serveCommand = Command.make(
|
|
|
26
26
|
|
|
27
27
|
const dispatchCommand = Command.make(
|
|
28
28
|
"dispatch",
|
|
29
|
-
{
|
|
29
|
+
{
|
|
30
|
+
board,
|
|
31
|
+
config,
|
|
32
|
+
ignoreAreas: Flag.Boolean("ignore-areas").pipe(Flag.withDefault(false), Flag.withDescription("With --now, also skip area claims")),
|
|
33
|
+
now: Flag.Boolean("now").pipe(
|
|
34
|
+
Flag.withDefault(false),
|
|
35
|
+
Flag.withDescription("Launch over concurrency, open-PR back pressure and backlog limits; areas and dependencies still apply"),
|
|
36
|
+
),
|
|
37
|
+
port,
|
|
38
|
+
workId: Argument.String("id"),
|
|
39
|
+
},
|
|
30
40
|
Effect.fn("WorkFleetCli.dispatch")(function* (input) {
|
|
31
|
-
const {
|
|
32
|
-
const value = yield*
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
41
|
+
const { daemonRequest } = yield* Effect.promise(() => import("#host/daemonClient.ts"));
|
|
42
|
+
const value = yield* daemonRequest(
|
|
43
|
+
input.port,
|
|
44
|
+
(client) => client("daemon.dispatch", { ignoreAreas: input.ignoreAreas, now: input.now, workId: input.workId }),
|
|
45
|
+
`dispatch ${input.workId}`,
|
|
46
|
+
);
|
|
47
|
+
yield* Console.log(`${value.workId}: dispatch recorded${value.now ? " over the limits" : ""}; preparing and launching in the background`);
|
|
36
48
|
}),
|
|
37
49
|
).pipe(Command.withDescription("Prepare the current approved revision of one Board item and launch it"));
|
|
38
50
|
|
|
@@ -46,13 +58,15 @@ const statusCommand = Command.make(
|
|
|
46
58
|
workId: Argument.String("id").pipe(Argument.optional),
|
|
47
59
|
},
|
|
48
60
|
Effect.fn("WorkFleetCli.status")(function* (input) {
|
|
49
|
-
const [{
|
|
61
|
+
const [{ daemonRequest }, { renderStatus }] = yield* Effect.promise(() =>
|
|
50
62
|
Promise.all([import("#host/daemonClient.ts"), import("#host/renderStatus.ts")]),
|
|
51
63
|
);
|
|
52
64
|
const workId = Option.getOrUndefined(input.workId);
|
|
53
|
-
const current = yield*
|
|
54
|
-
|
|
55
|
-
|
|
65
|
+
const current = yield* daemonRequest(
|
|
66
|
+
input.port,
|
|
67
|
+
(client) => client("daemon.status", workId === undefined ? {} : { workId }),
|
|
68
|
+
workId === undefined ? "status" : `status ${workId}`,
|
|
69
|
+
);
|
|
56
70
|
yield* Console.log(input.json ? JSON.stringify(current) : renderStatus(current, input.port));
|
|
57
71
|
}),
|
|
58
72
|
).pipe(Command.withDescription("Show active and completed Fleet work, and waiting work grouped by owner"));
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import type { EngineState } from "#engine/makeState.ts";
|
|
3
|
+
import { retryPending } from "#engine/readRetry.ts";
|
|
4
|
+
import type { FleetRecord } from "#model.ts";
|
|
5
|
+
import type { Priority } from "#policy.ts";
|
|
6
|
+
import type { Versioned } from "#storage/model.ts";
|
|
7
|
+
|
|
8
|
+
const ranks: Readonly<Record<Priority, number>> = { high: 1, normal: 2, urgent: 0 };
|
|
9
|
+
|
|
10
|
+
export function admissionOrder(state: EngineState) {
|
|
11
|
+
return Effect.fn("Fleet.admissionOrder")(function* (records: readonly Versioned<FleetRecord>[]) {
|
|
12
|
+
const prepared = records.filter(({ value }) => value.stage === "prepared");
|
|
13
|
+
const ranked = yield* Effect.forEach(prepared, (entry) =>
|
|
14
|
+
retryPending(state, entry.value)
|
|
15
|
+
? Effect.succeed({ entry, rank: ranks.normal })
|
|
16
|
+
: state.board.get(entry.value.workId).pipe(
|
|
17
|
+
Effect.map((work) => ({ entry, rank: ranks[work.priority ?? "normal"] })),
|
|
18
|
+
Effect.orElseSucceed(() => ({ entry, rank: ranks.normal })),
|
|
19
|
+
),
|
|
20
|
+
);
|
|
21
|
+
return ranked
|
|
22
|
+
.sort((left, right) => (right.entry.value.launchRetry?.retryAt ?? 0) - (left.entry.value.launchRetry?.retryAt ?? 0) || left.rank - right.rank)
|
|
23
|
+
.map(({ entry }) => entry);
|
|
24
|
+
});
|
|
25
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Effect, Result } from "effect";
|
|
2
2
|
import { Forbidden } from "@shivaedev/platform/errors/taxonomy.ts";
|
|
3
|
+
import { waitingOwner } from "#attention.ts";
|
|
3
4
|
import { approveDispatchedBrief } from "#engine/approveBrief.ts";
|
|
4
5
|
import { authorizeBriefContext } from "#engine/boardBrief.ts";
|
|
5
6
|
import { failureCode } from "#engine/failureCode.ts";
|
|
@@ -10,10 +11,16 @@ import type { EngineState } from "#engine/makeState.ts";
|
|
|
10
11
|
import { clearIntegrationRetry, readRetry, retryPending } from "#engine/readRetry.ts";
|
|
11
12
|
import { refreshBrief } from "#engine/refreshBrief.ts";
|
|
12
13
|
import { releaseClosedPreparation } from "#engine/releaseClosedPreparation.ts";
|
|
14
|
+
import type { DispatchNow, FleetRecord } from "#model.ts";
|
|
13
15
|
import { assessPreparation } from "#preparation/compatibility.ts";
|
|
16
|
+
import type { Versioned } from "#storage/model.ts";
|
|
14
17
|
export function dispatchCommand(state: EngineState, launch: ReturnType<typeof makeLaunch>) {
|
|
15
18
|
const { board, load, save, decision, integrations, policy } = state;
|
|
16
|
-
|
|
19
|
+
function rememberNow(stored: Versioned<FleetRecord>, now: DispatchNow | undefined) {
|
|
20
|
+
const requested = requestedNow(stored.value, now);
|
|
21
|
+
return requested === undefined ? Effect.succeed(stored) : save(stored, requested);
|
|
22
|
+
}
|
|
23
|
+
const dispatchPrepared = Effect.fn("Fleet.dispatchPrepared")(function* (workId: string, prompt?: string, now?: DispatchNow) {
|
|
17
24
|
let stored = yield* load(workId);
|
|
18
25
|
const work = yield* board.get(workId);
|
|
19
26
|
stored = yield* refreshBrief(state, stored, work);
|
|
@@ -25,6 +32,7 @@ export function dispatchCommand(state: EngineState, launch: ReturnType<typeof ma
|
|
|
25
32
|
if (released !== undefined) {
|
|
26
33
|
return released;
|
|
27
34
|
}
|
|
35
|
+
stored = yield* rememberNow(stored, now);
|
|
28
36
|
const authorized = yield* authorizeBriefContext(stored.value, work).pipe(Effect.result);
|
|
29
37
|
if (Result.isFailure(authorized)) {
|
|
30
38
|
return yield* decision(
|
|
@@ -56,18 +64,21 @@ export function dispatchCommand(state: EngineState, launch: ReturnType<typeof ma
|
|
|
56
64
|
if (current.value.stage !== "prepared") {
|
|
57
65
|
return current;
|
|
58
66
|
}
|
|
59
|
-
|
|
67
|
+
const waiting = {
|
|
60
68
|
...current.value,
|
|
61
69
|
admissionReady: !(error instanceof Forbidden),
|
|
62
70
|
attentionOwner: failureOwner(error),
|
|
63
71
|
blocker: failureMessage(error),
|
|
64
|
-
}
|
|
72
|
+
};
|
|
73
|
+
if (!sameWait(current.value, waiting)) {
|
|
74
|
+
yield* save(current, waiting);
|
|
75
|
+
}
|
|
65
76
|
return yield* Effect.fail(error);
|
|
66
77
|
}),
|
|
67
78
|
),
|
|
68
79
|
);
|
|
69
80
|
});
|
|
70
|
-
return Effect.fn("Fleet.dispatch")(function* (workId: string, prompt?: string) {
|
|
81
|
+
return Effect.fn("Fleet.dispatch")(function* (workId: string, prompt?: string, now?: DispatchNow) {
|
|
71
82
|
const current = yield* load(workId);
|
|
72
83
|
if (retryPending(state, current.value)) {
|
|
73
84
|
return current;
|
|
@@ -75,7 +86,7 @@ export function dispatchCommand(state: EngineState, launch: ReturnType<typeof ma
|
|
|
75
86
|
if (current.value.integrationRetry !== undefined) {
|
|
76
87
|
yield* save(current, { ...current.value, attentionOwner: undefined, blocker: undefined });
|
|
77
88
|
}
|
|
78
|
-
return yield* dispatchPrepared(workId, prompt).pipe(
|
|
89
|
+
return yield* dispatchPrepared(workId, prompt, now).pipe(
|
|
79
90
|
Effect.flatMap((updated) => clearIntegrationRetry(state, updated)),
|
|
80
91
|
Effect.catch((error) =>
|
|
81
92
|
Effect.gen(function* () {
|
|
@@ -86,3 +97,16 @@ export function dispatchCommand(state: EngineState, launch: ReturnType<typeof ma
|
|
|
86
97
|
);
|
|
87
98
|
});
|
|
88
99
|
}
|
|
100
|
+
|
|
101
|
+
function requestedNow(record: FleetRecord, now: DispatchNow | undefined): FleetRecord | undefined {
|
|
102
|
+
const current = record.dispatchNow;
|
|
103
|
+
if (now === undefined || (current !== undefined && (current.ignoreAreas || !now.ignoreAreas))) {
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
return { ...record, dispatchNow: now };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Every scheduler pass retries waiting work, so rewriting an unchanged wait would make each pass write and notify once per waiter.
|
|
110
|
+
function sameWait(current: FleetRecord, waiting: FleetRecord) {
|
|
111
|
+
return current.blocker === waiting.blocker && current.admissionReady === waiting.admissionReady && current.attentionOwner === waitingOwner(waiting);
|
|
112
|
+
}
|
|
@@ -10,10 +10,21 @@ export function failureMessage(error: unknown): string {
|
|
|
10
10
|
return "Fresh available provider quota is required";
|
|
11
11
|
}
|
|
12
12
|
if (error instanceof StorageCapacity) {
|
|
13
|
-
return
|
|
13
|
+
return capacityMessage(error);
|
|
14
14
|
}
|
|
15
15
|
if (error instanceof StorageConflict) {
|
|
16
16
|
return "Work changed during this observation; load the current record";
|
|
17
17
|
}
|
|
18
18
|
return "The integration is unavailable; inspect runtime diagnostics";
|
|
19
19
|
}
|
|
20
|
+
|
|
21
|
+
function capacityMessage(error: StorageCapacity) {
|
|
22
|
+
switch (error.kind) {
|
|
23
|
+
case "open-pull-requests":
|
|
24
|
+
return `waiting for open PRs to merge: ${error.occupied ?? error.limit} of ${error.limit}`;
|
|
25
|
+
case "merge-work":
|
|
26
|
+
return `waiting for ${error.occupied ?? 0} review or repair launches to go first (limit ${error.limit})`;
|
|
27
|
+
default:
|
|
28
|
+
return `${error.kind} capacity is occupied (limit ${error.limit})`;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -2,11 +2,16 @@ import { Effect } from "effect";
|
|
|
2
2
|
import { workMetadata } from "#board/readPass.ts";
|
|
3
3
|
import type { BoardWork } from "#policy.ts";
|
|
4
4
|
|
|
5
|
+
function mentions(text: string, localPath: string) {
|
|
6
|
+
const escaped = localPath.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
7
|
+
return new RegExp(`(?<![\\w.-])${escaped}(?![\\w-])`, "u").test(text);
|
|
8
|
+
}
|
|
9
|
+
|
|
5
10
|
export const localOnlyCriteria = Effect.fn("Fleet.localOnlyCriteria")(function* (work: BoardWork, localPath: string | undefined) {
|
|
6
11
|
if (localPath === undefined) {
|
|
7
12
|
return undefined;
|
|
8
13
|
}
|
|
9
|
-
const criteria = (yield* workMetadata(work)).fields.criteria?.filter(({ text }) => text
|
|
14
|
+
const criteria = (yield* workMetadata(work)).fields.criteria?.filter(({ text }) => mentions(text, localPath)) ?? [];
|
|
10
15
|
if (criteria.length > 0) {
|
|
11
16
|
return `Criteria ${criteria.map(({ id }) => `"${id}"`).join(", ")} reference ${localPath}: Cloud workers cannot read local-only Board data`;
|
|
12
17
|
}
|
package/src/engine/makeLaunch.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { launchRecord } from "#engine/launchRecord.ts";
|
|
|
7
7
|
import { localOnlyCriteria } from "#engine/localOnlyCriteria.ts";
|
|
8
8
|
import type { EngineState } from "#engine/makeState.ts";
|
|
9
9
|
import { releaseClosedPreparation } from "#engine/releaseClosedPreparation.ts";
|
|
10
|
+
import { saveLaunch } from "#engine/saveLaunch.ts";
|
|
10
11
|
import { submitLaunch } from "#engine/submitLaunch.ts";
|
|
11
12
|
import type { Attempt, FleetRecord } from "#model.ts";
|
|
12
13
|
import type { DecisionResponse } from "#policy.ts";
|
|
@@ -14,7 +15,7 @@ import { policyGuidance } from "#policyGuidance.ts";
|
|
|
14
15
|
import { reportPrompt, withWorkerGuidance } from "#prompt/worker.ts";
|
|
15
16
|
import type { Versioned } from "#storage/model.ts";
|
|
16
17
|
export function makeLaunch(state: EngineState) {
|
|
17
|
-
const { store, board,
|
|
18
|
+
const { store, board, sessions, load } = state;
|
|
18
19
|
return Effect.fn("Fleet.launch")(function* (
|
|
19
20
|
input: Versioned<FleetRecord>,
|
|
20
21
|
role: "worker" | "repair",
|
|
@@ -27,6 +28,7 @@ export function makeLaunch(state: EngineState) {
|
|
|
27
28
|
},
|
|
28
29
|
) {
|
|
29
30
|
const stored = input;
|
|
31
|
+
const policy = yield* state.current;
|
|
30
32
|
const work = yield* board.get(stored.value.workId, { fresh: true });
|
|
31
33
|
const released = yield* releaseClosedPreparation(state, stored, work);
|
|
32
34
|
if (released !== undefined) {
|
|
@@ -75,22 +77,7 @@ export function makeLaunch(state: EngineState) {
|
|
|
75
77
|
submittedAt: policy.now(),
|
|
76
78
|
};
|
|
77
79
|
const record = launchRecord(stored.value, launchRole, policy.now(), continuation?.responses);
|
|
78
|
-
yield*
|
|
79
|
-
stored,
|
|
80
|
-
{
|
|
81
|
-
...record,
|
|
82
|
-
admissionReady: true,
|
|
83
|
-
attempts: [...record.attempts, attempt],
|
|
84
|
-
blocker: undefined,
|
|
85
|
-
launchRetry: undefined,
|
|
86
|
-
mergeAreasReleased: undefined,
|
|
87
|
-
mergeReadyAt: undefined,
|
|
88
|
-
mergeReadyHead: undefined,
|
|
89
|
-
pendingAnswers: undefined,
|
|
90
|
-
stage: "executing",
|
|
91
|
-
},
|
|
92
|
-
{ quota, role: launchRole },
|
|
93
|
-
);
|
|
80
|
+
yield* saveLaunch(state, stored, record, attempt, { priority: work.priority, quota, role: launchRole });
|
|
94
81
|
const submitted =
|
|
95
82
|
sessionId === undefined
|
|
96
83
|
? sessions.start({ cwd: stored.value.cwd, operationId: attempt.operationId, prompt: workerPrompt, settings })
|
package/src/engine/makeState.ts
CHANGED
|
@@ -6,11 +6,18 @@ import { originalWork } from "#engine/originalWork.ts";
|
|
|
6
6
|
import { ReportInspection } from "#engine/ReportInspection.ts";
|
|
7
7
|
import { FleetRepository } from "#engine/repository.ts";
|
|
8
8
|
import type { Attempt, FleetRecord } from "#model.ts";
|
|
9
|
-
import { BoardGateway, type BoardWork, type Decision, FleetIntegrations, FleetPolicy } from "#policy.ts";
|
|
9
|
+
import { BoardGateway, type BoardWork, type Decision, type FleetConfiguration, FleetIntegrations, FleetPolicy } from "#policy.ts";
|
|
10
10
|
import { DEFAULT_AREA_MERGE_WAIT_MS } from "#scheduling/areas.ts";
|
|
11
11
|
import type { SessionReceipt } from "#session/schema.ts";
|
|
12
12
|
import { SessionService } from "#session/service.ts";
|
|
13
|
-
import type { Versioned } from "#storage/model.ts";
|
|
13
|
+
import type { AdmissionLimits, Versioned } from "#storage/model.ts";
|
|
14
|
+
export interface LaunchAdmission {
|
|
15
|
+
readonly ignoreAreas?: boolean;
|
|
16
|
+
readonly implementer?: boolean;
|
|
17
|
+
readonly overLimit?: boolean;
|
|
18
|
+
readonly quota: FleetConfiguration["quota"];
|
|
19
|
+
readonly role: Attempt["role"];
|
|
20
|
+
}
|
|
14
21
|
export const makeState = Effect.gen(function* () {
|
|
15
22
|
const store = yield* FleetRepository;
|
|
16
23
|
const board = yield* BoardGateway;
|
|
@@ -29,29 +36,13 @@ export const makeState = Effect.gen(function* () {
|
|
|
29
36
|
),
|
|
30
37
|
);
|
|
31
38
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
value:
|
|
35
|
-
admission
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
) {
|
|
40
|
-
return store.compareAndSet(
|
|
41
|
-
value.workId,
|
|
42
|
-
stored.version,
|
|
43
|
-
{ ...value, attentionOwner: waitingOwner(value) },
|
|
44
|
-
admission === undefined
|
|
45
|
-
? undefined
|
|
46
|
-
: {
|
|
47
|
-
scheduling: { areaMergeWaitMs: policy.areaMergeWaitMs ?? DEFAULT_AREA_MERGE_WAIT_MS, now: policy.now() },
|
|
48
|
-
...(admission.quota.available === undefined
|
|
49
|
-
? {}
|
|
50
|
-
: { quota: { available: admission.quota.available, observedAt: admission.quota.observedAt } }),
|
|
51
|
-
...(policy.executionConcurrency === undefined ? {} : { maxExecuting: policy.executionConcurrency }),
|
|
52
|
-
...(admission.role !== "worker" || policy.deliveryBacklog === undefined ? {} : { maxBacklog: policy.deliveryBacklog }),
|
|
53
|
-
},
|
|
54
|
-
);
|
|
39
|
+
const current = policy.current ?? Effect.succeed(policy);
|
|
40
|
+
function save(stored: Versioned<FleetRecord>, value: FleetRecord, admission?: LaunchAdmission) {
|
|
41
|
+
const record = { ...value, attentionOwner: waitingOwner(value) };
|
|
42
|
+
if (admission === undefined) {
|
|
43
|
+
return store.compareAndSet(value.workId, stored.version, record);
|
|
44
|
+
}
|
|
45
|
+
return Effect.flatMap(current, (applied) => store.compareAndSet(value.workId, stored.version, record, launchLimits(applied, admission)));
|
|
55
46
|
}
|
|
56
47
|
const decision = Effect.fn("Fleet.decision")(function* (
|
|
57
48
|
stored: Versioned<FleetRecord>,
|
|
@@ -84,6 +75,19 @@ export const makeState = Effect.gen(function* () {
|
|
|
84
75
|
const published = yield* board.decision(stored.value.workId, value, publicationWork ?? originalWork(stored.value));
|
|
85
76
|
return yield* save(updated, { ...updated.value, decision: { ...value, published }, decisionPublished: true });
|
|
86
77
|
});
|
|
87
|
-
return { board, decision, integrations, launching, launchScope, load, policy, reportInspection, save, sessions, store };
|
|
78
|
+
return { board, current, decision, integrations, launching, launchScope, load, policy, reportInspection, save, sessions, store };
|
|
88
79
|
});
|
|
89
80
|
export type EngineState = Effect.Success<typeof makeState>;
|
|
81
|
+
|
|
82
|
+
function launchLimits(policy: FleetConfiguration, admission: LaunchAdmission): AdmissionLimits {
|
|
83
|
+
const concurrency = admission.overLimit ? undefined : policy.executionConcurrency;
|
|
84
|
+
return {
|
|
85
|
+
...(admission.ignoreAreas ? {} : { scheduling: { areaMergeWaitMs: policy.areaMergeWaitMs ?? DEFAULT_AREA_MERGE_WAIT_MS, now: policy.now() } }),
|
|
86
|
+
...(admission.quota.available === undefined ? {} : { quota: { available: admission.quota.available, observedAt: admission.quota.observedAt } }),
|
|
87
|
+
...(concurrency === undefined ? {} : { maxExecuting: concurrency }),
|
|
88
|
+
...(admission.role !== "worker" || admission.overLimit || policy.deliveryBacklog === undefined ? {} : { maxBacklog: policy.deliveryBacklog }),
|
|
89
|
+
...(concurrency === undefined || !admission.implementer
|
|
90
|
+
? {}
|
|
91
|
+
: { implementers: { concurrency, ...(policy.openPullRequests === undefined ? {} : { openPullRequests: policy.openPullRequests }) } }),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
@@ -36,9 +36,10 @@ export const awaitHumanMerge = Effect.fn("Fleet.awaitHumanMerge")(function* (
|
|
|
36
36
|
);
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
-
export function expireMergeAreas({ save,
|
|
40
|
-
return
|
|
41
|
-
&& mergeWaitExpired(stored.value, policy.now(), policy.areaMergeWaitMs ?? DEFAULT_AREA_MERGE_WAIT_MS)
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
export function expireMergeAreas({ save, current }: EngineState, stored: Versioned<FleetRecord>) {
|
|
40
|
+
return Effect.flatMap(current, (policy) =>
|
|
41
|
+
stored.value.mergeAreasReleased !== true && mergeWaitExpired(stored.value, policy.now(), policy.areaMergeWaitMs ?? DEFAULT_AREA_MERGE_WAIT_MS)
|
|
42
|
+
? save(stored, { ...stored.value, mergeAreasReleased: true })
|
|
43
|
+
: Effect.succeed(stored),
|
|
44
|
+
);
|
|
44
45
|
}
|
|
@@ -13,7 +13,7 @@ import { readReviewerVerdict, reviewerPrompt } from "#prompt/reviewer.ts";
|
|
|
13
13
|
import type { Versioned } from "#storage/model.ts";
|
|
14
14
|
|
|
15
15
|
export function obtainReview(state: EngineState) {
|
|
16
|
-
const { store,
|
|
16
|
+
const { store, sessions, save, board } = state;
|
|
17
17
|
return Effect.fn("Fleet.obtainReview")(function* (
|
|
18
18
|
stored: Versioned<FleetRecord>,
|
|
19
19
|
work: BoardWork,
|
|
@@ -25,6 +25,7 @@ export function obtainReview(state: EngineState) {
|
|
|
25
25
|
readonly observationRetries?: number;
|
|
26
26
|
},
|
|
27
27
|
) {
|
|
28
|
+
const policy = yield* state.current;
|
|
28
29
|
if (stored.value.review?.head === result.head) {
|
|
29
30
|
return stored.value.review.receipt;
|
|
30
31
|
}
|
|
@@ -41,7 +41,7 @@ export function prepareCommand(state: EngineState) {
|
|
|
41
41
|
return yield* store.insert(current);
|
|
42
42
|
}
|
|
43
43
|
if (unusedPreparation(existing.value)) {
|
|
44
|
-
return yield* save(existing, { ...current, history: existing.value.history });
|
|
44
|
+
return yield* save(existing, { ...current, dispatchNow: existing.value.dispatchNow, history: existing.value.history });
|
|
45
45
|
}
|
|
46
46
|
if (refreshablePreparation(existing.value, work, input)) {
|
|
47
47
|
return yield* save(existing, {
|
|
@@ -35,7 +35,8 @@ export function readOrContinueReview(state: EngineState) {
|
|
|
35
35
|
|
|
36
36
|
function continueReview(state: EngineState) {
|
|
37
37
|
return Effect.fn("Fleet.continueReview")(function* (stored: Versioned<FleetRecord>, work: BoardWork, result: WorkResult, receipt: SessionReceipt) {
|
|
38
|
-
const {
|
|
38
|
+
const { store, board, save, sessions } = state;
|
|
39
|
+
const policy = yield* state.current;
|
|
39
40
|
const reviewerGuidance = yield* policyGuidance(policy, "reviewer");
|
|
40
41
|
const prompt = [
|
|
41
42
|
reviewerPrompt({
|
package/src/engine/readRetry.ts
CHANGED
|
@@ -39,6 +39,24 @@ function retryAttempts(record: FleetRecord, operationId: string | undefined, ret
|
|
|
39
39
|
);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
function rateLimitedUntil(kind: "integration" | "provider", error: unknown) {
|
|
43
|
+
return kind === "integration" ? failureContext(error).retryAt : undefined;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function providerReadClosed(kind: "integration" | "provider", attempt: Attempt | undefined) {
|
|
47
|
+
return kind === "provider" && (attempt === undefined || !["submitting", "accepted", "running"].includes(attempt.status));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// An integration that names its retry time, such as a GitHub rate limit, is pacing Fleet rather than failing, so the wait does not count toward escalation.
|
|
51
|
+
function waitForRateLimit(state: EngineState, current: Versioned<FleetRecord>, message: string, retryAt: number) {
|
|
52
|
+
return state.save(current, {
|
|
53
|
+
...current.value,
|
|
54
|
+
attentionOwner: "automation",
|
|
55
|
+
blocker: message,
|
|
56
|
+
integrationRetry: { error: message, failures: current.value.integrationRetry?.failures ?? 0, retryAt },
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
42
60
|
export const readRetry = Effect.fn("Fleet.readRetry")(function* (
|
|
43
61
|
state: EngineState,
|
|
44
62
|
current: Versioned<FleetRecord>,
|
|
@@ -56,13 +74,17 @@ export const readRetry = Effect.fn("Fleet.readRetry")(function* (
|
|
|
56
74
|
return current;
|
|
57
75
|
}
|
|
58
76
|
const attempt = current.value.attempts.at(-1);
|
|
59
|
-
if (kind
|
|
77
|
+
if (providerReadClosed(kind, attempt)) {
|
|
60
78
|
return undefined;
|
|
61
79
|
}
|
|
62
80
|
const previous = kind === "provider" ? attempt?.readRetry : current.value.integrationRetry;
|
|
63
81
|
if (retryPending(state, current.value)) {
|
|
64
82
|
return current;
|
|
65
83
|
}
|
|
84
|
+
const limitedUntil = rateLimitedUntil(kind, error);
|
|
85
|
+
if (limitedUntil !== undefined) {
|
|
86
|
+
return yield* waitForRateLimit(state, current, failureMessage(error), limitedUntil);
|
|
87
|
+
}
|
|
66
88
|
const failures = (previous?.failures ?? 0) + 1;
|
|
67
89
|
if (failures >= 5 && (yield* retryLostReview(state, current.value, error))) {
|
|
68
90
|
return yield* state.load(current.value.workId);
|
|
@@ -5,9 +5,10 @@ import type { Attempt, FleetRecord } from "#model.ts";
|
|
|
5
5
|
import { reportPrompt } from "#prompt/worker.ts";
|
|
6
6
|
import type { Versioned } from "#storage/model.ts";
|
|
7
7
|
|
|
8
|
-
export function reconcileAttempt({ sessions,
|
|
8
|
+
export function reconcileAttempt({ sessions, current, board }: EngineState) {
|
|
9
9
|
return Effect.fn("Fleet.reconcileAttempt")(function* (stored: Versioned<FleetRecord>, attempt: Attempt) {
|
|
10
10
|
const work = yield* board.get(stored.value.workId);
|
|
11
|
+
const policy = yield* current;
|
|
11
12
|
const authorized = briefApproved(work) && !briefChanged(stored.value, work);
|
|
12
13
|
const preparedPrompt = stored.value.deliverable === "report" ? reportPrompt(stored.value.prompt) : stored.value.prompt;
|
|
13
14
|
const prompt = attempt.prompt ?? (attempt.role === "worker" ? preparedPrompt : undefined);
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { Conflict } from "@shivaedev/platform/errors/taxonomy.ts";
|
|
3
|
+
import { ANSWER_RECORDED } from "#attention.ts";
|
|
4
|
+
import { failureMessage } from "#engine/failureMessage.ts";
|
|
5
|
+
import { makeHuman } from "#engine/makeHuman.ts";
|
|
6
|
+
import type { EngineState } from "#engine/makeState.ts";
|
|
7
|
+
import { readResolution } from "#engine/readResolution.ts";
|
|
8
|
+
import { cleanupSessions } from "#engine/sessionCleanup.ts";
|
|
9
|
+
|
|
10
|
+
export function recordResponseCommand(state: EngineState) {
|
|
11
|
+
return Effect.fn("Fleet.recordResponse")(function* (workId: string, decisionId: string, responseId: string) {
|
|
12
|
+
const stored = yield* state.load(workId);
|
|
13
|
+
const receipts = [...(stored.value.history ?? []).flatMap((cycle) => cycle.responses ?? []), ...(stored.value.responses ?? [])];
|
|
14
|
+
if (receipts.some((receipt) => receipt.decisionId === decisionId && receipt.responseId === responseId)) {
|
|
15
|
+
return stored;
|
|
16
|
+
}
|
|
17
|
+
if (stored.value.stage !== "needs-human" || stored.value.decision?.id !== decisionId) {
|
|
18
|
+
return yield* new Conflict({ message: "Decision changed" });
|
|
19
|
+
}
|
|
20
|
+
yield* readResolution(state.board, stored.value.decision, responseId);
|
|
21
|
+
const recorded = yield* state.save(stored, { ...stored.value, blocker: ANSWER_RECORDED });
|
|
22
|
+
yield* state.load(workId).pipe(
|
|
23
|
+
Effect.flatMap(makeHuman(state)),
|
|
24
|
+
Effect.flatMap(cleanupSessions(state)),
|
|
25
|
+
Effect.catch((error) => recordFailure(state, workId, error)),
|
|
26
|
+
Effect.catchCause(Effect.logError),
|
|
27
|
+
Effect.forkIn(state.launchScope),
|
|
28
|
+
);
|
|
29
|
+
return recorded;
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const recordFailure = Effect.fn("Fleet.recordFailure")(function* (state: EngineState, workId: string, error: unknown) {
|
|
34
|
+
const current = yield* state.load(workId);
|
|
35
|
+
return yield* current.value.blocker === ANSWER_RECORDED
|
|
36
|
+
? state.save(current, { ...current.value, blocker: failureMessage(error) })
|
|
37
|
+
: Effect.succeed(current);
|
|
38
|
+
});
|