firedrill-run 2.2.4 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +178 -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 +465 -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 +1622 -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 +61 -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,369 @@
|
|
|
1
|
+
import { APP_ORIGIN } from './http.js';
|
|
2
|
+
import { createInterface } from 'node:readline/promises';
|
|
3
|
+
import { api, openBrowser } from './auth.js';
|
|
4
|
+
import { CliError } from './http.js';
|
|
5
|
+
import { selectMany, selectOne } from './prompts.js';
|
|
6
|
+
import { identifier } from './world-contracts.js';
|
|
7
|
+
import { selectedWorkspace, selectedWorld } from './world-access.js';
|
|
8
|
+
import { inputSchema, readMetadata, remember, requestAction, retained, validateBody } from './configuration-intents.js';
|
|
9
|
+
import { serviceReceipts, validateReceiptOptions } from './service-receipts.js';
|
|
10
|
+
import { packageReads } from './tool-package-reads.js';
|
|
11
|
+
const VARIABLE = /^[A-Za-z_][A-Za-z0-9_]{0,127}$/;
|
|
12
|
+
export const interactive = (options) => !options.json && !!process.stdin.isTTY && !!process.stderr.isTTY;
|
|
13
|
+
export const auth = (context, options) => ({ actor: context.owner, workspace: context.workspace, signal: options.signal });
|
|
14
|
+
export function query(options) {
|
|
15
|
+
if (options.page !== undefined && !/^[1-9][0-9]{0,8}$/.test(options.page) || (options.search?.length ?? 0) > 200) {
|
|
16
|
+
throw new CliError('arguments_invalid', 'Use a positive page and a search up to 200 characters.', 2);
|
|
17
|
+
}
|
|
18
|
+
return `page=${options.page ?? '1'}&q=${encodeURIComponent(options.search ?? '')}`;
|
|
19
|
+
}
|
|
20
|
+
export async function line(title, maximum, signal, initial = '', preserveSpace = false) {
|
|
21
|
+
const prompt = createInterface({ input: process.stdin, output: process.stderr, terminal: false });
|
|
22
|
+
try {
|
|
23
|
+
const entered = await prompt.question(`${title}${initial ? ` [${initial}]` : ''}: `, { signal });
|
|
24
|
+
const value = (preserveSpace ? entered : entered.trim()) || initial;
|
|
25
|
+
if (value.length > maximum || /[\u0000-\u001f\u007f]/.test(value))
|
|
26
|
+
throw new CliError('configuration_input_invalid', 'Use configuration text within this field capacity. No request was saved.', 2);
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
finally {
|
|
30
|
+
prompt.close();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export async function choosePaged(title, path, context, options, describe, includeNew = false, read) {
|
|
34
|
+
let page = 1, search = options.search ?? '';
|
|
35
|
+
while (true) {
|
|
36
|
+
const data = read ? await read(page, search)
|
|
37
|
+
: await api(`${path}${path.includes('?') ? '&' : '?'}page=${page}&q=${encodeURIComponent(search)}`, auth(context, options));
|
|
38
|
+
const choices = data.results.map(row => ({ value: row.id, ...describe(row) }));
|
|
39
|
+
if (includeNew)
|
|
40
|
+
choices.unshift({ value: 'new', label: 'Add a variable' });
|
|
41
|
+
if (page > 1)
|
|
42
|
+
choices.push({ value: 'previous', label: 'Previous page' });
|
|
43
|
+
if (data.next)
|
|
44
|
+
choices.push({ value: 'next', label: 'Next page' });
|
|
45
|
+
choices.push({ value: 'search', label: 'Search entries' }, { value: 'cancel', label: 'Cancel' });
|
|
46
|
+
const choice = await selectOne(title, choices, options.signal);
|
|
47
|
+
if (choice === 'new')
|
|
48
|
+
return null;
|
|
49
|
+
if (choice === 'next') {
|
|
50
|
+
page += 1;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (choice === 'previous') {
|
|
54
|
+
page -= 1;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (choice === 'search') {
|
|
58
|
+
search = await line('Find an entry (blank for all)', 200, options.signal);
|
|
59
|
+
page = 1;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (choice === 'cancel')
|
|
63
|
+
throw new CliError('canceled', 'No selection was submitted.', 130);
|
|
64
|
+
const row = data.results.find(item => item.id === choice);
|
|
65
|
+
if (!row)
|
|
66
|
+
throw new CliError('selection_changed', 'The selected entry changed. Reopen this setup.', 2);
|
|
67
|
+
return row;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
export async function approval(options, title) {
|
|
71
|
+
const allowed = options.approve || interactive(options) && await selectOne(title, [{ value: false, label: 'Cancel' }, { value: true, label: 'Save reviewed settings' }], options.signal);
|
|
72
|
+
if (!allowed)
|
|
73
|
+
throw new CliError('configuration_consent_required', 'Nothing was submitted. Review the metadata and use --approve-configuration for automation.', 2);
|
|
74
|
+
}
|
|
75
|
+
function edit(row) {
|
|
76
|
+
return { name: row.name, phase: row.phase, source: row.source, vault_entry_id: row.vault_entry_id,
|
|
77
|
+
binding_key: row.binding_key, dependency_key: row.dependency_key };
|
|
78
|
+
}
|
|
79
|
+
async function mappingBody(context, options, output) {
|
|
80
|
+
const selected = await choosePaged('Configuration variable', context.prefix + '/configuration?editable=true', context, options, row => ({ label: row.name, detail: `${row.phase} · ${row.connection_role === 'endpoint' ? 'Supplied by connection' : row.source}${row.source === 'vault' ? row.vault_reference ? ` · ${row.vault_reference.name} · Version ${row.vault_reference.version} · ${row.vault_reference.purpose || 'No purpose recorded'} · ${row.vault_reference.state}` : ' · Saved reference unavailable' : ''}` }), true);
|
|
81
|
+
const current = await api(`${context.prefix}/configuration?page=1${selected ? '&mapping_id=' + identifier(selected.id) : ''}`, auth(context, options));
|
|
82
|
+
if (!Number.isSafeInteger(current.configuration_revision))
|
|
83
|
+
throw new CliError('configuration_conflict', 'Configuration revision is unavailable.', 2);
|
|
84
|
+
if (selected) {
|
|
85
|
+
const refreshed = current.results.find(one => one.id === selected.id);
|
|
86
|
+
if (!refreshed || ['id', 'name', 'phase', 'required', 'source', 'vault_entry_id', 'binding_key', 'dependency_key', 'has_default', 'connection_role']
|
|
87
|
+
.some(key => refreshed[key] !== selected[key]))
|
|
88
|
+
throw new CliError('configuration_conflict', 'The chosen mapping changed. Review its current settings before editing.', 2);
|
|
89
|
+
}
|
|
90
|
+
let row;
|
|
91
|
+
if (selected) {
|
|
92
|
+
if (selected.connection_role === 'endpoint') {
|
|
93
|
+
throw new CliError('connection_endpoint_owned', 'The connection supplies this endpoint. Use firedrill connections save to change its address or variable.', 2);
|
|
94
|
+
}
|
|
95
|
+
row = edit(selected);
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
const name = await line('Variable name', 128, options.signal);
|
|
99
|
+
if (!VARIABLE.test(name))
|
|
100
|
+
throw new CliError('configuration_input_invalid', 'Use a valid variable name.', 2);
|
|
101
|
+
const phase = await selectOne('Phase', [{ value: 'runtime', label: 'Runtime' }, { value: 'build', label: 'Build' }, { value: 'both', label: 'Build and runtime' }], options.signal);
|
|
102
|
+
const existing = await api(`${context.prefix}/configuration?name=${encodeURIComponent(name)}`, auth(context, options));
|
|
103
|
+
if (existing.configuration_revision !== current.configuration_revision || existing.results.some(one => one.phase === phase || one.phase === 'both' || phase === 'both')) {
|
|
104
|
+
throw new CliError('configuration_conflict', 'An overlapping variable already exists or settings changed. Choose the existing mapping to edit it.', 2);
|
|
105
|
+
}
|
|
106
|
+
row = { name, phase, source: 'unset', vault_entry_id: null, binding_key: '', dependency_key: '' };
|
|
107
|
+
}
|
|
108
|
+
const credential = selected?.connection_role === 'credential';
|
|
109
|
+
const choices = [{ value: 'vault', label: 'Saved value' }, { value: 'unset', label: 'Not set' },
|
|
110
|
+
...(selected?.source === 'local' ? [{ value: 'local', label: 'Keep the current device-only value' }] : []),
|
|
111
|
+
...(!credential && row.phase === 'runtime' ? [{ value: 'world', label: 'Simulated world endpoint' }] : []),
|
|
112
|
+
...(selected?.has_default && !credential ? [{ value: 'default', label: 'Detected default' }] : []),
|
|
113
|
+
...(selected && !selected.required && !selected.connection_role ? [{ value: 'remove', label: 'Remove this variable mapping' }] : [])];
|
|
114
|
+
row.source = await selectOne('Value source', choices, options.signal);
|
|
115
|
+
if (row.source === 'vault') {
|
|
116
|
+
const entry = await choosePaged('Saved value', `/api/workspaces/${context.workspace}/vault?phase=${row.phase}${credential ? '&secret=true' : ''}`, context, options, item => ({ label: item.name, detail: item.secret ? 'Secret' : item.empty ? 'Empty string' : 'Configuration value' }));
|
|
117
|
+
if (!entry || entry.state !== 'active')
|
|
118
|
+
throw new CliError('credential_unavailable', 'Choose an active saved value.', 2);
|
|
119
|
+
row.vault_entry_id = entry.id;
|
|
120
|
+
row.binding_key = '';
|
|
121
|
+
if (!credential) {
|
|
122
|
+
const use = await selectOne('Use this value for', [{ value: 'agent', label: 'Agent configuration' },
|
|
123
|
+
{ value: 'dependency', label: 'A selected dependency' }], options.signal);
|
|
124
|
+
if (use === 'agent')
|
|
125
|
+
row.dependency_key = '';
|
|
126
|
+
else {
|
|
127
|
+
const dependency = await choosePaged('Dependency', `${context.prefix}/dependencies${entry.secret ? '?mode=real' : ''}`, context, options, item => ({ label: item.name, detail: item.mode }));
|
|
128
|
+
if (!dependency || dependency.mode === 'unselected')
|
|
129
|
+
throw new CliError('dependency_choice_required', 'Select how this dependency runs before mapping a value.', 2);
|
|
130
|
+
row.dependency_key = dependency.key;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
else if (row.source === 'world') {
|
|
135
|
+
const dependency = await choosePaged('Simulated dependency', `${context.prefix}/dependencies?mode=simulated`, context, options, item => ({ label: item.name }));
|
|
136
|
+
if (!dependency)
|
|
137
|
+
throw new CliError('dependency_choice_required', 'Choose a simulated dependency.', 2);
|
|
138
|
+
if (row.phase !== 'runtime')
|
|
139
|
+
throw new CliError('world_binding_phase_invalid', 'World endpoints are allocated at Runtime. Add a Runtime mapping instead.', 2);
|
|
140
|
+
row.binding_key = dependency.key;
|
|
141
|
+
row.dependency_key = dependency.key;
|
|
142
|
+
row.vault_entry_id = null;
|
|
143
|
+
}
|
|
144
|
+
else if (row.source !== 'local') {
|
|
145
|
+
row.vault_entry_id = null;
|
|
146
|
+
row.binding_key = '';
|
|
147
|
+
}
|
|
148
|
+
output('configuration_review', { variable: row.name, phase: row.phase, source: row.source, dependency_key: row.dependency_key }, `${row.name} · ${row.phase} · ${row.source}\nOnly this mapping is changed. No agent is run.`);
|
|
149
|
+
return { revision: current.configuration_revision, mappings: [row] };
|
|
150
|
+
}
|
|
151
|
+
async function operationSelection(context, dependency, options) {
|
|
152
|
+
const selected = new Set(dependency.policy.operation_names ?? []);
|
|
153
|
+
let page = 1;
|
|
154
|
+
while (true) {
|
|
155
|
+
const data = await api(`${context.prefix}/items/${dependency.id}/operations?page=${page}&q=${encodeURIComponent(options.search ?? '')}`, auth(context, options));
|
|
156
|
+
if (!data.results.length)
|
|
157
|
+
throw new CliError('dependency_operations_missing', 'This selection has no declared operations. Review the service contract.', 2);
|
|
158
|
+
const chosen = await selectMany(`Allowed operations · page ${page}`, data.results.map(row => ({ value: row.name, label: row.name,
|
|
159
|
+
detail: row.effect === 'unknown' ? 'Effects not classified' : row.effect })), options.signal, [...selected]);
|
|
160
|
+
for (const row of data.results)
|
|
161
|
+
selected.delete(row.name);
|
|
162
|
+
for (const name of chosen)
|
|
163
|
+
selected.add(name);
|
|
164
|
+
const actions = [{ value: 'done', label: `Continue with ${selected.size} selected operations` },
|
|
165
|
+
...(data.next ? [{ value: 'next', label: 'Next page' }] : []), ...(page > 1 ? [{ value: 'previous', label: 'Previous page' }] : [])];
|
|
166
|
+
const action = await selectOne('Operation selection', actions, options.signal);
|
|
167
|
+
if (action === 'next') {
|
|
168
|
+
page += 1;
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
if (action === 'previous') {
|
|
172
|
+
page -= 1;
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
if (!selected.size)
|
|
176
|
+
throw new CliError('dependency_operations_missing', 'Choose at least one operation.', 2);
|
|
177
|
+
return [...selected];
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
async function bindingInput(options, prior) {
|
|
181
|
+
if (prior && await selectOne('Service address and credential header mappings', [{ value: true, label: 'Keep the reviewed mappings' },
|
|
182
|
+
{ value: false, label: 'Enter different mappings' }], options.signal))
|
|
183
|
+
return prior;
|
|
184
|
+
const base_url = await line('HTTPS service address (no credentials or query)', 2048, options.signal);
|
|
185
|
+
const endpoint_variable = await line('Original endpoint variable', 128, options.signal);
|
|
186
|
+
const authentication = [];
|
|
187
|
+
while (authentication.length < 16) {
|
|
188
|
+
const add = await selectOne('Credential headers', [{ value: false, label: 'No more credential headers' },
|
|
189
|
+
{ value: true, label: 'Add a credential header mapping' }], options.signal);
|
|
190
|
+
if (!add)
|
|
191
|
+
break;
|
|
192
|
+
const variable = await line('Credential variable name, not its value', 128, options.signal);
|
|
193
|
+
const header = await line('HTTP header name', 64, options.signal);
|
|
194
|
+
const prefix = await line('Prefix including any trailing space (optional)', 33, options.signal, '', true);
|
|
195
|
+
authentication.push({ variable, header, prefix });
|
|
196
|
+
}
|
|
197
|
+
return { base_url, endpoint_variable, authentication };
|
|
198
|
+
}
|
|
199
|
+
async function dependencyBody(context, detail, options, output) {
|
|
200
|
+
const dependency = detail.dependency;
|
|
201
|
+
const mode = await selectOne('Connection', [{ value: 'simulated', label: 'Simulated service' },
|
|
202
|
+
{ value: 'real', label: 'Real account' }, { value: 'unselected', label: 'Not selected' }], options.signal);
|
|
203
|
+
const body = { mode, configuration_revision: detail.configuration_revision, service_revision: dependency.service_revision };
|
|
204
|
+
if (mode === 'simulated') {
|
|
205
|
+
const source = await selectOne('Service implementation', [{ value: 'generated', label: 'Catalog first', detail: 'Review compatible packages before authoring missing supported behavior.' },
|
|
206
|
+
{ value: 'catalog', label: 'Saved tool package', detail: 'Reuse an exact version. Runtime validation checks the native layout and supported state.' }], options.signal);
|
|
207
|
+
if (source === 'catalog') {
|
|
208
|
+
const prefix = `/api/workspaces/${context.workspace}/tools`;
|
|
209
|
+
const packages = packageReads(context, options.signal);
|
|
210
|
+
const picked = await choosePaged('Saved tool package', `${prefix}/catalog?state=inspected`, context, options, row => ({ label: row.name, detail: row.version }), false, packages.versions);
|
|
211
|
+
if (!picked)
|
|
212
|
+
throw new CliError('canceled', 'No service connection was saved.', 130);
|
|
213
|
+
const path = `${prefix}/implementations/${identifier(picked.id)}`;
|
|
214
|
+
const version = await packages.version(picked.id);
|
|
215
|
+
if (version.state !== 'inspected' || !Number.isSafeInteger(version.service_count) || (version.service_count ?? 0) < 1) {
|
|
216
|
+
throw new CliError('catalog_binding_revoked', 'This package is unavailable. No connection was saved.');
|
|
217
|
+
}
|
|
218
|
+
let service;
|
|
219
|
+
if (version.service_count === 1) {
|
|
220
|
+
const page = await packages.services(version);
|
|
221
|
+
if (page.implementation_id !== version.id || page.contract_digest !== version.contract_digest || page.count !== 1 || page.results.length !== 1) {
|
|
222
|
+
throw new CliError('catalog_binding_revoked', 'This package changed. Reopen the connection setup. No connection was saved.');
|
|
223
|
+
}
|
|
224
|
+
service = page.results[0] ?? null;
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
service = await choosePaged('Service', `${path}/services`, context, options, row => ({ label: row.name, detail: `${row.operation_count} operations` }), false, (page, search) => packages.services(version, page, search));
|
|
228
|
+
}
|
|
229
|
+
if (!service || !/^[a-z][a-z0-9_-]{0,79}$/.test(service.key))
|
|
230
|
+
throw new CliError('catalog_binding_invalid', 'Choose an available service. No connection was saved.');
|
|
231
|
+
const selected = await packages.service(version, service.key);
|
|
232
|
+
if (selected.implementation_id !== version.id || selected.contract_digest !== version.contract_digest || selected.key !== service.key) {
|
|
233
|
+
throw new CliError('catalog_binding_revoked', 'This package changed. Reopen the connection setup. No connection was saved.');
|
|
234
|
+
}
|
|
235
|
+
body.catalog = { implementation_id: version.id, package_service_key: selected.key };
|
|
236
|
+
output('tool_package_review', { name: version.name, version: version.version, implementation_id: version.id, service_key: selected.key, service_name: selected.name }, `Tool package: ${version.name} ${version.version}\nService: ${selected.name}\nEach independent drill uses private state. This selection is not runtime validation.`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
if (mode === 'real') {
|
|
240
|
+
const all = await selectOne('Allowed operations', [{ value: false, label: 'Select individual operations' },
|
|
241
|
+
{ value: true, label: `All ${dependency.operation_count} operations in this revision` }], options.signal);
|
|
242
|
+
body.allow_all_operations = all;
|
|
243
|
+
body.operation_names = all ? [] : await operationSelection(context, dependency, options);
|
|
244
|
+
const hosts = await line('Exact allowed hostnames, separated by commas', 4096, options.signal, (dependency.policy.allowed_hosts ?? []).join(', '));
|
|
245
|
+
body.allowed_hosts = hosts.split(',').map(one => one.trim()).filter(Boolean);
|
|
246
|
+
body.http_binding = await bindingInput(options, dependency.policy.http_binding);
|
|
247
|
+
body.allow_write_effects = await selectOne('Real-account effects', [{ value: false, label: 'Read-only declared operations' },
|
|
248
|
+
{ value: true, label: 'Also allow selected writes and unclassified effects' }], options.signal);
|
|
249
|
+
body.acknowledge_external_effects = await selectOne('Authorize these operations on the real account? Resetting a world cannot undo them.', [{ value: false, label: 'Cancel' }, { value: true, label: 'Authorize the reviewed operations' }], options.signal);
|
|
250
|
+
if (!body.acknowledge_external_effects)
|
|
251
|
+
throw new CliError('configuration_consent_required', 'No real connection was saved.', 2);
|
|
252
|
+
}
|
|
253
|
+
output('configuration_review', { service: dependency.name, mode, service_revision: dependency.service_revision }, `${dependency.name} · ${mode} · Revision ${dependency.service_revision}\nSaving changes revokes prior credential grants. Review and save Configuration before executing.`);
|
|
254
|
+
return body;
|
|
255
|
+
}
|
|
256
|
+
async function recovery(action, options, output) {
|
|
257
|
+
if (!options.request || options.world || options.file || options.page || options.search)
|
|
258
|
+
throw new CliError('arguments_invalid', 'Use configuration status|resume|withdraw|forget --request-key <id>, with --workspace if needed.', 2);
|
|
259
|
+
const scope = await selectedWorkspace({ ...options, interactive: interactive(options) });
|
|
260
|
+
const intent = await retained(scope, options.request);
|
|
261
|
+
const context = { ...scope, world: intent.world, prefix: `/api/workspaces/${scope.workspace}/worlds/${intent.world}` };
|
|
262
|
+
if (action !== 'status' && action !== 'resume')
|
|
263
|
+
await approval(options, action === 'withdraw'
|
|
264
|
+
? 'Withdraw this exact delayed request? An already accepted change will not be undone.'
|
|
265
|
+
: 'Remove only the private local recovery copy? A delayed or accepted cloud request is not cancelled.');
|
|
266
|
+
return requestAction(context, intent, action, options.signal, output);
|
|
267
|
+
}
|
|
268
|
+
async function connectionActivity(args, options, output, selected) {
|
|
269
|
+
if (args.length > 3 || args[2] !== undefined && !['selected', 'all'].includes(args[2]) || options.file || options.request || options.approve)
|
|
270
|
+
throw new CliError('arguments_invalid', 'Use connections activity [service-id] [selected|all] with paging, search or response filters only.', 2);
|
|
271
|
+
validateReceiptOptions(options);
|
|
272
|
+
if (args[1])
|
|
273
|
+
identifier(args[1]);
|
|
274
|
+
const context = selected ?? await selectedWorld({ ...options, interactive: interactive(options) });
|
|
275
|
+
const service = args[1] ?? (interactive(options) ? (await choosePaged('Service history', `${context.prefix}/items?kind=service`, context, { ...options, page: undefined, search: undefined }, row => ({ label: row.name })))?.id : undefined);
|
|
276
|
+
if (!service)
|
|
277
|
+
throw new CliError('dependency_required', 'Pass a service ID from this world to inspect its retained activity.', 2);
|
|
278
|
+
const revisions = args[2] ?? 'selected';
|
|
279
|
+
await serviceReceipts(`${context.prefix}/items/${identifier(service)}/activity?revisions=${revisions}`, context, options, interactive(options), (data, readable) => output('service_activity', data, readable), `firedrill connections activity ${service} ${revisions} --world ${context.world}`);
|
|
280
|
+
}
|
|
281
|
+
export async function configurationCommand(command, args, options, output) {
|
|
282
|
+
query(options);
|
|
283
|
+
let action = args[0] ?? 'list';
|
|
284
|
+
if (options.status !== undefined && !(command === 'connections' && action === 'activity'))
|
|
285
|
+
throw new CliError('arguments_invalid', 'Response status filters apply to connections activity.', 2);
|
|
286
|
+
if (command === 'connections' && action === 'activity')
|
|
287
|
+
return connectionActivity(args, options, output);
|
|
288
|
+
if (action === 'schema') {
|
|
289
|
+
if (args.length !== 1 || options.world || options.workspace || options.file || options.page || options.search || options.request || options.approve) {
|
|
290
|
+
throw new CliError('arguments_invalid', 'Use configuration schema or connections schema with --json only.', 2);
|
|
291
|
+
}
|
|
292
|
+
const schema = inputSchema(command === 'configuration' ? 'mappings' : 'dependency');
|
|
293
|
+
output('input_schema', schema, JSON.stringify(schema, null, 2));
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
if (command === 'configuration' && ['status', 'resume', 'withdraw', 'forget'].includes(action)) {
|
|
297
|
+
if (args.length !== 1 || action === 'status' && options.approve)
|
|
298
|
+
throw new CliError('arguments_invalid', 'Use the exact saved configuration request.', 2);
|
|
299
|
+
return recovery(action, options, output);
|
|
300
|
+
}
|
|
301
|
+
if (!['list', 'show', 'save', 'vault', 'local'].includes(action) || args.length > 2 || command === 'configuration' && args.length > 1
|
|
302
|
+
|| command === 'connections' && ['vault', 'local'].includes(action) || action !== 'save' && (options.file || options.request || options.approve)
|
|
303
|
+
|| ['show', 'save', 'vault'].includes(action) && (options.page || options.search)) {
|
|
304
|
+
throw new CliError('arguments_invalid', 'Use configuration list|save|vault|local or connections list|show|save [service-id].', 2);
|
|
305
|
+
}
|
|
306
|
+
const context = await selectedWorld({ ...options, interactive: interactive(options) });
|
|
307
|
+
if (action === 'vault') {
|
|
308
|
+
const url = `${APP_ORIGIN}/vault?workspace=${context.workspace}`;
|
|
309
|
+
const opened = options.openBrowser && !options.json && await openBrowser(url);
|
|
310
|
+
output('result', { url, opened }, opened ? 'Opened Vault. Saved credentials are never printed by this command.' : url);
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
if (!args.length && interactive(options))
|
|
314
|
+
action = await selectOne(command === 'connections' ? 'Connections' : 'Configuration', [{ value: 'list', label: 'View saved settings' }, ...(command === 'connections' ? [{ value: 'activity', label: 'Inspect service history' }] : []),
|
|
315
|
+
...(command === 'configuration' ? [{ value: 'local', label: 'Manage values kept on this device' }] : []),
|
|
316
|
+
{ value: 'save', label: 'Change settings' }], options.signal);
|
|
317
|
+
if (action === 'local') {
|
|
318
|
+
const { localValuesCommand } = await import('./local-values.js');
|
|
319
|
+
return localValuesCommand([], { ...options, workspace: context.workspace, world: context.world, expectedOwner: context.owner }, (data, readable) => output('local_value', data, readable));
|
|
320
|
+
}
|
|
321
|
+
if (action === 'activity')
|
|
322
|
+
return connectionActivity(['activity'], options, output, context);
|
|
323
|
+
if (action === 'list') {
|
|
324
|
+
if (args.length > 1)
|
|
325
|
+
throw new CliError('arguments_invalid', 'List does not accept an item ID.', 2);
|
|
326
|
+
if (command === 'configuration') {
|
|
327
|
+
const data = await api(`${context.prefix}/configuration?${query(options)}`, auth(context, options));
|
|
328
|
+
output('result', data, [`Configuration revision ${data.configuration_revision}`, data.results.map(row => `${row.name} · ${row.phase} · ${row.connection_role === 'endpoint' ? 'Supplied by connection' : row.source}${row.source === 'vault' ? row.vault_reference ? ` · ${row.vault_reference.name} · Version ${row.vault_reference.version} · ${row.vault_reference.purpose || 'No purpose recorded'} · ${row.vault_reference.state}` : ' · Saved reference unavailable' : ''}${row.dependency_name ? ' · ' + row.dependency_name : ''}`).join('\n') || 'No configuration variables.',
|
|
329
|
+
...(data.next ? [`Next page: --page ${data.page + 1}`] : [])].join('\n'));
|
|
330
|
+
}
|
|
331
|
+
else {
|
|
332
|
+
const data = await api(`${context.prefix}/dependencies?${query(options)}`, auth(context, options));
|
|
333
|
+
output('result', data, [data.results.map(row => `${row.id} ${row.name} · ${row.mode} · ${row.operation_count} operations`).join('\n') || 'No discovered dependencies.',
|
|
334
|
+
...(data.next ? [`Next page: --page ${data.page + 1}`] : [])].join('\n'));
|
|
335
|
+
}
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
if (command === 'configuration' && action === 'show')
|
|
339
|
+
throw new CliError('arguments_invalid', 'Use configuration list to inspect saved mappings.', 2);
|
|
340
|
+
let service = null, detail;
|
|
341
|
+
if (command === 'connections') {
|
|
342
|
+
service = args[1] ? identifier(args[1]) : null;
|
|
343
|
+
if (!service && interactive(options))
|
|
344
|
+
service = (await choosePaged('Dependency', context.prefix + '/dependencies', context, options, row => ({ label: row.name, detail: row.mode })))?.id ?? null;
|
|
345
|
+
if (!service)
|
|
346
|
+
throw new CliError('dependency_required', 'Choose a service ID from firedrill connections.', 2);
|
|
347
|
+
detail = await api(`${context.prefix}/dependencies/${service}`, auth(context, options));
|
|
348
|
+
if (detail.dependency.id !== service)
|
|
349
|
+
throw new CliError('dependency_changed', 'The selected dependency changed.', 2);
|
|
350
|
+
if (action === 'show') {
|
|
351
|
+
output('result', detail, `${detail.dependency.name} · ${detail.dependency.mode}\nService revision ${detail.dependency.service_revision}\nConfiguration revision ${detail.configuration_revision}\n${detail.dependency.operation_count} declared operations`);
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
const kind = command === 'configuration' ? 'mappings' : 'dependency';
|
|
356
|
+
let body;
|
|
357
|
+
if (options.file)
|
|
358
|
+
body = await readMetadata(options.file);
|
|
359
|
+
else if (!interactive(options))
|
|
360
|
+
throw new CliError('configuration_input_required', 'Use --file <metadata.json> and --approve-configuration, or run this command in a terminal.', 2);
|
|
361
|
+
else
|
|
362
|
+
body = kind === 'mappings' ? await mappingBody(context, options, output) : await dependencyBody(context, detail, options, output);
|
|
363
|
+
validateBody(kind, body);
|
|
364
|
+
if (detail && (body.configuration_revision !== detail.configuration_revision || body.service_revision !== detail.dependency.service_revision)) {
|
|
365
|
+
throw new CliError('configuration_conflict', 'The file does not match the current connection revisions. Review its saved settings first.', 2);
|
|
366
|
+
}
|
|
367
|
+
await approval(options, 'Save these settings and keep a private metadata recovery copy? No agent or external account operation is started.');
|
|
368
|
+
return remember(context, kind, service, body, options.request, options.signal, output);
|
|
369
|
+
}
|