firedrill-run 2.2.5 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +176 -22
- package/bin/firedrill.mjs +29 -5
- package/dist/assembly.json +13 -0
- package/dist/cli/runtime/candidate_copy.py +395 -0
- package/dist/cli/runtime/source_snapshot.py +391 -0
- package/dist/cli/src/administration.js +295 -0
- package/dist/cli/src/agent-changes.js +496 -0
- package/dist/cli/src/assessment-requests.js +67 -0
- package/dist/cli/src/auth.js +506 -0
- package/dist/cli/src/billing-commerce-contracts.js +1 -0
- package/dist/cli/src/billing-usage.js +227 -0
- package/dist/cli/src/billing-wallet-contracts.js +1 -0
- package/dist/cli/src/billing.js +170 -0
- package/dist/cli/src/bootstrap-process-lock.js +136 -0
- package/dist/cli/src/browser-links.js +14 -0
- package/dist/cli/src/campaign-controls.js +122 -0
- package/dist/cli/src/campaign-diagnoses.js +118 -0
- package/dist/cli/src/campaign-reports.js +1215 -0
- package/dist/cli/src/campaign-world.js +156 -0
- package/dist/cli/src/candidate-copy.js +376 -0
- package/dist/cli/src/catalog-contracts.js +1 -0
- package/dist/cli/src/ci-access-contracts.js +1 -0
- package/dist/cli/src/ci-configuration-contracts.js +1 -0
- package/dist/cli/src/ci-coverage.js +64 -0
- package/dist/cli/src/ci-delivery-contracts.js +1 -0
- package/dist/cli/src/ci-result-contracts.js +1 -0
- package/dist/cli/src/ci-run-contracts.js +1 -0
- package/dist/cli/src/ci-setup-proposals.js +52 -0
- package/dist/cli/src/company-policies.js +229 -0
- package/dist/cli/src/completion.js +79 -0
- package/dist/cli/src/configuration-intents.js +277 -0
- package/dist/cli/src/configuration.js +369 -0
- package/dist/cli/src/continuous-simulation.js +277 -0
- package/dist/cli/src/coordinated-checkpoints.js +133 -0
- package/dist/cli/src/credential-mode.js +139 -0
- package/dist/cli/src/credentials.js +331 -0
- package/dist/cli/src/credit-format.js +8 -0
- package/dist/cli/src/dataset-contracts.js +1 -0
- package/dist/cli/src/dataset-export.js +154 -0
- package/dist/cli/src/dataset-reads.js +37 -0
- package/dist/cli/src/dependency-preparation.js +239 -0
- package/dist/cli/src/director-tool-setup.js +104 -0
- package/dist/cli/src/driver-review.js +225 -0
- package/dist/cli/src/evaluation-authoring.js +315 -0
- package/dist/cli/src/evidence-bundles.js +367 -0
- package/dist/cli/src/execution-proposals.js +36 -0
- package/dist/cli/src/http.js +302 -0
- package/dist/cli/src/local-container-boundary.js +38 -0
- package/dist/cli/src/local-container-policy.js +201 -0
- package/dist/cli/src/local-execution-setup.js +81 -0
- package/dist/cli/src/local-source-basis.js +73 -0
- package/dist/cli/src/local-source.js +66 -0
- package/dist/cli/src/local-value-store.js +91 -0
- package/dist/cli/src/local-values.js +163 -0
- package/dist/cli/src/login-organizations.js +70 -0
- package/dist/cli/src/main.js +1627 -0
- package/dist/cli/src/mcp-connection.js +109 -0
- package/dist/cli/src/native/bindings.js +137 -0
- package/dist/cli/src/native/canonical.js +370 -0
- package/dist/cli/src/native/cloud-resources.js +942 -0
- package/dist/cli/src/native/companion-channel.js +421 -0
- package/dist/cli/src/native/companion-ipc.js +473 -0
- package/dist/cli/src/native/contracts.js +218 -0
- package/dist/cli/src/native/control-plane.js +1354 -0
- package/dist/cli/src/native/credit-approval.js +15 -0
- package/dist/cli/src/native/dependency-proxy.js +1006 -0
- package/dist/cli/src/native/drill-cleanup.js +115 -0
- package/dist/cli/src/native/drill-runner.js +1562 -0
- package/dist/cli/src/native/drivers/action-trace.js +210 -0
- package/dist/cli/src/native/drivers/function-wrapper.js +152 -0
- package/dist/cli/src/native/drivers/http.js +442 -0
- package/dist/cli/src/native/drivers/index.js +47 -0
- package/dist/cli/src/native/drivers/jsonl-process.js +538 -0
- package/dist/cli/src/native/drivers/playwright.js +600 -0
- package/dist/cli/src/native/drivers/signed-event.js +244 -0
- package/dist/cli/src/native/drivers/types.js +578 -0
- package/dist/cli/src/native/evidence-filter.js +255 -0
- package/dist/cli/src/native/isolated-access.js +241 -0
- package/dist/cli/src/native/library-sharing.js +220 -0
- package/dist/cli/src/native/local-run.js +667 -0
- package/dist/cli/src/native/local-secrets.js +19 -0
- package/dist/cli/src/native/mcp-config.js +123 -0
- package/dist/cli/src/native/metadata-requests.js +120 -0
- package/dist/cli/src/native/observations.js +1159 -0
- package/dist/cli/src/native/owned-groups.js +46 -0
- package/dist/cli/src/native/plan.js +594 -0
- package/dist/cli/src/native/png.js +159 -0
- package/dist/cli/src/native/ports.js +43 -0
- package/dist/cli/src/native/readiness.js +139 -0
- package/dist/cli/src/native/reassessments.js +206 -0
- package/dist/cli/src/native/redaction.js +235 -0
- package/dist/cli/src/native/registration.js +155 -0
- package/dist/cli/src/native/roots.js +110 -0
- package/dist/cli/src/native/run-cleanup.js +199 -0
- package/dist/cli/src/native/scratch.js +117 -0
- package/dist/cli/src/native/screenshots.js +60 -0
- package/dist/cli/src/native/session.js +556 -0
- package/dist/cli/src/native/standalone-proxy.js +580 -0
- package/dist/cli/src/native/standalone-renewals.js +183 -0
- package/dist/cli/src/native/standalone-state.js +193 -0
- package/dist/cli/src/native/standalone-tools.js +187 -0
- package/dist/cli/src/native/supervisor.js +831 -0
- package/dist/cli/src/native/target-auth.js +161 -0
- package/dist/cli/src/native/target-state.js +330 -0
- package/dist/cli/src/native/tool-reuse.js +364 -0
- package/dist/cli/src/native/tool-setups.js +336 -0
- package/dist/cli/src/native/world-reuse.js +288 -0
- package/dist/cli/src/onboarding.js +23 -0
- package/dist/cli/src/priority-requests.js +70 -0
- package/dist/cli/src/priority.js +223 -0
- package/dist/cli/src/prompts.js +184 -0
- package/dist/cli/src/real-operations.js +221 -0
- package/dist/cli/src/recipe-intents.js +58 -0
- package/dist/cli/src/recorded-context-intents.js +59 -0
- package/dist/cli/src/recorded-context.js +248 -0
- package/dist/cli/src/recordings.js +69 -0
- package/dist/cli/src/registration-guide.js +39 -0
- package/dist/cli/src/report-exports.js +213 -0
- package/dist/cli/src/request-input.js +47 -0
- package/dist/cli/src/resource-lifecycle.js +141 -0
- package/dist/cli/src/revision-requests.js +55 -0
- package/dist/cli/src/runner-abandon.js +53 -0
- package/dist/cli/src/runner-campaign-controls.js +262 -0
- package/dist/cli/src/runner-claim-reads.js +36 -0
- package/dist/cli/src/runner-completion.js +65 -0
- package/dist/cli/src/runner-configuration.js +546 -0
- package/dist/cli/src/runner-container.js +794 -0
- package/dist/cli/src/runner-evidence-erasure.js +351 -0
- package/dist/cli/src/runner-evidence-privacy.js +37 -0
- package/dist/cli/src/runner-evidence-retention.js +161 -0
- package/dist/cli/src/runner-evidence.js +326 -0
- package/dist/cli/src/runner-execute.js +92 -0
- package/dist/cli/src/runner-execution-deadline.js +25 -0
- package/dist/cli/src/runner-grants.js +307 -0
- package/dist/cli/src/runner-identity.js +615 -0
- package/dist/cli/src/runner-inputs.js +308 -0
- package/dist/cli/src/runner-jobs.js +49 -0
- package/dist/cli/src/runner-model-transport.js +392 -0
- package/dist/cli/src/runner-ownership.js +332 -0
- package/dist/cli/src/runner-process-lock.js +175 -0
- package/dist/cli/src/runner-runtime.js +396 -0
- package/dist/cli/src/runner-session-channel.js +377 -0
- package/dist/cli/src/runner-trial-completion.js +34 -0
- package/dist/cli/src/runner-trial-journal.js +358 -0
- package/dist/cli/src/runner-trial-live.js +393 -0
- package/dist/cli/src/runner-trial-protocol.js +289 -0
- package/dist/cli/src/runner-trial-sync.js +110 -0
- package/dist/cli/src/runner-trial-transfer.js +107 -0
- package/dist/cli/src/runner-voice.js +40 -0
- package/dist/cli/src/runner-world-claim.js +21 -0
- package/dist/cli/src/runner-world-collector.js +159 -0
- package/dist/cli/src/runner-world-command-evidence.js +487 -0
- package/dist/cli/src/runner-world-commands.js +268 -0
- package/dist/cli/src/runner-world-completion.js +76 -0
- package/dist/cli/src/runner-world-erasure.js +95 -0
- package/dist/cli/src/runner-world-evidence-sync.js +91 -0
- package/dist/cli/src/runner-world-journal.js +510 -0
- package/dist/cli/src/runner-world-native-filters.js +134 -0
- package/dist/cli/src/runner-world-observations.js +50 -0
- package/dist/cli/src/runner-world-session-protocol.js +134 -0
- package/dist/cli/src/saved-records.js +40 -0
- package/dist/cli/src/scenario-authoring.js +212 -0
- package/dist/cli/src/scenario-discovery.js +216 -0
- package/dist/cli/src/scenario-paths.js +68 -0
- package/dist/cli/src/scenario-requests.js +4 -0
- package/dist/cli/src/service-receipts.js +105 -0
- package/dist/cli/src/simple/authoring.js +270 -0
- package/dist/cli/src/simple/credit-approval.js +16 -0
- package/dist/cli/src/simple/help.js +98 -0
- package/dist/cli/src/simple/init.js +96 -0
- package/dist/cli/src/simple/library-sharing.js +414 -0
- package/dist/cli/src/simple/metadata-requests.js +46 -0
- package/dist/cli/src/simple/native-report.js +841 -0
- package/dist/cli/src/simple/native-tools.js +780 -0
- package/dist/cli/src/simple/plan-apply.js +506 -0
- package/dist/cli/src/simple/reassessment.js +323 -0
- package/dist/cli/src/simple/register.js +123 -0
- package/dist/cli/src/simple/run.js +122 -0
- package/dist/cli/src/simple/status.js +49 -0
- package/dist/cli/src/simple/tool-renewal.js +308 -0
- package/dist/cli/src/simple/tool-reuse.js +526 -0
- package/dist/cli/src/simple/tool-start-catalog.js +100 -0
- package/dist/cli/src/simple/tool-state.js +426 -0
- package/dist/cli/src/simple/tools-author.js +222 -0
- package/dist/cli/src/simple/watch.js +28 -0
- package/dist/cli/src/simple/world-reuse.js +586 -0
- package/dist/cli/src/simulation-intents.js +406 -0
- package/dist/cli/src/simulation-run.js +1058 -0
- package/dist/cli/src/source-batch.js +322 -0
- package/dist/cli/src/source-connection.js +451 -0
- package/dist/cli/src/source-runtime.js +346 -0
- package/dist/cli/src/source-selection-intents.js +75 -0
- package/dist/cli/src/source-sets.js +214 -0
- package/dist/cli/src/target-models.js +109 -0
- package/dist/cli/src/tool-catalog.js +224 -0
- package/dist/cli/src/tool-command-contracts.js +1 -0
- package/dist/cli/src/tool-command-export.js +245 -0
- package/dist/cli/src/tool-connection-contracts.js +1 -0
- package/dist/cli/src/tool-connection-reads.js +23 -0
- package/dist/cli/src/tool-contributions.js +58 -0
- package/dist/cli/src/tool-data.js +116 -0
- package/dist/cli/src/tool-datasets.js +176 -0
- package/dist/cli/src/tool-group-contracts.js +1 -0
- package/dist/cli/src/tool-group-reads.js +26 -0
- package/dist/cli/src/tool-group-state.js +147 -0
- package/dist/cli/src/tool-groups.js +311 -0
- package/dist/cli/src/tool-instances.js +186 -0
- package/dist/cli/src/tool-lifecycle-contracts.js +1 -0
- package/dist/cli/src/tool-lifecycle-reads.js +30 -0
- package/dist/cli/src/tool-lifecycle.js +323 -0
- package/dist/cli/src/tool-package-contracts.js +1 -0
- package/dist/cli/src/tool-package-reads.js +41 -0
- package/dist/cli/src/tool-records.js +53 -0
- package/dist/cli/src/tool-runtime.js +96 -0
- package/dist/cli/src/tool-state-contracts.js +1 -0
- package/dist/cli/src/tool-state-reads.js +31 -0
- package/dist/cli/src/tools.js +306 -0
- package/dist/cli/src/trial-actions.js +93 -0
- package/dist/cli/src/trial-checkpoints.js +133 -0
- package/dist/cli/src/trial-checks.js +70 -0
- package/dist/cli/src/trial-state.js +197 -0
- package/dist/cli/src/vault.js +266 -0
- package/dist/cli/src/workspace-registration.js +383 -0
- package/dist/cli/src/workspace-team-contracts.js +1 -0
- package/dist/cli/src/world-access.js +231 -0
- package/dist/cli/src/world-agent.js +4 -0
- package/dist/cli/src/world-checkpoint-scopes.js +15 -0
- package/dist/cli/src/world-contracts.js +6 -0
- package/dist/cli/src/world-creation.js +201 -0
- package/dist/cli/src/world-datasets.js +207 -0
- package/dist/cli/src/world-inspection.js +257 -0
- package/dist/cli/src/world-recipes.js +103 -0
- package/dist/cli/src/world-requests.js +241 -0
- package/dist/cli/src/world-session-checkpoints.js +196 -0
- package/dist/cli/src/world-session-lifecycle.js +207 -0
- package/dist/cli/src/world-session-requests.js +215 -0
- package/dist/cli/src/world-session-state.js +145 -0
- package/dist/cli/src/world-session-voice.js +66 -0
- package/dist/cli/src/world-sessions.js +288 -0
- package/dist/cli/src/world-stream.js +99 -0
- package/dist/cli/src/world-time-report.js +58 -0
- package/dist/contracts/agent-change-contracts.js +75 -0
- package/dist/contracts/agent-execution-contracts.js +38 -0
- package/dist/contracts/application-state-contracts.js +26 -0
- package/dist/contracts/assessment-aggregate-contracts.js +15 -0
- package/dist/contracts/assessment-contracts.js +74 -0
- package/dist/contracts/billing-commerce-contracts.js +107 -0
- package/dist/contracts/billing-wallet-contracts.js +43 -0
- package/dist/contracts/campaign-lifecycle.js +1 -0
- package/dist/contracts/campaign-world-contracts.js +80 -0
- package/dist/contracts/catalog-contracts.js +73 -0
- package/dist/contracts/ci-access-contracts.js +68 -0
- package/dist/contracts/ci-configuration-contracts.js +88 -0
- package/dist/contracts/ci-coverage-contracts.js +65 -0
- package/dist/contracts/ci-coverage-labels.js +25 -0
- package/dist/contracts/ci-delivery-contracts.js +61 -0
- package/dist/contracts/ci-result-contracts.js +103 -0
- package/dist/contracts/ci-run-contracts.js +51 -0
- package/dist/contracts/ci-setup-contracts.js +88 -0
- package/dist/contracts/clip-contracts.js +32 -0
- package/dist/contracts/comparison-contracts.js +53 -0
- package/dist/contracts/composite-contracts.js +34 -0
- package/dist/contracts/context-contracts.js +76 -0
- package/dist/contracts/continuation-report-contracts.js +1 -0
- package/dist/contracts/continuity-requirements.js +8 -0
- package/dist/contracts/coordinated-checkpoint-contracts.js +34 -0
- package/dist/contracts/dataset-contracts.js +88 -0
- package/dist/contracts/dependency-decision-contracts.js +36 -0
- package/dist/contracts/dependency-protocol-contracts.js +43 -0
- package/dist/contracts/director-execution.js +51 -0
- package/dist/contracts/driver-review-contracts.js +99 -0
- package/dist/contracts/evidence-contracts.js +65 -0
- package/dist/contracts/evidence-coverage-contracts.js +10 -0
- package/dist/contracts/export-contracts.js +44 -0
- package/dist/contracts/github-directory-contracts.js +96 -0
- package/dist/contracts/insight-contracts.js +11 -0
- package/dist/contracts/inspection-contracts.js +1 -0
- package/dist/contracts/local-claim-contracts.js +39 -0
- package/dist/contracts/local-configuration-contracts.js +7 -0
- package/dist/contracts/local-evidence-contracts.js +32 -0
- package/dist/contracts/local-grant-contracts.js +83 -0
- package/dist/contracts/local-input-contracts.js +19 -0
- package/dist/contracts/local-runner-contracts.js +42 -0
- package/dist/contracts/local-trial-live-contracts.js +16 -0
- package/dist/contracts/local-value-source-contracts.js +92 -0
- package/dist/contracts/local-world-native-contracts.js +8 -0
- package/dist/contracts/mcp-contracts.js +42 -0
- package/dist/contracts/media-contracts.js +28 -0
- package/dist/contracts/native-check-contracts.js +31 -0
- package/dist/contracts/native-identity-contracts.js +52 -0
- package/dist/contracts/onboarding-contracts.js +32 -0
- package/dist/contracts/performance-contracts.js +85 -0
- package/dist/contracts/planning-contracts.js +81 -0
- package/dist/contracts/real-operation-contracts.js +30 -0
- package/dist/contracts/recommendation-contracts.js +54 -0
- package/dist/contracts/report-contracts.js +1 -0
- package/dist/contracts/resource-lifecycle-contracts.js +57 -0
- package/dist/contracts/revision-contracts.js +12 -0
- package/dist/contracts/revision-request-contracts.js +39 -0
- package/dist/contracts/saved-record-contracts.js +76 -0
- package/dist/contracts/scenario-draft-comparison.js +91 -0
- package/dist/contracts/scenario-world-contracts.js +14 -0
- package/dist/contracts/service-contracts.js +1 -0
- package/dist/contracts/session-command-contracts.js +56 -0
- package/dist/contracts/session-contracts.js +65 -0
- package/dist/contracts/session-state-contracts.js +67 -0
- package/dist/contracts/session-voice-contracts.js +45 -0
- package/dist/contracts/source-set-contracts.js +26 -0
- package/dist/contracts/source-upload-contracts.js +22 -0
- package/dist/contracts/tool-command-contracts.js +57 -0
- package/dist/contracts/tool-connection-contracts.js +87 -0
- package/dist/contracts/tool-contribution-contracts.js +35 -0
- package/dist/contracts/tool-group-contracts.js +53 -0
- package/dist/contracts/tool-group-state-contracts.js +63 -0
- package/dist/contracts/tool-lifecycle-contracts.js +94 -0
- package/dist/contracts/tool-package-contracts.js +91 -0
- package/dist/contracts/tool-protocol-contracts.js +71 -0
- package/dist/contracts/tool-runtime-billing-contracts.js +28 -0
- package/dist/contracts/tool-setup-proposal.js +59 -0
- package/dist/contracts/tool-state-contracts.js +79 -0
- package/dist/contracts/trial-state-contracts.js +30 -0
- package/dist/contracts/typescript/agent-change.js +1 -0
- package/dist/contracts/typescript/assessment-aggregate.js +1 -0
- package/dist/contracts/typescript/assessment.js +1 -0
- package/dist/contracts/typescript/billing-commerce.js +1 -0
- package/dist/contracts/typescript/campaigns.js +1 -0
- package/dist/contracts/typescript/catalog.js +1 -0
- package/dist/contracts/typescript/ci-access.js +1 -0
- package/dist/contracts/typescript/ci-configuration.js +1 -0
- package/dist/contracts/typescript/ci-delivery.js +1 -0
- package/dist/contracts/typescript/ci-result.js +1 -0
- package/dist/contracts/typescript/ci-runs.js +1 -0
- package/dist/contracts/typescript/clips.js +1 -0
- package/dist/contracts/typescript/comparison.js +1 -0
- package/dist/contracts/typescript/composite.js +1 -0
- package/dist/contracts/typescript/connections.js +1 -0
- package/dist/contracts/typescript/context.js +1 -0
- package/dist/contracts/typescript/datasets.js +1 -0
- package/dist/contracts/typescript/evidence-coverage.js +1 -0
- package/dist/contracts/typescript/export.js +1 -0
- package/dist/contracts/typescript/github-directory.js +1 -0
- package/dist/contracts/typescript/insight.js +1 -0
- package/dist/contracts/typescript/inspection.js +1 -0
- package/dist/contracts/typescript/intake.js +1 -0
- package/dist/contracts/typescript/local-claim.js +1 -0
- package/dist/contracts/typescript/local-configuration.js +1 -0
- package/dist/contracts/typescript/local-evidence.js +1 -0
- package/dist/contracts/typescript/local-grant.js +1 -0
- package/dist/contracts/typescript/local-input.js +1 -0
- package/dist/contracts/typescript/local-runner.js +1 -0
- package/dist/contracts/typescript/local-trial-live.js +1 -0
- package/dist/contracts/typescript/local-value-source.js +1 -0
- package/dist/contracts/typescript/local-world-native.js +1 -0
- package/dist/contracts/typescript/mcp.js +1 -0
- package/dist/contracts/typescript/media.js +1 -0
- package/dist/contracts/typescript/native-check.js +1 -0
- package/dist/contracts/typescript/native-identity.js +1 -0
- package/dist/contracts/typescript/onboarding.js +1 -0
- package/dist/contracts/typescript/performance.js +1 -0
- package/dist/contracts/typescript/planning.js +1 -0
- package/dist/contracts/typescript/preparation.js +1 -0
- package/dist/contracts/typescript/real-operation.js +1 -0
- package/dist/contracts/typescript/recommendation.js +1 -0
- package/dist/contracts/typescript/reports.js +1 -0
- package/dist/contracts/typescript/resource-lifecycle.js +1 -0
- package/dist/contracts/typescript/saved-record.js +1 -0
- package/dist/contracts/typescript/scenarios.js +1 -0
- package/dist/contracts/typescript/services.js +1 -0
- package/dist/contracts/typescript/session-command.js +1 -0
- package/dist/contracts/typescript/session-state.js +1 -0
- package/dist/contracts/typescript/session-voice.js +1 -0
- package/dist/contracts/typescript/session.js +1 -0
- package/dist/contracts/typescript/tool-command.js +1 -0
- package/dist/contracts/typescript/tool-connection.js +1 -0
- package/dist/contracts/typescript/tool-contribution.js +1 -0
- package/dist/contracts/typescript/tool-groups.js +1 -0
- package/dist/contracts/typescript/tool-lifecycle.js +1 -0
- package/dist/contracts/typescript/tool-package.js +1 -0
- package/dist/contracts/typescript/tool-state.js +1 -0
- package/dist/contracts/typescript/trial-state.js +1 -0
- package/dist/contracts/typescript/vault.js +1 -0
- package/dist/contracts/typescript/workspace-team.js +1 -0
- package/dist/contracts/typescript/world-stream.js +1 -0
- package/dist/contracts/workspace-team-contracts.js +55 -0
- package/dist/contracts/world-command.js +65 -0
- package/dist/contracts/world-lifetime-contracts.js +74 -0
- package/dist/contracts/world-recipe-contracts.js +27 -0
- package/dist/contracts/world-stream-contracts.js +27 -0
- package/dist/package.json +1 -0
- package/package.json +16 -16
- package/LICENSE.md +0 -23
- package/PACKAGING.json +0 -50
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
// `firedrill tools session <session-id> renew ...`: extend a running tool
|
|
2
|
+
// session's shared-pool tools on the same live batch, with the same tools and
|
|
3
|
+
// data and nothing restarted. Root reviews the extension under a request key
|
|
4
|
+
// printed before anything is sent and quotes it at once; nothing is reserved or
|
|
5
|
+
// extended until the human approves that exact estimate. A rerun with the
|
|
6
|
+
// printed key continues the original review, never a second one, and a lost
|
|
7
|
+
// approval is read back, never charged twice. An unused review is closed
|
|
8
|
+
// explicitly, and a review request whose answer was lost is read back by its
|
|
9
|
+
// key or withdrawn. Nothing here renews automatically: it is never a heartbeat.
|
|
10
|
+
// Isolated tools keep their own lifetime, and drill-owned tools never extend a
|
|
11
|
+
// campaign's deadline.
|
|
12
|
+
import { randomUUID } from 'node:crypto';
|
|
13
|
+
import { approveCredits } from './credit-approval.js';
|
|
14
|
+
import { CliError } from '../http.js';
|
|
15
|
+
import { selectOne, terminalText } from '../prompts.js';
|
|
16
|
+
import { errorCode, isTransient, retryTransient } from '../native/control-plane.js';
|
|
17
|
+
import { applyRenewal, cancelRenewal, getRenewal, listRenewals, recoverRenewal, renewalId, reviewRenewal, withdrawRenewal, RENEWAL_MAX_SECONDS, RENEWAL_MIN_SECONDS, } from '../native/standalone-renewals.js';
|
|
18
|
+
import { STANDALONE_ACTIVE } from '../native/standalone-tools.js';
|
|
19
|
+
import { amount } from './plan-apply.js';
|
|
20
|
+
/** The verbs this module owns under `tools session <session-id>`. */
|
|
21
|
+
export const RENEWAL_VERBS = new Set(['renew', 'renewals', 'renewal', 'cancel-renewal', 'renewal-request', 'withdraw-renewal']);
|
|
22
|
+
/** An estimate this close to expiry is not approved: approval would race it. */
|
|
23
|
+
const QUOTE_MARGIN_MS = 60_000;
|
|
24
|
+
const RECOVER_MS = 15_000;
|
|
25
|
+
// Closed public transport/authority/billing categories only. Never copy an
|
|
26
|
+
// arbitrary server/provider code, message, response body or exception cause.
|
|
27
|
+
const RENEWAL_DIAGNOSTIC_CODES = new Set([
|
|
28
|
+
'request_failed', 'connection_uncertain', 'response_unavailable', 'native_disconnected', 'native_response_unconfirmed',
|
|
29
|
+
'native_authorization_refresh_pending', 'agent_authorization_refresh_pending',
|
|
30
|
+
'identity_service_unavailable', 'identity_refresh_capacity', 'identity_refresh_configuration_required',
|
|
31
|
+
'billing_credit_policy_unavailable', 'billing_credit_unit_definition_required', 'billing_seat_policy_unavailable',
|
|
32
|
+
]);
|
|
33
|
+
function renewalDiagnostic(emit, phase, error, recovery) {
|
|
34
|
+
const original = error instanceof CliError ? error : null;
|
|
35
|
+
const code = original && RENEWAL_DIAGNOSTIC_CODES.has(original.code) ? original.code : 'unknown';
|
|
36
|
+
const httpStatus = original?.httpStatus;
|
|
37
|
+
const http_status = typeof httpStatus === 'number' && Number.isInteger(httpStatus)
|
|
38
|
+
&& httpStatus >= 100 && httpStatus <= 599 ? httpStatus : null;
|
|
39
|
+
const candidate = original?.requestId;
|
|
40
|
+
const request_id = typeof candidate === 'string' && (/^[a-f0-9]{32}$/.test(candidate)
|
|
41
|
+
|| /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(candidate)) ? candidate : null;
|
|
42
|
+
const description = recovery === 'not_found' ? 'The recovery read did not find the original request.'
|
|
43
|
+
: recovery === 'still_reviewed' ? 'The original renewal is still reviewed, not confirmed as applied.'
|
|
44
|
+
: 'The recovery read could not be completed.';
|
|
45
|
+
emit('tool_renewal_diagnostic', { phase, original_error: { code, http_status, request_id }, recovery }, 'Renewal ' + phase + ' was not confirmed. Original error ' + code
|
|
46
|
+
+ (http_status === null ? '' : ' (HTTP ' + http_status + ')') + '. '
|
|
47
|
+
+ (request_id === null ? '' : 'Support reference ' + request_id + '. ') + description);
|
|
48
|
+
}
|
|
49
|
+
const STATE_TEXT = {
|
|
50
|
+
reviewed: 'reviewed, not approved (nothing reserved or extended)',
|
|
51
|
+
applied: 'applied',
|
|
52
|
+
cancelled: 'closed without extending anything',
|
|
53
|
+
};
|
|
54
|
+
const tty = (options) => !options.json && !!process.stdin.isTTY && !!process.stderr.isTTY;
|
|
55
|
+
const tools = (n) => `${n} shared-pool tool${n === 1 ? '' : 's'}`;
|
|
56
|
+
const seconds = (value) => value % 86_400 === 0 ? `${value / 86_400} day${value === 86_400 ? '' : 's'}`
|
|
57
|
+
: value % 3_600 === 0 ? `${value / 3_600} hour${value === 3_600 ? '' : 's'}` : value % 60 === 0 ? `${value / 60} minutes` : `${value} seconds`;
|
|
58
|
+
function renewSeconds(value) {
|
|
59
|
+
if (value === undefined)
|
|
60
|
+
return null;
|
|
61
|
+
if (!/^[1-9][0-9]{0,8}$/.test(value) || Number(value) < RENEWAL_MIN_SECONDS || Number(value) > RENEWAL_MAX_SECONDS) {
|
|
62
|
+
throw new CliError('tool_duration_invalid', `Use --seconds with a whole number from ${RENEWAL_MIN_SECONDS} to ${RENEWAL_MAX_SECONDS} (one year). Nothing was sent.`, 2);
|
|
63
|
+
}
|
|
64
|
+
return Number(value);
|
|
65
|
+
}
|
|
66
|
+
function pageNumber(value) {
|
|
67
|
+
if (value === undefined)
|
|
68
|
+
return undefined;
|
|
69
|
+
if (!/^[1-9][0-9]{0,6}$/.test(value))
|
|
70
|
+
throw new CliError('arguments_invalid', 'Use --page with a positive page number.', 2);
|
|
71
|
+
return Number(value);
|
|
72
|
+
}
|
|
73
|
+
/** Root changes a session's renewals only for the person who started it; anyone else gets a 404. */
|
|
74
|
+
const ownerOnly = (error) => {
|
|
75
|
+
if (error instanceof CliError && error.httpStatus === 404) {
|
|
76
|
+
throw new CliError('tool_renewal_not_owner', 'Only the person who started this tool session can extend it or change its renewals. Nothing was reserved or extended.', 2);
|
|
77
|
+
}
|
|
78
|
+
throw error;
|
|
79
|
+
};
|
|
80
|
+
const withdrawnError = (requestKey) => new CliError('native_tool_request_withdrawn', `Renewal request ${requestKey} was withdrawn and can never be reviewed. Start a new renewal without --request-key.`, 2);
|
|
81
|
+
const mapWithdrawn = (requestKey) => (error) => {
|
|
82
|
+
if (errorCode(error) === 'native_tool_request_withdrawn')
|
|
83
|
+
throw withdrawnError(requestKey);
|
|
84
|
+
throw error;
|
|
85
|
+
};
|
|
86
|
+
function renewalText(target, row) {
|
|
87
|
+
return [
|
|
88
|
+
`Renewal ${row.id} of tool session ${target.sessionId}: ${STATE_TEXT[row.state]}`,
|
|
89
|
+
` ${tools(row.instance_count)}: +${seconds(row.additional_seconds)}, end ${terminalText(row.previous_expires_at)} -> ${terminalText(row.new_expires_at)}`,
|
|
90
|
+
` Request ${row.request_key}, reviewed ${terminalText(row.created_at)}${row.applied_at ? `, applied ${terminalText(row.applied_at)}` : ''}`,
|
|
91
|
+
].join('\n');
|
|
92
|
+
}
|
|
93
|
+
function quoteText(target, row) {
|
|
94
|
+
return [
|
|
95
|
+
`Extend ${tools(row.instance_count)} of tool session ${target.sessionId} by ${seconds(row.additional_seconds)}: `
|
|
96
|
+
+ `they would run until ${terminalText(row.new_expires_at)} instead of ${terminalText(row.previous_expires_at)}. Same tools and data; nothing restarts.`,
|
|
97
|
+
target.isolatedTools ? `${target.isolatedTools} isolated tool${target.isolatedTools === 1 ? '' : 's'} in this session keep their current end time.` : null,
|
|
98
|
+
`Cloud-work estimate (maximum, reserved only once approved): ${amount(row.quote.maximum_units, row.quote.credit_scale, row.quote.denomination)}`,
|
|
99
|
+
`Estimate expires: ${terminalText(row.quote.expires_at)}`,
|
|
100
|
+
].filter((line) => line !== null).join('\n');
|
|
101
|
+
}
|
|
102
|
+
async function consent(question, detail, retry, options) {
|
|
103
|
+
let approved = options.approve === true;
|
|
104
|
+
if (!approved && tty(options)) {
|
|
105
|
+
approved = await selectOne(question, [
|
|
106
|
+
{ value: false, label: 'Not now', detail: 'Nothing is sent.' },
|
|
107
|
+
{ value: true, label: 'Yes', detail },
|
|
108
|
+
], options.signal);
|
|
109
|
+
}
|
|
110
|
+
if (!approved)
|
|
111
|
+
throw new CliError('tool_change_consent_required', `Nothing was sent. After the human approves: ${retry} --approve-tool-change`, 2);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* `renew --seconds <n> [--request-key <key>] [--usage-quote <quote-id>] [--approve-tool-change]`.
|
|
115
|
+
* The review is continued by its key; approval names the exact quote the human saw.
|
|
116
|
+
*/
|
|
117
|
+
async function renew(scope, target, options, emit) {
|
|
118
|
+
const signal = options.signal;
|
|
119
|
+
const batchId = target.batch.id;
|
|
120
|
+
const wanted = renewSeconds(options.seconds);
|
|
121
|
+
if (options.quote !== undefined && options.request === undefined) {
|
|
122
|
+
throw new CliError('arguments_invalid', 'Use --usage-quote with the --request-key that was printed with it. Nothing was sent.', 2);
|
|
123
|
+
}
|
|
124
|
+
const quoteGiven = options.quote === undefined ? undefined : renewalId(options.quote, 'quote id');
|
|
125
|
+
const requestKey = options.request === undefined ? randomUUID() : renewalId(options.request, 'request key');
|
|
126
|
+
const recovery = `firedrill tools session ${target.sessionId} renew${wanted ? ` --seconds ${wanted}` : ''} --request-key ${requestKey}`;
|
|
127
|
+
const read = `firedrill tools session ${target.sessionId} renewal-request ${requestKey}`;
|
|
128
|
+
const withdraw = `firedrill tools session ${target.sessionId} withdraw-renewal ${requestKey}`;
|
|
129
|
+
// A renewal already reviewed under this key is continued, never reviewed again.
|
|
130
|
+
let renewal = options.request === undefined ? null : await recoverRenewal(scope, { batchId, requestKey, signal }).catch(mapWithdrawn(requestKey));
|
|
131
|
+
if (renewal && wanted !== null && renewal.additional_seconds !== wanted) {
|
|
132
|
+
throw new CliError('idempotency_conflict', `That renewal was reviewed for ${seconds(renewal.additional_seconds)}. Continue it without --seconds, `
|
|
133
|
+
+ 'or start a new one without --request-key.', 2);
|
|
134
|
+
}
|
|
135
|
+
if (!renewal) {
|
|
136
|
+
if (wanted === null)
|
|
137
|
+
throw new CliError('tool_duration_required', 'Use --seconds <n> to say how much longer the tools run. Nothing was sent.', 2);
|
|
138
|
+
const batch = target.batch;
|
|
139
|
+
if (batch.state !== STANDALONE_ACTIVE || batch.stop_requested_at || !batch.expires_at || Date.parse(batch.expires_at) <= Date.now()) {
|
|
140
|
+
throw new CliError('tool_renewal_not_live', `Only a running tool session can be extended; this one is ${terminalText(batch.state)}`
|
|
141
|
+
+ `${batch.stop_requested_at ? ' and stopping' : ''}. Start a new session instead. Nothing was sent.`, 2);
|
|
142
|
+
}
|
|
143
|
+
emit('tool_renewal_request', { session_id: target.sessionId, batch_id: batchId, additional_seconds: wanted, request_key: requestKey }, `Renewal request: ${requestKey}\nIf interrupted, continue with ${recovery}. Do not start again under a new key.`);
|
|
144
|
+
try {
|
|
145
|
+
renewal = await reviewRenewal(scope, { batchId, requestKey, seconds: wanted, signal });
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
if (errorCode(error) === 'native_tool_request_withdrawn')
|
|
149
|
+
throw withdrawnError(requestKey);
|
|
150
|
+
if (error instanceof CliError && error.httpStatus === 404)
|
|
151
|
+
ownerOnly(error);
|
|
152
|
+
// Only an unanswered (or cancelled) review may have landed; a refusal or a bad local input is reported as it is.
|
|
153
|
+
if (!signal.aborted && !isTransient(error) && errorCode(error) !== 'native_response_unconfirmed')
|
|
154
|
+
throw error;
|
|
155
|
+
let recoveryState = 'not_found';
|
|
156
|
+
renewal = await recoverRenewal(scope, { batchId, requestKey, signal: AbortSignal.timeout(RECOVER_MS) })
|
|
157
|
+
.catch(() => { recoveryState = 'read_failed'; return null; });
|
|
158
|
+
if (!renewal) {
|
|
159
|
+
renewalDiagnostic(emit, 'review', error, recoveryState);
|
|
160
|
+
throw new CliError('tool_renewal_unconfirmed', `The renewal request was not confirmed. Read it with ${read}; continue it with ${recovery}; `
|
|
161
|
+
+ `or, if the human decides it must never be reviewed, withdraw it with ${withdraw} (which undoes nothing).`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const reviewed = renewal;
|
|
166
|
+
if (wanted !== null && reviewed.additional_seconds !== wanted) {
|
|
167
|
+
throw new CliError('idempotency_conflict', 'The recovered original renewal has a different duration. Read it by its request key before continuing. Nothing was approved.', 2);
|
|
168
|
+
}
|
|
169
|
+
if (reviewed.state !== 'reviewed') {
|
|
170
|
+
// Already applied or closed: shown as it is, never approved again.
|
|
171
|
+
emit('tool_renewal', reviewed, renewalText(target, reviewed)
|
|
172
|
+
+ (reviewed.state === 'cancelled' ? '\nThis review was closed. To extend the tools, start a new renewal without --request-key.' : ''));
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const cancel = `firedrill tools session ${target.sessionId} cancel-renewal ${reviewed.id}`;
|
|
176
|
+
if (Date.parse(reviewed.quote.expires_at) - Date.now() <= QUOTE_MARGIN_MS) {
|
|
177
|
+
throw new CliError('tool_quote_expired', 'This estimate has expired or expires within a minute. Nothing was reserved or extended. '
|
|
178
|
+
+ `Close this review with ${cancel}, then start a new renewal without --request-key.`, 2);
|
|
179
|
+
}
|
|
180
|
+
if (quoteGiven !== undefined && quoteGiven !== reviewed.quote.id) {
|
|
181
|
+
throw new CliError('idempotency_conflict', `That estimate is not this renewal's (its estimate is ${reviewed.quote.id}). Nothing was reserved or extended.`, 2);
|
|
182
|
+
}
|
|
183
|
+
let approved = options.approve === true && (!reviewed.quote.credit_approval_required || quoteGiven === reviewed.quote.id);
|
|
184
|
+
const interactive = tty(options);
|
|
185
|
+
emit('tool_renewal_quote', { ...reviewed, session_id: target.sessionId }, quoteText(target, reviewed));
|
|
186
|
+
if (!approved && interactive) {
|
|
187
|
+
approved = await selectOne(`Extend these tools by ${seconds(reviewed.additional_seconds)}?`, [
|
|
188
|
+
{ value: false, label: 'Not now', detail: 'Nothing is reserved or extended. The review stays open until it is closed or its estimate expires.' },
|
|
189
|
+
{ value: true, label: 'Extend them', detail: 'Reserves up to the estimate above and moves the end time. Same tools and data; nothing restarts.' },
|
|
190
|
+
], signal);
|
|
191
|
+
}
|
|
192
|
+
if (!approved) {
|
|
193
|
+
throw new CliError('tool_change_consent_required', 'Nothing was reserved or extended. Show the human this estimate; after they approve it: '
|
|
194
|
+
+ `${recovery} --usage-quote ${reviewed.quote.id} --approve-tool-change\nIf they decline, close the review: ${cancel} --approve-tool-change`, 2);
|
|
195
|
+
}
|
|
196
|
+
const creditApproval = await approveCredits([reviewed.quote], options, interactive, `${recovery} --usage-quote ${reviewed.quote.id} --approve-tool-change`);
|
|
197
|
+
let applied;
|
|
198
|
+
try {
|
|
199
|
+
applied = await retryTransient(() => applyRenewal(scope, { renewal: reviewed, signal, creditApproval }), { signal, attempts: 3 });
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
if (signal.aborted)
|
|
203
|
+
throw error;
|
|
204
|
+
// An unanswered approval may have landed: the renewal says, and nothing is applied or charged twice.
|
|
205
|
+
let recoveryState = 'read_failed';
|
|
206
|
+
const current = await getRenewal(scope, { batchId, renewalId: reviewed.id, signal: AbortSignal.timeout(RECOVER_MS) })
|
|
207
|
+
.catch(readError => {
|
|
208
|
+
if (readError instanceof CliError && readError.httpStatus === 404)
|
|
209
|
+
recoveryState = 'not_found';
|
|
210
|
+
return null;
|
|
211
|
+
});
|
|
212
|
+
if (!current || current.state === 'reviewed') {
|
|
213
|
+
if (error instanceof CliError && error.httpStatus !== null && !isTransient(error))
|
|
214
|
+
throw error;
|
|
215
|
+
renewalDiagnostic(emit, 'approval', error, current?.state === 'reviewed' ? 'still_reviewed' : recoveryState);
|
|
216
|
+
throw new CliError('tool_renewal_unconfirmed', `The approval was not confirmed. Check firedrill tools session ${target.sessionId} renewal ${reviewed.id}; `
|
|
217
|
+
+ `if it is still reviewed, run ${recovery} --usage-quote ${reviewed.quote.id} --approve-tool-change. It is never charged twice.`);
|
|
218
|
+
}
|
|
219
|
+
applied = current;
|
|
220
|
+
}
|
|
221
|
+
emit('tool_renewal', applied, renewalText(target, applied)
|
|
222
|
+
+ (applied.state === 'applied' ? `\nThe tools now run until ${terminalText(applied.new_expires_at)}. Check with firedrill tools session ${target.sessionId}.` : ''));
|
|
223
|
+
}
|
|
224
|
+
/** Each renewal verb's arguments and flags, checked before anything is read or sent. */
|
|
225
|
+
export function checkRenewalArguments(verb, value, options) {
|
|
226
|
+
const takes = {
|
|
227
|
+
renew: ['seconds', 'request', 'quote', 'approve', 'approveCredits'], renewals: ['page'], renewal: [], 'cancel-renewal': ['approve'],
|
|
228
|
+
'renewal-request': [], 'withdraw-renewal': ['approve'],
|
|
229
|
+
};
|
|
230
|
+
const flags = { seconds: '--seconds', request: '--request-key', quote: '--usage-quote',
|
|
231
|
+
approve: '--approve-tool-change', approveCredits: '--approve-credits', page: '--page' };
|
|
232
|
+
const extra = Object.keys(flags)
|
|
233
|
+
.filter((flag) => options[flag] !== undefined && options[flag] !== false && !takes[verb]?.includes(flag));
|
|
234
|
+
if (extra.length)
|
|
235
|
+
throw new CliError('arguments_invalid', `tools session <session-id> ${verb} does not take ${extra.map((flag) => flags[flag]).join(', ')}.`, 2);
|
|
236
|
+
if (!RENEWAL_VERBS.has(verb) || (verb === 'renew' || verb === 'renewals') !== (value === undefined)) {
|
|
237
|
+
throw new CliError('arguments_invalid', 'Use tools session <session-id> renew --seconds <n>, renewals, renewal <renewal-id>, cancel-renewal <renewal-id>, '
|
|
238
|
+
+ 'renewal-request <key> or withdraw-renewal <key>.', 2);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* `tools session <session-id> renew --seconds <n> [--request-key <key>] [--usage-quote <quote-id>] [--approve-tool-change]
|
|
243
|
+
* | renewals [--page <n>] | renewal <renewal-id> | cancel-renewal <renewal-id> [--approve-tool-change]
|
|
244
|
+
* | renewal-request <key> | withdraw-renewal <key> [--approve-tool-change]`.
|
|
245
|
+
*/
|
|
246
|
+
export async function toolRenewalCommand(scope, target, verb, value, options, emit) {
|
|
247
|
+
checkRenewalArguments(verb, value, options);
|
|
248
|
+
const signal = options.signal;
|
|
249
|
+
const batchId = target.batch.id;
|
|
250
|
+
const session = `firedrill tools session ${target.sessionId}`;
|
|
251
|
+
if (verb === 'renew')
|
|
252
|
+
return renew(scope, target, options, emit);
|
|
253
|
+
if (verb === 'renewals') {
|
|
254
|
+
const page = await listRenewals(scope, { batchId, page: pageNumber(options.page), signal });
|
|
255
|
+
emit('tool_renewals', { session_id: target.sessionId, batch_id: batchId, ...page }, [
|
|
256
|
+
`Renewals of tool session ${target.sessionId}, page ${page.page} (${page.count} in all):`,
|
|
257
|
+
...page.results.map((one) => ` ${one.id} ${STATE_TEXT[one.state]} +${seconds(one.additional_seconds)}, until ${terminalText(one.new_expires_at)}`
|
|
258
|
+
+ ` ${terminalText(one.created_at)}`),
|
|
259
|
+
page.results.length ? null : ' none',
|
|
260
|
+
page.next ? `More: --page ${page.page + 1}` : null,
|
|
261
|
+
page.results.length ? `Read one: ${session} renewal <renewal-id>` : null,
|
|
262
|
+
`Extend the tools: ${session} renew --seconds <n>`,
|
|
263
|
+
].filter((line) => line !== null).join('\n'));
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
if (verb === 'renewal' || verb === 'cancel-renewal') {
|
|
267
|
+
const id = renewalId(value, 'renewal id');
|
|
268
|
+
const row = await getRenewal(scope, { batchId, renewalId: id, signal }).catch((error) => {
|
|
269
|
+
if (error instanceof CliError && error.httpStatus === 404) {
|
|
270
|
+
throw new CliError('tool_renewal_not_found', `That renewal is not one of this session's. List them with ${session} renewals.`, 2);
|
|
271
|
+
}
|
|
272
|
+
throw error;
|
|
273
|
+
});
|
|
274
|
+
if (verb === 'renewal' || row.state !== 'reviewed') {
|
|
275
|
+
emit('tool_renewal', row, renewalText(target, row) + (row.state === 'reviewed'
|
|
276
|
+
? `\nApprove it: ${session} renew --request-key ${row.request_key}\nClose it unused: ${session} cancel-renewal ${row.id}`
|
|
277
|
+
: verb === 'cancel-renewal' ? `\nThis renewal is ${STATE_TEXT[row.state]}, so there is nothing to close; nothing was sent.` : ''));
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
await consent('Close this unused renewal review?', 'Its estimate can no longer be approved. The tools keep their current end time.', `${session} cancel-renewal ${row.id}`, options);
|
|
281
|
+
// Closing is idempotent, and an applied extension is returned unchanged (never undone).
|
|
282
|
+
const closed = await retryTransient(() => cancelRenewal(scope, { batchId, renewalId: row.id, signal }), { signal, attempts: 3 }).catch(ownerOnly);
|
|
283
|
+
emit('tool_renewal', closed, renewalText(target, closed) + (closed.state === 'applied'
|
|
284
|
+
? '\nIt had already been applied, so nothing was closed or undone.' : '\nClosed. Nothing was reserved or extended.'));
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
const requestKey = renewalId(value, 'request key');
|
|
288
|
+
if (verb === 'renewal-request') {
|
|
289
|
+
const row = await recoverRenewal(scope, { batchId, requestKey, signal }).catch(mapWithdrawn(requestKey));
|
|
290
|
+
if (!row) {
|
|
291
|
+
emit('tool_renewal_request', { session_id: target.sessionId, batch_id: batchId, request_key: requestKey, state: 'not_found' }, `No renewal is recorded under request ${requestKey} yet. An unanswered request may still arrive.\n`
|
|
292
|
+
+ `Continue it with ${session} renew --seconds <the original n> --request-key ${requestKey}, `
|
|
293
|
+
+ `or, if the human decides it must never be reviewed, withdraw it with ${session} withdraw-renewal ${requestKey} (which undoes nothing).`);
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
emit('tool_renewal', row, renewalText(target, row));
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
await consent(`Withdraw renewal request ${requestKey}?`, 'If it has not arrived, it can never be reviewed. If it already arrived, it is shown instead; nothing is undone.', `${session} withdraw-renewal ${requestKey}`, options);
|
|
300
|
+
const result = await retryTransient(() => withdrawRenewal(scope, { batchId, requestKey, signal }), { signal, attempts: 3 }).catch(ownerOnly);
|
|
301
|
+
if (result.state === 'withdrawn') {
|
|
302
|
+
emit('tool_renewal_withdrawal', result, `Renewal request ${requestKey} is withdrawn: it can never be reviewed. Nothing else changed.`);
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
emit('tool_renewal_withdrawal', result, `Renewal request ${requestKey} had already arrived, so it was not withdrawn and nothing was undone:\n`
|
|
306
|
+
+ renewalText(target, result.receipt)
|
|
307
|
+
+ (result.receipt.state === 'reviewed' ? `\nClose that review unused with ${session} cancel-renewal ${result.receipt.id}.` : ''));
|
|
308
|
+
}
|