@shivaedev/work-fleet 0.6.0 → 0.7.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 +17 -0
- package/README.md +6 -4
- package/dist/DecisionCode.d.ts +1 -1
- package/dist/DecisionCode.d.ts.map +1 -1
- package/dist/DecisionCode.js +1 -0
- package/dist/DecisionCode.js.map +1 -1
- package/dist/admit.d.ts +2 -2
- package/dist/board/acknowledgeDecision.d.ts.map +1 -1
- package/dist/board/acknowledgeDecision.js +7 -3
- package/dist/board/acknowledgeDecision.js.map +1 -1
- package/dist/board/briefRevision.d.ts +1 -1
- package/dist/board/briefRevision.d.ts.map +1 -1
- package/dist/board/briefRevision.js +1 -1
- package/dist/board/briefRevision.js.map +1 -1
- package/dist/board/closePublishedDecision.d.ts +22 -0
- package/dist/board/closePublishedDecision.d.ts.map +1 -0
- package/dist/board/closePublishedDecision.js +41 -0
- package/dist/board/closePublishedDecision.js.map +1 -0
- package/dist/board/decisionAnswer.d.ts +2 -2
- package/dist/board/decisionAnswer.d.ts.map +1 -1
- package/dist/board/decisionAnswer.js +8 -8
- package/dist/board/decisionAnswer.js.map +1 -1
- package/dist/board/decisionReading.js +2 -2
- package/dist/board/decisionReading.js.map +1 -1
- package/dist/board/documents.d.ts +1 -2
- package/dist/board/documents.d.ts.map +1 -1
- package/dist/board/documents.js +4 -4
- package/dist/board/documents.js.map +1 -1
- package/dist/board/fleetField.d.ts +1 -1
- package/dist/board/fleetField.d.ts.map +1 -1
- package/dist/board/markdown.d.ts.map +1 -1
- package/dist/board/markdown.js +6 -5
- package/dist/board/markdown.js.map +1 -1
- package/dist/board/publish.d.ts +1 -1
- package/dist/board/publish.d.ts.map +1 -1
- package/dist/board/publish.js +10 -8
- package/dist/board/publish.js.map +1 -1
- package/dist/board/publishReport.js +2 -2
- package/dist/board/publishReport.js.map +1 -1
- package/dist/board/readDocument.js +1 -1
- package/dist/board/readDocument.js.map +1 -1
- package/dist/board/readPass.d.ts +1 -1
- package/dist/board/readPass.d.ts.map +1 -1
- package/dist/board/readPass.js +1 -1
- package/dist/board/readPass.js.map +1 -1
- package/dist/board/reportIdentity.js +1 -1
- package/dist/board/reportIdentity.js.map +1 -1
- package/dist/board/reportLinks.js +1 -1
- package/dist/board/reportLinks.js.map +1 -1
- package/dist/board/schema.d.ts +13 -13
- package/dist/board/schema.js +2 -2
- package/dist/board/schema.js.map +1 -1
- package/dist/board/upgradeDecisionClosure.d.ts +5 -0
- package/dist/board/upgradeDecisionClosure.d.ts.map +1 -0
- package/dist/board/upgradeDecisionClosure.js +46 -0
- package/dist/board/upgradeDecisionClosure.js.map +1 -0
- package/dist/board/workRevision.js +2 -2
- package/dist/board/workRevision.js.map +1 -1
- package/dist/board/writeHealth.d.ts +1 -1
- package/dist/board/writeHealth.d.ts.map +1 -1
- package/dist/board/writeHealth.js +1 -1
- package/dist/board/writeHealth.js.map +1 -1
- package/dist/board/writePublished.d.ts +1 -1
- package/dist/board/writePublished.d.ts.map +1 -1
- package/dist/board/writePublished.js +5 -1
- package/dist/board/writePublished.js.map +1 -1
- package/dist/cli.js +11 -5
- package/dist/cli.js.map +1 -1
- package/dist/engine/abandonStalled.d.ts +530 -533
- package/dist/engine/abandonStalled.d.ts.map +1 -1
- package/dist/engine/admissionOrder.d.ts +4 -4
- package/dist/engine/applyResolution.d.ts +4 -4
- package/dist/engine/approveBrief.d.ts +6 -6
- package/dist/engine/authorizeResolution.d.ts +528 -531
- package/dist/engine/authorizeResolution.d.ts.map +1 -1
- package/dist/engine/authorizeResolution.js +1 -1
- package/dist/engine/authorizeResolution.js.map +1 -1
- package/dist/engine/boardBrief.d.ts +7 -6
- package/dist/engine/boardBrief.d.ts.map +1 -1
- package/dist/engine/boardBrief.js +3 -10
- package/dist/engine/boardBrief.js.map +1 -1
- package/dist/engine/capacityRetry.d.ts +1715 -1724
- package/dist/engine/capacityRetry.d.ts.map +1 -1
- package/dist/engine/closeDecisions.d.ts +4 -4
- package/dist/engine/completeBoardWork.d.ts +4 -4
- package/dist/engine/completeReport.d.ts +277 -280
- package/dist/engine/completeReport.d.ts.map +1 -1
- package/dist/engine/continueCommand.d.ts +2 -2
- package/dist/engine/continueWorker.d.ts +4 -4
- package/dist/engine/decisionCopy.d.ts +15 -0
- package/dist/engine/decisionCopy.d.ts.map +1 -0
- package/dist/engine/decisionCopy.js +44 -0
- package/dist/engine/decisionCopy.js.map +1 -0
- package/dist/engine/deliverPendingAnswers.d.ts +534 -537
- package/dist/engine/deliverPendingAnswers.d.ts.map +1 -1
- package/dist/engine/dispatchCommand.d.ts +2 -2
- package/dist/engine/dispatchCommand.d.ts.map +1 -1
- package/dist/engine/dispatchCommand.js +4 -27
- package/dist/engine/dispatchCommand.js.map +1 -1
- package/dist/engine/dispatchFailure.d.ts +9391 -0
- package/dist/engine/dispatchFailure.d.ts.map +1 -0
- package/dist/engine/dispatchFailure.js +24 -0
- package/dist/engine/dispatchFailure.js.map +1 -0
- package/dist/engine/ensureDecisionOwner.d.ts +4 -4
- package/dist/engine/ensurePublication.d.ts +4 -4
- package/dist/engine/failureCode.js +1 -1
- package/dist/engine/failureCode.js.map +1 -1
- package/dist/engine/health.d.ts +1 -1
- package/dist/engine/health.d.ts.map +1 -1
- package/dist/engine/inspectRenewal.d.ts +4 -4
- package/dist/engine/launchInput.d.ts +2 -2
- package/dist/engine/launchReceipt.d.ts +2 -2
- package/dist/engine/makeAdopt.d.ts +4 -4
- package/dist/engine/makeAdvance.d.ts +2 -2
- package/dist/engine/makeDeliver.d.ts +4 -4
- package/dist/engine/makeDeliver.d.ts.map +1 -1
- package/dist/engine/makeDeliver.js +5 -1
- package/dist/engine/makeDeliver.js.map +1 -1
- package/dist/engine/makeHuman.d.ts +4 -4
- package/dist/engine/makeLaunch.d.ts +4 -4
- package/dist/engine/makeObserve.d.ts +4 -4
- package/dist/engine/makeReview.d.ts +4 -4
- package/dist/engine/makeState.d.ts +533 -536
- package/dist/engine/makeState.d.ts.map +1 -1
- package/dist/engine/makeState.js +9 -2
- package/dist/engine/makeState.js.map +1 -1
- package/dist/engine/makeValidate.d.ts +4 -4
- package/dist/engine/mergeReadiness.d.ts +536 -539
- package/dist/engine/mergeReadiness.d.ts.map +1 -1
- package/dist/engine/mergeReadiness.js +1 -1
- package/dist/engine/mergeReadiness.js.map +1 -1
- package/dist/engine/missingBoardWork.d.ts +9936 -0
- package/dist/engine/missingBoardWork.d.ts.map +1 -0
- package/dist/engine/missingBoardWork.js +17 -0
- package/dist/engine/missingBoardWork.js.map +1 -0
- package/dist/engine/observeDeliveryFailure.d.ts +530 -533
- package/dist/engine/observeDeliveryFailure.d.ts.map +1 -1
- package/dist/engine/observeRenewal.d.ts +6 -6
- package/dist/engine/obtainReview.d.ts +2 -2
- package/dist/engine/operationRecord.d.ts +26 -26
- package/dist/engine/persistTerminalReceipts.d.ts +4 -4
- package/dist/engine/prepareCommand.d.ts +2 -2
- package/dist/engine/queueAnswerCommand.d.ts +2 -2
- package/dist/engine/readOrContinueReview.d.ts +2 -2
- package/dist/engine/readResolution.d.ts +1 -1
- package/dist/engine/readResolution.js +1 -1
- package/dist/engine/readResolution.js.map +1 -1
- package/dist/engine/readRetry.d.ts +1177 -1183
- package/dist/engine/readRetry.d.ts.map +1 -1
- package/dist/engine/reassignCommand.d.ts +2 -2
- package/dist/engine/reconcileAttempt.d.ts +2 -2
- package/dist/engine/reconcileCommand.d.ts +2 -2
- package/dist/engine/reconcileCommand.d.ts.map +1 -1
- package/dist/engine/reconcileCommand.js +2 -1
- package/dist/engine/reconcileCommand.js.map +1 -1
- package/dist/engine/recordResponseCommand.d.ts +2 -2
- package/dist/engine/recoverStall.d.ts +530 -533
- package/dist/engine/recoverStall.d.ts.map +1 -1
- package/dist/engine/recoverUnobservable.d.ts +530 -533
- package/dist/engine/recoverUnobservable.d.ts.map +1 -1
- package/dist/engine/refreshBrief.d.ts +1177 -1183
- package/dist/engine/refreshBrief.d.ts.map +1 -1
- package/dist/engine/refreshReviewResult.d.ts +4 -4
- package/dist/engine/releaseClosedPreparation.d.ts +530 -533
- package/dist/engine/releaseClosedPreparation.d.ts.map +1 -1
- package/dist/engine/releaseExecution.d.ts +530 -533
- package/dist/engine/releaseExecution.d.ts.map +1 -1
- package/dist/engine/releaseFinishedWork.d.ts +2 -2
- package/dist/engine/repository.d.ts +24 -24
- package/dist/engine/repository.js +1 -1
- package/dist/engine/repository.js.map +1 -1
- package/dist/engine/requestConflictRepair.d.ts +530 -533
- package/dist/engine/requestConflictRepair.d.ts.map +1 -1
- package/dist/engine/requestRework.d.ts +4 -4
- package/dist/engine/resolveCommand.d.ts +2 -2
- package/dist/engine/resolveExecution.d.ts +530 -533
- package/dist/engine/resolveExecution.d.ts.map +1 -1
- package/dist/engine/resumeAttempt.d.ts +530 -533
- package/dist/engine/resumeAttempt.d.ts.map +1 -1
- package/dist/engine/retireUnacknowledged.d.ts +4 -4
- package/dist/engine/retryTerminal.d.ts +528 -531
- package/dist/engine/retryTerminal.d.ts.map +1 -1
- package/dist/engine/saveLaunch.d.ts +532 -535
- package/dist/engine/saveLaunch.d.ts.map +1 -1
- package/dist/engine/saveLaunch.js +2 -1
- package/dist/engine/saveLaunch.js.map +1 -1
- package/dist/engine/scheduler.d.ts +4 -4
- package/dist/engine/scheduler.d.ts.map +1 -1
- package/dist/engine/scheduler.js +4 -1
- package/dist/engine/scheduler.js.map +1 -1
- package/dist/engine/sessionCleanup.d.ts +4 -4
- package/dist/engine/settleMergedDelivery.d.ts +530 -533
- package/dist/engine/settleMergedDelivery.d.ts.map +1 -1
- package/dist/engine/situations/choices.d.ts +20 -0
- package/dist/engine/situations/choices.d.ts.map +1 -0
- package/dist/engine/situations/choices.js +21 -0
- package/dist/engine/situations/choices.js.map +1 -0
- package/dist/engine/situations/service.d.ts +60 -0
- package/dist/engine/situations/service.d.ts.map +1 -0
- package/dist/engine/situations/service.js +51 -0
- package/dist/engine/situations/service.js.map +1 -0
- package/dist/engine/situations/stop.d.ts +25 -0
- package/dist/engine/situations/stop.d.ts.map +1 -0
- package/dist/engine/situations/stop.js +25 -0
- package/dist/engine/situations/stop.js.map +1 -0
- package/dist/engine/situations/work.d.ts +114 -0
- package/dist/engine/situations/work.d.ts.map +1 -0
- package/dist/engine/situations/work.js +91 -0
- package/dist/engine/situations/work.js.map +1 -0
- package/dist/engine/steerBrief.d.ts +532 -535
- package/dist/engine/steerBrief.d.ts.map +1 -1
- package/dist/engine/submissionFailure.d.ts +526 -529
- package/dist/engine/submissionFailure.d.ts.map +1 -1
- package/dist/engine/submitLaunch.d.ts +528 -531
- package/dist/engine/submitLaunch.d.ts.map +1 -1
- package/dist/engine/threadNames.js +1 -1
- package/dist/engine/threadNames.js.map +1 -1
- package/dist/engine/workerReport.d.ts +7 -7
- package/dist/engine/workerReport.d.ts.map +1 -1
- package/dist/exposeFailure.js +1 -1
- package/dist/exposeFailure.js.map +1 -1
- package/dist/fleet.d.ts +26 -26
- package/dist/fleet.js +1 -1
- package/dist/fleet.js.map +1 -1
- package/dist/host/actionCommands.d.ts +10 -10
- package/dist/host/actionCommands.d.ts.map +1 -1
- package/dist/host/actionCommands.js +6 -6
- package/dist/host/actionCommands.js.map +1 -1
- package/dist/host/admission.d.ts +4 -4
- package/dist/host/answerWork.d.ts +4 -3
- package/dist/host/answerWork.d.ts.map +1 -1
- package/dist/host/cliOptions.d.ts +5 -1
- package/dist/host/cliOptions.d.ts.map +1 -1
- package/dist/host/cliOptions.js +6 -4
- package/dist/host/cliOptions.js.map +1 -1
- package/dist/host/commands.d.ts +1 -1
- package/dist/host/commands.d.ts.map +1 -1
- package/dist/host/configSettings.d.ts +5 -5
- package/dist/host/daemon.d.ts +133 -132
- package/dist/host/daemon.d.ts.map +1 -1
- package/dist/host/daemon.js +7 -3
- package/dist/host/daemon.js.map +1 -1
- package/dist/host/daemonClient.d.ts +28 -28
- package/dist/host/daemonClient.js +1 -1
- package/dist/host/daemonClient.js.map +1 -1
- package/dist/host/daemonContract.d.ts +146 -146
- package/dist/host/daemonContract.d.ts.map +1 -1
- package/dist/host/daemonContract.js +1 -1
- package/dist/host/daemonContract.js.map +1 -1
- package/dist/host/daemonDiagnostics.js +1 -1
- package/dist/host/daemonDiagnostics.js.map +1 -1
- package/dist/host/daemonHandlers.d.ts +1 -1
- package/dist/host/daemonHandlers.d.ts.map +1 -1
- package/dist/host/daemonPort.d.ts +6 -0
- package/dist/host/daemonPort.d.ts.map +1 -0
- package/dist/host/daemonPort.js +40 -0
- package/dist/host/daemonPort.js.map +1 -0
- package/dist/host/daemonSnapshots.d.ts +1 -1
- package/dist/host/daemonSnapshots.d.ts.map +1 -1
- package/dist/host/daemonSnapshots.js +1 -1
- package/dist/host/daemonSnapshots.js.map +1 -1
- package/dist/host/fleetStatus.d.ts +5 -5
- package/dist/host/follow.d.ts +1 -0
- package/dist/host/follow.d.ts.map +1 -1
- package/dist/host/follow.js +10 -4
- package/dist/host/follow.js.map +1 -1
- package/dist/host/followCommands.d.ts +2 -2
- package/dist/host/followCommands.d.ts.map +1 -1
- package/dist/host/followCommands.js +4 -2
- package/dist/host/followCommands.js.map +1 -1
- package/dist/host/githubApi.js +1 -1
- package/dist/host/githubApi.js.map +1 -1
- package/dist/host/githubDelivery.js +3 -1
- package/dist/host/githubDelivery.js.map +1 -1
- package/dist/host/healthLayer.js +1 -1
- package/dist/host/healthLayer.js.map +1 -1
- package/dist/host/integrations.js +1 -1
- package/dist/host/integrations.js.map +1 -1
- package/dist/host/mainSource.js +1 -1
- package/dist/host/mainSource.js.map +1 -1
- package/dist/host/providerHealth.js +1 -1
- package/dist/host/providerHealth.js.map +1 -1
- package/dist/host/quota.js +1 -1
- package/dist/host/quota.js.map +1 -1
- package/dist/host/recordDecisionResponse.d.ts +3 -2
- package/dist/host/recordDecisionResponse.d.ts.map +1 -1
- package/dist/host/recordDecisionResponse.js +1 -1
- package/dist/host/recordDecisionResponse.js.map +1 -1
- package/dist/host/releaseWork.d.ts +6 -5
- package/dist/host/releaseWork.d.ts.map +1 -1
- package/dist/host/releaseWork.js +2 -2
- package/dist/host/releaseWork.js.map +1 -1
- package/dist/host/renderStatus.d.ts +4 -1
- package/dist/host/renderStatus.d.ts.map +1 -1
- package/dist/host/renderStatus.js +6 -6
- package/dist/host/renderStatus.js.map +1 -1
- package/dist/host/reportBoard.js +1 -1
- package/dist/host/reportBoard.js.map +1 -1
- package/dist/host/runtime.d.ts +2 -2
- package/dist/host/runtime.d.ts.map +1 -1
- package/dist/host/runtime.js +1 -1
- package/dist/host/runtime.js.map +1 -1
- package/dist/host/statusLayer.js +2 -2
- package/dist/host/statusLayer.js.map +1 -1
- package/dist/host/watch.d.ts.map +1 -1
- package/dist/host/watch.js +1 -1
- package/dist/host/watch.js.map +1 -1
- package/dist/model.d.ts +9 -9
- package/dist/model.js +1 -1
- package/dist/model.js.map +1 -1
- package/dist/operations.d.ts +57 -57
- package/dist/packageInfo.d.ts +1 -1
- package/dist/packageInfo.js +1 -1
- package/dist/policy.d.ts +3 -2
- package/dist/policy.d.ts.map +1 -1
- package/dist/policy.js +2 -1
- package/dist/policy.js.map +1 -1
- package/dist/prompt/briefEdit.js +1 -1
- package/dist/prompt/briefEdit.js.map +1 -1
- package/dist/providers/codexCloud.js +1 -1
- package/dist/providers/codexCloud.js.map +1 -1
- package/dist/providers/codexLocal.js +1 -1
- package/dist/providers/codexLocal.js.map +1 -1
- package/dist/qualifyDependencies.d.ts +2 -2
- package/dist/reportFileDirectory.js +1 -1
- package/dist/reportFileDirectory.js.map +1 -1
- package/dist/scheduling/admission.d.ts +6 -6
- package/dist/scheduling/areas.d.ts +6 -6
- package/dist/scheduling/backPressure.d.ts +6 -6
- package/dist/session/schema.d.ts +1 -1
- package/dist/session/service.js +1 -1
- package/dist/session/service.js.map +1 -1
- package/dist/storage/fleetMigrations.d.ts.map +1 -1
- package/dist/storage/fleetMigrations.js +5 -0
- package/dist/storage/fleetMigrations.js.map +1 -1
- package/dist/storage/makeFleetTransaction.d.ts +1 -1
- package/dist/storage/makeFleetTransaction.d.ts.map +1 -1
- package/dist/storage/makeFleetTransaction.js +1 -1
- package/dist/storage/makeFleetTransaction.js.map +1 -1
- package/dist/storage/makeForeignReservations.d.ts.map +1 -1
- package/dist/storage/makeForeignReservations.js +16 -4
- package/dist/storage/makeForeignReservations.js.map +1 -1
- package/package.json +8 -9
- package/src/DecisionCode.ts +1 -0
- package/src/board/acknowledgeDecision.ts +7 -3
- package/src/board/briefRevision.ts +2 -2
- package/src/board/closePublishedDecision.ts +51 -0
- package/src/board/decisionAnswer.ts +11 -9
- package/src/board/decisionReading.ts +3 -3
- package/src/board/documents.ts +5 -6
- package/src/board/fleetField.ts +1 -1
- package/src/board/markdown.ts +6 -5
- package/src/board/publish.ts +10 -8
- package/src/board/publishReport.ts +2 -2
- package/src/board/readDocument.ts +1 -1
- package/src/board/readPass.ts +2 -2
- package/src/board/reportIdentity.ts +1 -1
- package/src/board/reportLinks.ts +1 -1
- package/src/board/schema.ts +2 -2
- package/src/board/upgradeDecisionClosure.ts +61 -0
- package/src/board/workRevision.ts +2 -2
- package/src/board/writeHealth.ts +2 -2
- package/src/board/writePublished.ts +13 -4
- package/src/cli.ts +13 -5
- package/src/engine/authorizeResolution.ts +1 -1
- package/src/engine/boardBrief.ts +11 -19
- package/src/engine/decisionCopy.ts +63 -0
- package/src/engine/dispatchCommand.ts +4 -34
- package/src/engine/dispatchFailure.ts +25 -0
- package/src/engine/failureCode.ts +1 -1
- package/src/engine/health.ts +1 -1
- package/src/engine/makeDeliver.ts +5 -1
- package/src/engine/makeState.ts +14 -4
- package/src/engine/mergeReadiness.ts +0 -2
- package/src/engine/missingBoardWork.ts +24 -0
- package/src/engine/readResolution.ts +2 -2
- package/src/engine/reconcileCommand.ts +7 -1
- package/src/engine/repository.ts +1 -1
- package/src/engine/saveLaunch.ts +2 -0
- package/src/engine/scheduler.ts +4 -1
- package/src/engine/situations/choices.ts +36 -0
- package/src/engine/situations/service.ts +82 -0
- package/src/engine/situations/stop.ts +60 -0
- package/src/engine/situations/work.ts +94 -0
- package/src/engine/threadNames.ts +1 -1
- package/src/exposeFailure.ts +1 -1
- package/src/fleet.ts +1 -1
- package/src/host/actionCommands.ts +6 -6
- package/src/host/cliOptions.ts +10 -5
- package/src/host/daemon.ts +7 -3
- package/src/host/daemonClient.ts +1 -1
- package/src/host/daemonContract.ts +1 -1
- package/src/host/daemonDiagnostics.ts +1 -1
- package/src/host/daemonPort.ts +50 -0
- package/src/host/daemonSnapshots.ts +1 -1
- package/src/host/follow.ts +16 -5
- package/src/host/followCommands.ts +4 -2
- package/src/host/githubApi.ts +1 -1
- package/src/host/githubDelivery.ts +3 -1
- package/src/host/healthLayer.ts +1 -1
- package/src/host/integrations.ts +1 -1
- package/src/host/mainSource.ts +1 -1
- package/src/host/providerHealth.ts +1 -1
- package/src/host/quota.ts +1 -1
- package/src/host/recordDecisionResponse.ts +1 -1
- package/src/host/releaseWork.ts +2 -2
- package/src/host/renderStatus.ts +6 -7
- package/src/host/reportBoard.ts +1 -1
- package/src/host/runtime.ts +1 -1
- package/src/host/statusLayer.ts +3 -3
- package/src/host/watch.ts +4 -1
- package/src/model.ts +1 -1
- package/src/packageInfo.ts +1 -1
- package/src/policy.ts +2 -1
- package/src/prompt/briefEdit.ts +1 -1
- package/src/providers/codexCloud.ts +1 -1
- package/src/providers/codexLocal.ts +1 -1
- package/src/reportFileDirectory.ts +1 -1
- package/src/session/service.ts +1 -1
- package/src/storage/fleetMigrations.ts +5 -0
- package/src/storage/makeFleetTransaction.ts +2 -2
- package/src/storage/makeForeignReservations.ts +15 -4
- package/dist/engine/releaseOnly.d.ts +0 -3
- package/dist/engine/releaseOnly.d.ts.map +0 -1
- package/dist/engine/releaseOnly.js +0 -19
- package/dist/engine/releaseOnly.js.map +0 -1
- package/src/engine/releaseOnly.ts +0 -24
package/src/cli.ts
CHANGED
|
@@ -11,7 +11,7 @@ import * as Flag from "effect/cli/Flag";
|
|
|
11
11
|
import * as Effect from "effect/Effect";
|
|
12
12
|
import * as Option from "effect/Option";
|
|
13
13
|
import { answerCommand, continueCommand, nameThreadsCommand, reassignCommand, releaseCommand } from "#host/actionCommands.ts";
|
|
14
|
-
import { board, config, host, port } from "#host/cliOptions.ts";
|
|
14
|
+
import { board, clientPort, config, host, port } from "#host/cliOptions.ts";
|
|
15
15
|
import { waitCommand, watchCommand } from "#host/followCommands.ts";
|
|
16
16
|
import { VERSION } from "#packageInfo.ts";
|
|
17
17
|
|
|
@@ -20,7 +20,7 @@ const serveCommand = Command.make(
|
|
|
20
20
|
{ board: Argument.Directory("board-dir"), config, port },
|
|
21
21
|
Effect.fn("WorkFleetCli.serve")(function* (input) {
|
|
22
22
|
const { serveFleet } = yield* Effect.promise(() => import("#host/daemon.ts"));
|
|
23
|
-
yield* serveFleet(yield* host(input.board, input.config), undefined, input.port);
|
|
23
|
+
yield* serveFleet(yield* host(input.board, input.config), undefined, Option.getOrUndefined(input.port));
|
|
24
24
|
}),
|
|
25
25
|
).pipe(Command.withDescription("Serve the local Fleet HTTP RPC daemon and schedule approved Board work"));
|
|
26
26
|
|
|
@@ -40,7 +40,7 @@ const dispatchCommand = Command.make(
|
|
|
40
40
|
Effect.fn("WorkFleetCli.dispatch")(function* (input) {
|
|
41
41
|
const { daemonRequest } = yield* Effect.promise(() => import("#host/daemonClient.ts"));
|
|
42
42
|
const value = yield* daemonRequest(
|
|
43
|
-
input
|
|
43
|
+
yield* clientPort(input),
|
|
44
44
|
(client) => client("daemon.dispatch", { ignoreAreas: input.ignoreAreas, now: input.now, workId: input.workId }),
|
|
45
45
|
`dispatch ${input.workId}`,
|
|
46
46
|
);
|
|
@@ -62,12 +62,20 @@ const statusCommand = Command.make(
|
|
|
62
62
|
Promise.all([import("#host/daemonClient.ts"), import("#host/renderStatus.ts")]),
|
|
63
63
|
);
|
|
64
64
|
const workId = Option.getOrUndefined(input.workId);
|
|
65
|
+
const daemonPort = yield* clientPort(input);
|
|
65
66
|
const current = yield* daemonRequest(
|
|
66
|
-
|
|
67
|
+
daemonPort,
|
|
67
68
|
(client) => client("daemon.status", workId === undefined ? {} : { workId }),
|
|
68
69
|
workId === undefined ? "status" : `status ${workId}`,
|
|
69
70
|
);
|
|
70
|
-
yield* Console.log(
|
|
71
|
+
yield* Console.log(
|
|
72
|
+
input.json
|
|
73
|
+
? JSON.stringify(current)
|
|
74
|
+
: renderStatus(current, {
|
|
75
|
+
board: input.board,
|
|
76
|
+
...Option.match(input.port, { onNone: () => ({}), onSome: (value) => ({ port: value }) }),
|
|
77
|
+
}),
|
|
78
|
+
);
|
|
71
79
|
}),
|
|
72
80
|
).pipe(Command.withDescription("Show active and completed Fleet work, and waiting work grouped by owner"));
|
|
73
81
|
|
|
@@ -17,7 +17,7 @@ export const authorizeResolution = Effect.fn("Fleet.authorizeResolution")(functi
|
|
|
17
17
|
if (executing(record)) {
|
|
18
18
|
return yield* Effect.fail(new Forbidden({ message: "Confirm terminal execution before releasing ownership" }));
|
|
19
19
|
}
|
|
20
|
-
if (record.result?.kind === "change") {
|
|
20
|
+
if (record.result?.kind === "change" && record.decision?.code !== "pr-closed") {
|
|
21
21
|
yield* state.store.reserveForeign(record.result.pr, { backlog: true, executing: false });
|
|
22
22
|
}
|
|
23
23
|
});
|
package/src/engine/boardBrief.ts
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import { Conflict, Forbidden } from "@shivaedev/platform/errors/taxonomy.ts";
|
|
3
3
|
import { workRevision } from "#board/workRevision.ts";
|
|
4
|
-
import { closeDecisions } from "#engine/closeDecisions.ts";
|
|
5
4
|
import { withFailureContext } from "#engine/failureContext.ts";
|
|
6
5
|
import type { EngineState } from "#engine/makeState.ts";
|
|
7
6
|
import type { FleetRecord } from "#model.ts";
|
|
8
7
|
import type { BoardWork } from "#policy.ts";
|
|
9
8
|
import type { Versioned } from "#storage/model.ts";
|
|
10
9
|
|
|
11
|
-
const CHANGED_BRIEF_REASON = "Board context changed";
|
|
10
|
+
export const CHANGED_BRIEF_REASON = "Board context changed";
|
|
12
11
|
|
|
13
12
|
export function briefChanged(record: Pick<FleetRecord, "boardRevision" | "boardContext">, work: BoardWork): boolean {
|
|
14
13
|
return workRevision(record.boardRevision, record.boardContext) !== workRevision(work.revision, work.context);
|
|
@@ -33,7 +32,7 @@ export const authorizeBriefContext = Effect.fn("Fleet.authorizeBriefContext")(fu
|
|
|
33
32
|
) {
|
|
34
33
|
yield* authorizeBrief(work);
|
|
35
34
|
if (briefChanged(record, work)) {
|
|
36
|
-
return yield* withFailureContext(new Conflict({ message: CHANGED_BRIEF_REASON }), {
|
|
35
|
+
return yield* withFailureContext(new Conflict({ message: CHANGED_BRIEF_REASON }), { code: "fleet-stale" });
|
|
37
36
|
}
|
|
38
37
|
});
|
|
39
38
|
|
|
@@ -53,29 +52,22 @@ export function stopChangedBrief(state: EngineState) {
|
|
|
53
52
|
) {
|
|
54
53
|
return stored;
|
|
55
54
|
}
|
|
56
|
-
const published = stored.value.decision?.published;
|
|
57
55
|
const stopped = yield* state.save(stored, {
|
|
58
56
|
...stored.value,
|
|
59
57
|
checks: undefined,
|
|
60
58
|
mergeReadyAt: undefined,
|
|
61
59
|
mergeReadyHead: undefined,
|
|
62
60
|
review: undefined,
|
|
63
|
-
supersededDecisions:
|
|
64
|
-
published === undefined
|
|
65
|
-
? stored.value.supersededDecisions
|
|
66
|
-
: [...(stored.value.supersededDecisions ?? []), { published, supersededAt: state.policy.now() }],
|
|
67
61
|
});
|
|
68
|
-
return yield* state
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
)
|
|
78
|
-
.pipe(Effect.flatMap(closeDecisions(state)));
|
|
62
|
+
return yield* state.decision(
|
|
63
|
+
stopped,
|
|
64
|
+
"fleet-stale",
|
|
65
|
+
CHANGED_BRIEF_REASON,
|
|
66
|
+
"Dispatch to approve the current brief in place, retry this decision, or safely release this work",
|
|
67
|
+
undefined,
|
|
68
|
+
undefined,
|
|
69
|
+
work,
|
|
70
|
+
);
|
|
79
71
|
});
|
|
80
72
|
}
|
|
81
73
|
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { DecisionCode } from "#DecisionCode.ts";
|
|
2
|
+
import { CHANGED_BRIEF_REASON } from "#engine/boardBrief.ts";
|
|
3
|
+
import { blocked, type Choice, RELEASE, type Situation } from "#engine/situations/choices.ts";
|
|
4
|
+
import { serviceSituations } from "#engine/situations/service.ts";
|
|
5
|
+
import { stopSituations } from "#engine/situations/stop.ts";
|
|
6
|
+
import { workSituations } from "#engine/situations/work.ts";
|
|
7
|
+
import type { Decision } from "#policy.ts";
|
|
8
|
+
|
|
9
|
+
export interface DecisionCopy {
|
|
10
|
+
readonly question?: {
|
|
11
|
+
readonly title: string;
|
|
12
|
+
readonly retry?: Choice;
|
|
13
|
+
readonly release: Choice;
|
|
14
|
+
};
|
|
15
|
+
readonly reason: string;
|
|
16
|
+
readonly recommendation: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const situations: Readonly<Record<DecisionCode, Situation>> = { ...serviceSituations, ...stopSituations, ...workSituations };
|
|
20
|
+
|
|
21
|
+
const changedBrief: Situation = {
|
|
22
|
+
happened: "The task was edited on the Board while this work was waiting.",
|
|
23
|
+
question: "Continue with the edited task?",
|
|
24
|
+
recommendation: "Fleet needs to know whether the edited task still fits the work done so far. If it does, continue. Otherwise stop here.",
|
|
25
|
+
retry: {
|
|
26
|
+
label: "Continue on the updated task",
|
|
27
|
+
outcome: "Fleet accepts the edited task and continues the same work with it, on the same branch and PR.",
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const uncoded = blocked("Fleet stopped and needs your decision.", "Check the details, then let Fleet try again, or stop here.");
|
|
32
|
+
|
|
33
|
+
const WORKER =
|
|
34
|
+
"The worker needs your answer to keep going. Write it on this card. Fleet passes it to the same worker, which continues where it stopped.";
|
|
35
|
+
|
|
36
|
+
export function decisionCopy(decision: Pick<Decision, "code" | "publicationWork" | "reason" | "worker">): DecisionCopy {
|
|
37
|
+
if (decision.worker !== undefined) {
|
|
38
|
+
return { reason: decision.reason, recommendation: WORKER };
|
|
39
|
+
}
|
|
40
|
+
const situation = situationOf(decision);
|
|
41
|
+
const detailed = situation.details === true && decision.reason.trim() !== "" && decision.reason !== decision.code;
|
|
42
|
+
return {
|
|
43
|
+
question: {
|
|
44
|
+
release: situation.release ?? RELEASE,
|
|
45
|
+
title: situation.question ?? "What should Fleet do next?",
|
|
46
|
+
...(situation.retry === undefined ? {} : { retry: situation.retry }),
|
|
47
|
+
},
|
|
48
|
+
reason: detailed ? `${situation.happened}\n\nDetails: ${decision.reason}` : situation.happened,
|
|
49
|
+
recommendation: situation.recommendation,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function releaseOnly(code: DecisionCode | undefined) {
|
|
54
|
+
const situation = code === undefined ? undefined : situations[code];
|
|
55
|
+
return situation?.retry === undefined ? situation?.recommendation : undefined;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function situationOf(decision: Pick<Decision, "code" | "publicationWork" | "reason">) {
|
|
59
|
+
if (decision.code === "fleet-stale" && decision.reason === CHANGED_BRIEF_REASON && decision.publicationWork !== undefined) {
|
|
60
|
+
return changedBrief;
|
|
61
|
+
}
|
|
62
|
+
return decision.code === undefined ? uncoded : situations[decision.code];
|
|
63
|
+
}
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { Effect, Result } from "effect";
|
|
2
|
-
import { waitingOwner } from "#attention.ts";
|
|
3
2
|
import { approveDispatchedBrief } from "#engine/approveBrief.ts";
|
|
4
3
|
import { authorizeBriefContext } from "#engine/boardBrief.ts";
|
|
4
|
+
import { dispatchFailure } from "#engine/dispatchFailure.ts";
|
|
5
5
|
import { failureCode } from "#engine/failureCode.ts";
|
|
6
|
-
import { failureMessage } from "#engine/failureMessage.ts";
|
|
7
|
-
import { failureOwner } from "#engine/failureOwner.ts";
|
|
8
6
|
import type { makeLaunch } from "#engine/makeLaunch.ts";
|
|
9
7
|
import type { EngineState } from "#engine/makeState.ts";
|
|
10
|
-
import { clearIntegrationRetry,
|
|
8
|
+
import { clearIntegrationRetry, retryPending } from "#engine/readRetry.ts";
|
|
11
9
|
import { refreshBrief } from "#engine/refreshBrief.ts";
|
|
12
10
|
import { releaseClosedPreparation } from "#engine/releaseClosedPreparation.ts";
|
|
13
11
|
import type { DispatchNow, FleetRecord } from "#model.ts";
|
|
@@ -56,25 +54,7 @@ export function dispatchCommand(state: EngineState, launch: ReturnType<typeof ma
|
|
|
56
54
|
) {
|
|
57
55
|
stored = yield* save(stored, { ...stored.value, preparation: assessment.preparation });
|
|
58
56
|
}
|
|
59
|
-
return yield* launch(stored, "worker", stored.value.prompt)
|
|
60
|
-
Effect.catch((error) =>
|
|
61
|
-
Effect.gen(function* () {
|
|
62
|
-
const current = yield* load(workId);
|
|
63
|
-
if (current.value.stage !== "prepared") {
|
|
64
|
-
return current;
|
|
65
|
-
}
|
|
66
|
-
const waiting = {
|
|
67
|
-
...current.value,
|
|
68
|
-
attentionOwner: failureOwner(error),
|
|
69
|
-
blocker: failureMessage(error),
|
|
70
|
-
};
|
|
71
|
-
if (!sameWait(current.value, waiting)) {
|
|
72
|
-
yield* save(current, waiting);
|
|
73
|
-
}
|
|
74
|
-
return yield* Effect.fail(error);
|
|
75
|
-
}),
|
|
76
|
-
),
|
|
77
|
-
);
|
|
57
|
+
return yield* launch(stored, "worker", stored.value.prompt);
|
|
78
58
|
});
|
|
79
59
|
return Effect.fn("Fleet.dispatch")(function* (workId: string, prompt?: string, now?: DispatchNow) {
|
|
80
60
|
const current = yield* load(workId);
|
|
@@ -86,12 +66,7 @@ export function dispatchCommand(state: EngineState, launch: ReturnType<typeof ma
|
|
|
86
66
|
}
|
|
87
67
|
return yield* dispatchPrepared(workId, prompt, now).pipe(
|
|
88
68
|
Effect.flatMap((updated) => clearIntegrationRetry(state, updated)),
|
|
89
|
-
Effect.catch((error) =>
|
|
90
|
-
Effect.gen(function* () {
|
|
91
|
-
const retrying = yield* readRetry(state, yield* load(workId), error);
|
|
92
|
-
return retrying === undefined ? yield* Effect.fail(error) : retrying;
|
|
93
|
-
}),
|
|
94
|
-
),
|
|
69
|
+
Effect.catch((error) => dispatchFailure(state, workId, error)),
|
|
95
70
|
);
|
|
96
71
|
});
|
|
97
72
|
}
|
|
@@ -103,8 +78,3 @@ function requestedNow(record: FleetRecord, now: DispatchNow | undefined): FleetR
|
|
|
103
78
|
}
|
|
104
79
|
return { ...record, dispatchNow: now };
|
|
105
80
|
}
|
|
106
|
-
|
|
107
|
-
// Every scheduler pass retries waiting work, so rewriting an unchanged wait would make each pass write and notify once per waiter.
|
|
108
|
-
function sameWait(current: FleetRecord, waiting: FleetRecord) {
|
|
109
|
-
return current.blocker === waiting.blocker && current.attentionOwner === waitingOwner(waiting);
|
|
110
|
-
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { waitingOwner } from "#attention.ts";
|
|
3
|
+
import { failureMessage } from "#engine/failureMessage.ts";
|
|
4
|
+
import { failureOwner } from "#engine/failureOwner.ts";
|
|
5
|
+
import type { EngineState } from "#engine/makeState.ts";
|
|
6
|
+
import { releaseMissingBoardWork } from "#engine/missingBoardWork.ts";
|
|
7
|
+
import { readRetry } from "#engine/readRetry.ts";
|
|
8
|
+
|
|
9
|
+
export const dispatchFailure = Effect.fn("Fleet.dispatchFailure")(function* <E>(state: EngineState, workId: string, error: E) {
|
|
10
|
+
const current = yield* state.load(workId);
|
|
11
|
+
const released = yield* releaseMissingBoardWork(state, current, error);
|
|
12
|
+
if (released !== undefined) {
|
|
13
|
+
return released;
|
|
14
|
+
}
|
|
15
|
+
const retrying = yield* readRetry(state, current, error);
|
|
16
|
+
if (retrying !== undefined) {
|
|
17
|
+
return retrying;
|
|
18
|
+
}
|
|
19
|
+
const waiting = { ...current.value, attentionOwner: failureOwner(error), blocker: failureMessage(error) };
|
|
20
|
+
// Unchanged waits must not write and wake every subscriber on every scheduler pass.
|
|
21
|
+
if (current.value.stage === "prepared" && (current.value.blocker !== waiting.blocker || current.value.attentionOwner !== waitingOwner(waiting))) {
|
|
22
|
+
yield* state.save(current, waiting);
|
|
23
|
+
}
|
|
24
|
+
return yield* Effect.fail(error);
|
|
25
|
+
});
|
|
@@ -24,7 +24,7 @@ export function failureCode(error: unknown): DecisionCode {
|
|
|
24
24
|
return error.code ?? `session-${error.reason}`;
|
|
25
25
|
}
|
|
26
26
|
if (error instanceof BoardFailure) {
|
|
27
|
-
return error.code ?? "board-failure";
|
|
27
|
+
return error.code === "board-item-missing" ? "board-failure" : (error.code ?? "board-failure");
|
|
28
28
|
}
|
|
29
29
|
return "integration-failure";
|
|
30
30
|
}
|
package/src/engine/health.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Clock, Context, Effect, Ref } from "effect";
|
|
2
|
-
import type { CapacityRejection, FleetHealth, SourceFailure } from "@shivaedev/work-board/integration/diagnostics.ts";
|
|
2
|
+
import type { CapacityRejection, FleetHealth, SourceFailure } from "@shivaedev/work-board/server/integration/diagnostics.ts";
|
|
3
3
|
import type { SessionObservation } from "#session/schema.ts";
|
|
4
4
|
|
|
5
5
|
export interface HealthState {
|
|
@@ -2,6 +2,7 @@ import { Effect, Result } from "effect";
|
|
|
2
2
|
import { validateChecks, validateReview } from "#completion.ts";
|
|
3
3
|
import { authorizeBriefContext } from "#engine/boardBrief.ts";
|
|
4
4
|
import { failureCode } from "#engine/failureCode.ts";
|
|
5
|
+
import { failureOwner } from "#engine/failureOwner.ts";
|
|
5
6
|
import type { EngineState } from "#engine/makeState.ts";
|
|
6
7
|
import { awaitHumanMerge, expireMergeAreas } from "#engine/mergeReadiness.ts";
|
|
7
8
|
import { observeDeliveryFailure } from "#engine/observeDeliveryFailure.ts";
|
|
@@ -54,7 +55,7 @@ function deniedDelivery(state: EngineState, stored: Versioned<FleetRecord>, work
|
|
|
54
55
|
error.message,
|
|
55
56
|
"Restore approval for work that is still needed, or release it",
|
|
56
57
|
undefined,
|
|
57
|
-
|
|
58
|
+
failureOwner(error),
|
|
58
59
|
)
|
|
59
60
|
: state.save(stored, { ...stored.value, blocker: error.message, mergeReadyAt: undefined, mergeReadyHead: undefined }),
|
|
60
61
|
),
|
|
@@ -72,6 +73,9 @@ const observeDelivery = Effect.fn("Fleet.observeDelivery")(function* (
|
|
|
72
73
|
) {
|
|
73
74
|
const record = stored.value;
|
|
74
75
|
const observed = yield* state.integrations.delivery(result).pipe(Effect.result);
|
|
76
|
+
if (Result.isFailure(observed) && failureCode(observed.failure) === "pr-closed") {
|
|
77
|
+
yield* state.store.releaseForeign(result.pr);
|
|
78
|
+
}
|
|
75
79
|
if (Result.isSuccess(observed) && observed.success !== undefined && !executing(record)) {
|
|
76
80
|
return yield* settleMergedDelivery(state, stored, result, observed.success, deliveryPending(record));
|
|
77
81
|
}
|
package/src/engine/makeState.ts
CHANGED
|
@@ -2,11 +2,12 @@ import { Effect } from "effect";
|
|
|
2
2
|
import { NotFound } from "@shivaedev/platform/errors/taxonomy.ts";
|
|
3
3
|
import { type AttentionOwner, waitingOwner } from "#attention.ts";
|
|
4
4
|
import type { DecisionCode } from "#DecisionCode.ts";
|
|
5
|
+
import { closeDecisions } from "#engine/closeDecisions.ts";
|
|
5
6
|
import { originalWork } from "#engine/originalWork.ts";
|
|
6
7
|
import { ReportInspection } from "#engine/ReportInspection.ts";
|
|
7
8
|
import { FleetRepository } from "#engine/repository.ts";
|
|
8
9
|
import type { Attempt, FleetRecord } from "#model.ts";
|
|
9
|
-
import { BoardGateway, type BoardWork, type Decision, type FleetConfiguration, FleetIntegrations, FleetPolicy } from "#policy.ts";
|
|
10
|
+
import { type BoardFailure, BoardGateway, type BoardWork, type Decision, type FleetConfiguration, FleetIntegrations, FleetPolicy } from "#policy.ts";
|
|
10
11
|
import { DEFAULT_AREA_MERGE_WAIT_MS } from "#scheduling/areas.ts";
|
|
11
12
|
import type { SessionReceipt } from "#session/schema.ts";
|
|
12
13
|
import { SessionService } from "#session/service.ts";
|
|
@@ -53,7 +54,7 @@ export const makeState = Effect.gen(function* () {
|
|
|
53
54
|
worker?: SessionReceipt,
|
|
54
55
|
attentionOwner: AttentionOwner = "orchestrator",
|
|
55
56
|
publicationWork?: BoardWork,
|
|
56
|
-
) {
|
|
57
|
+
): Effect.fn.Return<Versioned<FleetRecord>, Effect.Error<ReturnType<typeof save>> | BoardFailure> {
|
|
57
58
|
const value: Decision = {
|
|
58
59
|
attentionOwner,
|
|
59
60
|
code,
|
|
@@ -64,6 +65,8 @@ export const makeState = Effect.gen(function* () {
|
|
|
64
65
|
recommendation,
|
|
65
66
|
...(worker === undefined ? {} : { worker }),
|
|
66
67
|
};
|
|
68
|
+
const previous = stored.value.decision?.published;
|
|
69
|
+
const superseded = stored.value.supersededDecisions ?? [];
|
|
67
70
|
const updated = yield* save(stored, {
|
|
68
71
|
...stored.value,
|
|
69
72
|
attentionOwner,
|
|
@@ -72,11 +75,18 @@ export const makeState = Effect.gen(function* () {
|
|
|
72
75
|
decisionPublished: false,
|
|
73
76
|
launchRetry: undefined,
|
|
74
77
|
stage: "needs-human",
|
|
78
|
+
supersededDecisions:
|
|
79
|
+
previous === undefined || superseded.some((receipt) => receipt.published.questionId === previous.questionId)
|
|
80
|
+
? stored.value.supersededDecisions
|
|
81
|
+
: [...superseded, { published: previous, supersededAt: policy.now() }],
|
|
75
82
|
});
|
|
76
83
|
const published = yield* board.decision(stored.value.workId, value, publicationWork ?? originalWork(stored.value));
|
|
77
|
-
return yield* save(updated, { ...updated.value, decision: { ...value, published }, decisionPublished: true })
|
|
84
|
+
return yield* save(updated, { ...updated.value, decision: { ...value, published }, decisionPublished: true }).pipe(
|
|
85
|
+
Effect.flatMap(closeDecisions(state)),
|
|
86
|
+
);
|
|
78
87
|
});
|
|
79
|
-
|
|
88
|
+
const state = { board, current, decision, integrations, launching, launchScope, load, policy, reportInspection, save, sessions, store };
|
|
89
|
+
return state;
|
|
80
90
|
});
|
|
81
91
|
export type EngineState = Effect.Success<typeof makeState>;
|
|
82
92
|
|
|
@@ -31,8 +31,6 @@ export const awaitHumanMerge = Effect.fn("Fleet.awaitHumanMerge")(function* (
|
|
|
31
31
|
"reviewed-pr-ready",
|
|
32
32
|
"Reviewed PR is ready to merge",
|
|
33
33
|
"Merge the reviewed, green PR, or choose retry with an overall response to request changes on the same branch and PR",
|
|
34
|
-
undefined,
|
|
35
|
-
"maintainer",
|
|
36
34
|
);
|
|
37
35
|
});
|
|
38
36
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import type { EngineState } from "#engine/makeState.ts";
|
|
3
|
+
import { releaseFinishedWork } from "#engine/releaseFinishedWork.ts";
|
|
4
|
+
import { executing, type FleetRecord } from "#model.ts";
|
|
5
|
+
import { BoardFailure } from "#policy.ts";
|
|
6
|
+
import type { Versioned } from "#storage/model.ts";
|
|
7
|
+
|
|
8
|
+
export function missingBoardItem(error: unknown, workId?: string): boolean {
|
|
9
|
+
return error instanceof BoardFailure && error.code === "board-item-missing" && (workId === undefined || error.workId === workId);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const releaseMissingBoardWork = Effect.fn("Fleet.releaseMissingBoardWork")(function* (
|
|
13
|
+
state: EngineState,
|
|
14
|
+
stored: Versioned<FleetRecord>,
|
|
15
|
+
error: unknown,
|
|
16
|
+
) {
|
|
17
|
+
const record = stored.value;
|
|
18
|
+
if (!missingBoardItem(error, record.workId) || ["completed", "released"].includes(record.stage) || executing(record)) {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
const released = yield* releaseFinishedWork(state, stored, `Board item no longer exists: ${record.workId}`);
|
|
22
|
+
yield* Effect.logInfo("Fleet released missing Board item").pipe(Effect.annotateLogs({ workId: record.workId }));
|
|
23
|
+
return released;
|
|
24
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import { BadRequest, Conflict } from "@shivaedev/platform/errors/taxonomy.ts";
|
|
3
|
-
import type { RecordedResponse } from "@shivaedev/work-board/integration/responses.ts";
|
|
4
|
-
import { releaseOnly } from "#engine/
|
|
3
|
+
import type { RecordedResponse } from "@shivaedev/work-board/server/integration/responses.ts";
|
|
4
|
+
import { releaseOnly } from "#engine/decisionCopy.ts";
|
|
5
5
|
import type { BoardGateway, Decision } from "#policy.ts";
|
|
6
6
|
|
|
7
7
|
export const readResolution = Effect.fn("Fleet.readResolution")(function* (
|
|
@@ -6,6 +6,7 @@ import { failureMessage } from "#engine/failureMessage.ts";
|
|
|
6
6
|
import { failureOwner } from "#engine/failureOwner.ts";
|
|
7
7
|
import type { makeAdvance } from "#engine/makeAdvance.ts";
|
|
8
8
|
import type { EngineState } from "#engine/makeState.ts";
|
|
9
|
+
import { releaseMissingBoardWork } from "#engine/missingBoardWork.ts";
|
|
9
10
|
import { persistTerminalReceipts } from "#engine/persistTerminalReceipts.ts";
|
|
10
11
|
import { clearIntegrationRetry, readRetry, retryPending } from "#engine/readRetry.ts";
|
|
11
12
|
import { refreshBrief } from "#engine/refreshBrief.ts";
|
|
@@ -67,7 +68,12 @@ export function reconcileCommand(state: EngineState, advance: ReturnType<typeof
|
|
|
67
68
|
}
|
|
68
69
|
return yield* advance(workId).pipe(
|
|
69
70
|
Effect.flatMap((updated) => clearIntegrationRetry(state, updated)),
|
|
70
|
-
Effect.catch((error) =>
|
|
71
|
+
Effect.catch((error) =>
|
|
72
|
+
load(workId).pipe(
|
|
73
|
+
Effect.flatMap((stored) => releaseMissingBoardWork(state, stored, error)),
|
|
74
|
+
Effect.flatMap((released) => (released === undefined ? handleFailure(workId, error) : Effect.succeed(released))),
|
|
75
|
+
),
|
|
76
|
+
),
|
|
71
77
|
Effect.flatMap(completeBoardWork(state)),
|
|
72
78
|
);
|
|
73
79
|
});
|
package/src/engine/repository.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Context, Effect, Layer } from "effect";
|
|
2
2
|
import { SqlClient } from "effect/sql";
|
|
3
|
-
import { defineService } from "@shivaedev/effect-service/
|
|
3
|
+
import { defineService } from "@shivaedev/effect-service/defineService.ts";
|
|
4
4
|
import { operationRecord } from "#engine/operationRecord.ts";
|
|
5
5
|
import { threadName } from "#engine/threadNames.ts";
|
|
6
6
|
import { type Attempt, allAttempts, backlog, executing, FleetRecord } from "#model.ts";
|
package/src/engine/saveLaunch.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import type { EngineState, LaunchAdmission } from "#engine/makeState.ts";
|
|
3
|
+
import { missingBoardItem } from "#engine/missingBoardWork.ts";
|
|
3
4
|
import type { Attempt, FleetRecord } from "#model.ts";
|
|
4
5
|
import type { BoardWork } from "#policy.ts";
|
|
5
6
|
import { qualifyDependencies } from "#qualifyDependencies.ts";
|
|
@@ -63,6 +64,7 @@ const areaWaiters = Effect.fn("Fleet.areaWaiters")(function* (state: EngineState
|
|
|
63
64
|
Effect.catchTag("Forbidden", () => Effect.succeed(false)),
|
|
64
65
|
),
|
|
65
66
|
),
|
|
67
|
+
Effect.catchTag("BoardFailure", (error) => (missingBoardItem(error) ? Effect.succeed(false) : Effect.fail(error))),
|
|
66
68
|
),
|
|
67
69
|
).pipe(Effect.map((entries) => entries.map((entry) => entry.workId)));
|
|
68
70
|
});
|
package/src/engine/scheduler.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Effect, Result } from "effect";
|
|
1
|
+
import { Cause, Effect, Result } from "effect";
|
|
2
2
|
import { inBoardReadPass, withBoardReadPass } from "#board/readPass.ts";
|
|
3
3
|
import { boardCompletionAction } from "#engine/completeBoardWork.ts";
|
|
4
4
|
import { schedulerPassed } from "#engine/health.ts";
|
|
@@ -15,6 +15,9 @@ const dispatchRecords = Effect.fn("Fleet.dispatchRecords")(function* (records: r
|
|
|
15
15
|
for (const { value } of prepared) {
|
|
16
16
|
const result = yield* fleet.dispatch(value.workId).pipe(Effect.result);
|
|
17
17
|
dispatched.push(result);
|
|
18
|
+
if (Result.isFailure(result)) {
|
|
19
|
+
yield* Effect.logWarning("Fleet dispatch failed", Cause.fail(result.failure)).pipe(Effect.annotateLogs({ workId: value.workId }));
|
|
20
|
+
}
|
|
18
21
|
if ((Result.isSuccess(result) && result.success.value.launchRetry !== undefined) || (yield* fleet.hasLaunchRetry())) {
|
|
19
22
|
break;
|
|
20
23
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface Choice {
|
|
2
|
+
readonly label: string;
|
|
3
|
+
readonly outcome: string;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface Situation {
|
|
7
|
+
readonly details?: boolean;
|
|
8
|
+
readonly happened: string;
|
|
9
|
+
readonly question?: string;
|
|
10
|
+
readonly recommendation: string;
|
|
11
|
+
readonly release?: Choice;
|
|
12
|
+
readonly retry?: Choice;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const RELEASE: Choice = {
|
|
16
|
+
label: "Stop and hand back",
|
|
17
|
+
outcome: "Fleet stops working on this task and hands it back to you. An open PR stays open.",
|
|
18
|
+
};
|
|
19
|
+
export const TRY_AGAIN: Choice = { label: "Try again", outcome: "Fleet repeats the step that stopped and continues the same work." };
|
|
20
|
+
export const RUN_AGAIN: Choice = { label: "Run the step again", outcome: "Fleet starts the step again and continues the same work." };
|
|
21
|
+
export const FRESH_WORKER: Choice = {
|
|
22
|
+
label: "Start a fresh worker",
|
|
23
|
+
outcome: "Fleet starts a new worker session with the same task. An existing branch and PR stay in use.",
|
|
24
|
+
};
|
|
25
|
+
export const CORRECT_REPORT: Choice = {
|
|
26
|
+
label: "Ask for a corrected report",
|
|
27
|
+
outcome: "Fleet asks the same worker to send its final report again in the expected format.",
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export function blocked(happened: string, recommendation: string): Situation {
|
|
31
|
+
return { details: true, happened, recommendation, retry: TRY_AGAIN };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function stopOnly(happened: string, recommendation: string): Situation {
|
|
35
|
+
return { happened, recommendation };
|
|
36
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { DecisionCode } from "#DecisionCode.ts";
|
|
2
|
+
import { blocked, FRESH_WORKER, RUN_AGAIN, type Situation, TRY_AGAIN } from "#engine/situations/choices.ts";
|
|
3
|
+
|
|
4
|
+
export const serviceSituations = {
|
|
5
|
+
"board-failure": blocked(
|
|
6
|
+
"Fleet could not read or update the Board.",
|
|
7
|
+
"Fleet needs the Board files readable again. Fix the cause in the details, then let Fleet try again.",
|
|
8
|
+
),
|
|
9
|
+
"fleet-denied": blocked(
|
|
10
|
+
"Fleet is not allowed to take the next step.",
|
|
11
|
+
"Fleet needs the blocker in the details resolved. Then let Fleet try again, or stop here.",
|
|
12
|
+
),
|
|
13
|
+
"fleet-integration": blocked(
|
|
14
|
+
"A service Fleet depends on is unavailable or not set up.",
|
|
15
|
+
"Fleet needs that service working. Fix it, then let Fleet try again, or stop here.",
|
|
16
|
+
),
|
|
17
|
+
"fleet-invalid": blocked("Fleet received data it cannot use.", "Fix the problem in the details, then let Fleet try again, or stop here."),
|
|
18
|
+
"fleet-missing": blocked(
|
|
19
|
+
"Fleet could not find something this work needs.",
|
|
20
|
+
"Restore what the details name, then let Fleet try again, or stop here.",
|
|
21
|
+
),
|
|
22
|
+
"fleet-stale": blocked(
|
|
23
|
+
"Something changed while Fleet was working on this task.",
|
|
24
|
+
"Fleet recommends trying again from the current state. Stop here if the task should not go on.",
|
|
25
|
+
),
|
|
26
|
+
"integration-failure": blocked(
|
|
27
|
+
"Fleet hit an unexpected error.",
|
|
28
|
+
"Check the details. If the cause is fixed, let Fleet try again. Otherwise stop here.",
|
|
29
|
+
),
|
|
30
|
+
"provider-quota-unavailable": {
|
|
31
|
+
happened: "The worker service has no usage quota left for Fleet.",
|
|
32
|
+
recommendation: "Fleet needs fresh quota to start workers. Try again once quota is available.",
|
|
33
|
+
retry: { label: "Try again", outcome: "Fleet checks the quota again and starts the work once quota is available." },
|
|
34
|
+
},
|
|
35
|
+
"session-active-turn": {
|
|
36
|
+
happened: "The worker was still busy with an earlier step, so Fleet could not send the next one.",
|
|
37
|
+
recommendation: "Fleet recommends trying again once the worker is free.",
|
|
38
|
+
retry: { label: "Try again", outcome: "Fleet sends the step to the same worker again." },
|
|
39
|
+
},
|
|
40
|
+
"session-active-turn-exhausted": {
|
|
41
|
+
happened: "The worker stayed busy with an earlier step through several attempts.",
|
|
42
|
+
recommendation: "Fleet recommends starting over with a fresh worker.",
|
|
43
|
+
retry: FRESH_WORKER,
|
|
44
|
+
},
|
|
45
|
+
"session-ambiguous": {
|
|
46
|
+
details: true,
|
|
47
|
+
happened: "Fleet lost contact with the worker service and cannot tell whether the last step started.",
|
|
48
|
+
recommendation: "Fleet recommends trying again once the worker service is reachable. Fleet checks what already ran before it sends anything.",
|
|
49
|
+
retry: { label: "Try again", outcome: "Fleet checks what the worker already did and continues from there." },
|
|
50
|
+
},
|
|
51
|
+
"session-persistence": blocked(
|
|
52
|
+
"Fleet could not save the state of the worker's run.",
|
|
53
|
+
"Fleet needs its database working. Fix the cause in the details, then let Fleet try again.",
|
|
54
|
+
),
|
|
55
|
+
"session-protocol": blocked(
|
|
56
|
+
"The worker service sent an answer Fleet does not understand.",
|
|
57
|
+
"Check the details. Let Fleet try again once the cause is fixed, or stop here.",
|
|
58
|
+
),
|
|
59
|
+
"session-queue-full": {
|
|
60
|
+
happened: "The worker service is too busy to accept new work.",
|
|
61
|
+
recommendation: "Fleet recommends trying again later.",
|
|
62
|
+
retry: TRY_AGAIN,
|
|
63
|
+
},
|
|
64
|
+
"session-rejected": blocked(
|
|
65
|
+
"The worker service rejected Fleet's request.",
|
|
66
|
+
"Check the details. Let Fleet try again once the cause is fixed, or stop here.",
|
|
67
|
+
),
|
|
68
|
+
"session-stalled": {
|
|
69
|
+
happened: "The worker stopped making progress, and nudging and interrupting it did not help.",
|
|
70
|
+
recommendation: "Fleet recommends starting over with a fresh worker.",
|
|
71
|
+
retry: FRESH_WORKER,
|
|
72
|
+
},
|
|
73
|
+
"session-turn-missing": {
|
|
74
|
+
happened: "The worker's run can no longer be found, even after Fleet resumed it once.",
|
|
75
|
+
recommendation: "Fleet recommends running the step again.",
|
|
76
|
+
retry: RUN_AGAIN,
|
|
77
|
+
},
|
|
78
|
+
"session-unavailable": blocked(
|
|
79
|
+
"Fleet could not reach the worker service.",
|
|
80
|
+
"Fleet needs the worker service reachable. Let Fleet try again once it is back, or stop here.",
|
|
81
|
+
),
|
|
82
|
+
} satisfies Partial<Record<DecisionCode, Situation>>;
|