quoxcli 0.0.0-stage → 0.3.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/LICENSE +35 -0
- package/README.md +144 -2
- package/bin/quox.js +265 -0
- package/bin/quoxon.js +8 -0
- package/lib/api/endpoints/admin.js +151 -0
- package/lib/api/endpoints/aee.js +38 -0
- package/lib/api/endpoints/agent-attach.js +126 -0
- package/lib/api/endpoints/agent-schedules.js +26 -0
- package/lib/api/endpoints/agents.js +63 -0
- package/lib/api/endpoints/assistants.js +62 -0
- package/lib/api/endpoints/audit.js +14 -0
- package/lib/api/endpoints/auth.js +50 -0
- package/lib/api/endpoints/awareness.js +34 -0
- package/lib/api/endpoints/away.js +15 -0
- package/lib/api/endpoints/backup-schedules.js +20 -0
- package/lib/api/endpoints/backups.js +86 -0
- package/lib/api/endpoints/brain.js +140 -0
- package/lib/api/endpoints/budgets.js +62 -0
- package/lib/api/endpoints/calendarq.js +71 -0
- package/lib/api/endpoints/catalog.js +14 -0
- package/lib/api/endpoints/chat.js +61 -0
- package/lib/api/endpoints/consent.js +26 -0
- package/lib/api/endpoints/contactsq.js +68 -0
- package/lib/api/endpoints/conversations.js +46 -0
- package/lib/api/endpoints/custom-roles.js +92 -0
- package/lib/api/endpoints/divisions.js +56 -0
- package/lib/api/endpoints/domains.js +38 -0
- package/lib/api/endpoints/engagement.js +231 -0
- package/lib/api/endpoints/engine.js +11 -0
- package/lib/api/endpoints/entity.js +50 -0
- package/lib/api/endpoints/executions.js +45 -0
- package/lib/api/endpoints/fetchAllowlist.js +27 -0
- package/lib/api/endpoints/file.js +20 -0
- package/lib/api/endpoints/files.js +40 -0
- package/lib/api/endpoints/github.js +21 -0
- package/lib/api/endpoints/governance.js +43 -0
- package/lib/api/endpoints/hat.js +66 -0
- package/lib/api/endpoints/inbox.js +52 -0
- package/lib/api/endpoints/inboxq.js +120 -0
- package/lib/api/endpoints/index.js +242 -0
- package/lib/api/endpoints/invites.js +19 -0
- package/lib/api/endpoints/llm-policy.js +43 -0
- package/lib/api/endpoints/lucid.js +89 -0
- package/lib/api/endpoints/members.js +32 -0
- package/lib/api/endpoints/memory.js +94 -0
- package/lib/api/endpoints/mfa.js +32 -0
- package/lib/api/endpoints/mind.js +13 -0
- package/lib/api/endpoints/mon.js +184 -0
- package/lib/api/endpoints/notesq.js +43 -0
- package/lib/api/endpoints/objectives.js +68 -0
- package/lib/api/endpoints/orgs.js +38 -0
- package/lib/api/endpoints/plugins.js +152 -0
- package/lib/api/endpoints/powers.js +75 -0
- package/lib/api/endpoints/presence.js +33 -0
- package/lib/api/endpoints/prompts.js +69 -0
- package/lib/api/endpoints/qlarity.js +122 -0
- package/lib/api/endpoints/quoxbox.js +55 -0
- package/lib/api/endpoints/quoxchat.js +54 -0
- package/lib/api/endpoints/quoxflow.js +32 -0
- package/lib/api/endpoints/quoxplan.js +121 -0
- package/lib/api/endpoints/quoxseo.js +114 -0
- package/lib/api/endpoints/reach.js +47 -0
- package/lib/api/endpoints/router.js +17 -0
- package/lib/api/endpoints/runs.js +38 -0
- package/lib/api/endpoints/safety.js +53 -0
- package/lib/api/endpoints/scim.js +46 -0
- package/lib/api/endpoints/scopes.js +14 -0
- package/lib/api/endpoints/security.js +69 -0
- package/lib/api/endpoints/setup.js +90 -0
- package/lib/api/endpoints/skills.js +200 -0
- package/lib/api/endpoints/sso.js +67 -0
- package/lib/api/endpoints/stepup.js +20 -0
- package/lib/api/endpoints/tags.js +32 -0
- package/lib/api/endpoints/teams.js +56 -0
- package/lib/api/endpoints/telephony.js +46 -0
- package/lib/api/endpoints/tg.js +56 -0
- package/lib/api/endpoints/tools.js +50 -0
- package/lib/api/endpoints/traces.js +157 -0
- package/lib/api/endpoints/triggers.js +96 -0
- package/lib/api/endpoints/user-library.js +41 -0
- package/lib/api/endpoints/users.js +20 -0
- package/lib/api/endpoints/v1.js +585 -0
- package/lib/api/endpoints/vault.js +192 -0
- package/lib/api/endpoints/voice.js +22 -0
- package/lib/api/endpoints/volt.js +84 -0
- package/lib/api/endpoints/ward.js +47 -0
- package/lib/api/endpoints/webhooks.js +46 -0
- package/lib/api/endpoints/workflows.js +169 -0
- package/lib/api/endpoints/x.js +32 -0
- package/lib/api/endpoints.js +15 -0
- package/lib/commands/actions.js +61 -0
- package/lib/commands/admin.js +375 -0
- package/lib/commands/aee.js +99 -0
- package/lib/commands/agent.js +337 -0
- package/lib/commands/agentAttach.js +1528 -0
- package/lib/commands/approvals.js +119 -0
- package/lib/commands/aside.js +24 -0
- package/lib/commands/ask.js +144 -0
- package/lib/commands/assistant.js +169 -0
- package/lib/commands/auth.js +464 -0
- package/lib/commands/awareness.js +88 -0
- package/lib/commands/backup.js +377 -0
- package/lib/commands/brain.js +1085 -0
- package/lib/commands/budget.js +241 -0
- package/lib/commands/build.js +170 -0
- package/lib/commands/calendar.js +216 -0
- package/lib/commands/capabilities.js +34 -0
- package/lib/commands/chat.js +295 -0
- package/lib/commands/claude.js +380 -0
- package/lib/commands/config-cmd.js +106 -0
- package/lib/commands/consent.js +84 -0
- package/lib/commands/contacts.js +1016 -0
- package/lib/commands/contactsSelftest.js +132 -0
- package/lib/commands/conversation.js +105 -0
- package/lib/commands/dashboard.js +43 -0
- package/lib/commands/department.js +96 -0
- package/lib/commands/dev.js +620 -0
- package/lib/commands/devResident.js +326 -0
- package/lib/commands/devSupervisor.js +1062 -0
- package/lib/commands/discord.js +132 -0
- package/lib/commands/doctor.js +181 -0
- package/lib/commands/domain.js +114 -0
- package/lib/commands/done.js +347 -0
- package/lib/commands/engagement.js +597 -0
- package/lib/commands/entity.js +119 -0
- package/lib/commands/facebook.js +212 -0
- package/lib/commands/fetchAllowlist.js +71 -0
- package/lib/commands/file.js +165 -0
- package/lib/commands/fleet.js +1189 -0
- package/lib/commands/governance.js +647 -0
- package/lib/commands/gripe.js +355 -0
- package/lib/commands/hat.js +374 -0
- package/lib/commands/helpers.js +96 -0
- package/lib/commands/hyperion.js +58 -0
- package/lib/commands/inbox.js +173 -0
- package/lib/commands/instagram.js +264 -0
- package/lib/commands/integration.js +100 -0
- package/lib/commands/inventory.js +115 -0
- package/lib/commands/invites.js +45 -0
- package/lib/commands/licence.js +139 -0
- package/lib/commands/linkedin.js +178 -0
- package/lib/commands/llm-policy.js +117 -0
- package/lib/commands/llm.js +45 -0
- package/lib/commands/lucid.js +597 -0
- package/lib/commands/mail.js +531 -0
- package/lib/commands/memory.js +361 -0
- package/lib/commands/mind.js +71 -0
- package/lib/commands/mon.js +581 -0
- package/lib/commands/monitoring.js +86 -0
- package/lib/commands/motion.js +22 -0
- package/lib/commands/notes.js +1246 -0
- package/lib/commands/notesBatch.js +160 -0
- package/lib/commands/notesBridges.js +56 -0
- package/lib/commands/notesLinks.js +60 -0
- package/lib/commands/notification.js +57 -0
- package/lib/commands/nucleus.js +123 -0
- package/lib/commands/objective.js +240 -0
- package/lib/commands/offload.js +89 -0
- package/lib/commands/onboard.js +329 -0
- package/lib/commands/open.js +56 -0
- package/lib/commands/org.js +276 -0
- package/lib/commands/peek.js +28 -0
- package/lib/commands/plan.js +944 -0
- package/lib/commands/plugin-doctor.js +1091 -0
- package/lib/commands/plugin.js +649 -0
- package/lib/commands/policy.js +78 -0
- package/lib/commands/powers.js +296 -0
- package/lib/commands/presence.js +89 -0
- package/lib/commands/prompt.js +350 -0
- package/lib/commands/provider.js +159 -0
- package/lib/commands/qlarity.js +706 -0
- package/lib/commands/quoxbox.js +270 -0
- package/lib/commands/quoxchat.js +275 -0
- package/lib/commands/quoxseo.js +378 -0
- package/lib/commands/reach.js +159 -0
- package/lib/commands/role.js +286 -0
- package/lib/commands/router.js +77 -0
- package/lib/commands/rows.js +358 -0
- package/lib/commands/run.js +187 -0
- package/lib/commands/safety.js +107 -0
- package/lib/commands/scim.js +88 -0
- package/lib/commands/scope.js +58 -0
- package/lib/commands/security.js +157 -0
- package/lib/commands/server.js +292 -0
- package/lib/commands/service.js +89 -0
- package/lib/commands/settings.js +99 -0
- package/lib/commands/setup.js +569 -0
- package/lib/commands/skillManifest.js +113 -0
- package/lib/commands/skillRightsFormat.js +38 -0
- package/lib/commands/skills.js +687 -0
- package/lib/commands/slot.js +1451 -0
- package/lib/commands/sso.js +229 -0
- package/lib/commands/status.js +137 -0
- package/lib/commands/tag.js +91 -0
- package/lib/commands/team.js +142 -0
- package/lib/commands/tg.js +240 -0
- package/lib/commands/tiktok.js +218 -0
- package/lib/commands/tips.js +23 -0
- package/lib/commands/tool.js +304 -0
- package/lib/commands/trace.js +530 -0
- package/lib/commands/trigger.js +223 -0
- package/lib/commands/update.js +46 -0
- package/lib/commands/vault.js +1447 -0
- package/lib/commands/vm.js +237 -0
- package/lib/commands/voice.js +213 -0
- package/lib/commands/volt.js +570 -0
- package/lib/commands/walkthrough.js +32 -0
- package/lib/commands/watch.js +167 -0
- package/lib/commands/webhook.js +137 -0
- package/lib/commands/welcome.js +14 -0
- package/lib/commands/workflow.js +660 -0
- package/lib/commands/x.js +448 -0
- package/lib/core/actingAs.js +136 -0
- package/lib/core/activeSummary.js +186 -0
- package/lib/core/aee.js +53 -0
- package/lib/core/agentAlias.js +163 -0
- package/lib/core/approvalContext.js +61 -0
- package/lib/core/aside.js +54 -0
- package/lib/core/askDecision.js +60 -0
- package/lib/core/auth.js +501 -0
- package/lib/core/banner.js +143 -0
- package/lib/core/brainPrime.js +90 -0
- package/lib/core/callerSource.js +129 -0
- package/lib/core/claudeLs.js +94 -0
- package/lib/core/cliBuild.js +62 -0
- package/lib/core/client.js +693 -0
- package/lib/core/commandRegistrars.js +121 -0
- package/lib/core/completions.js +163 -0
- package/lib/core/config.js +669 -0
- package/lib/core/confirm.js +37 -0
- package/lib/core/customHats.js +168 -0
- package/lib/core/deeplinks.js +76 -0
- package/lib/core/doneEngineFetch.js +227 -0
- package/lib/core/errors.js +441 -0
- package/lib/core/global-flags.js +190 -0
- package/lib/core/governedSession.js +402 -0
- package/lib/core/hyperion.js +102 -0
- package/lib/core/inboxResolution.js +65 -0
- package/lib/core/lazyCommands.js +122 -0
- package/lib/core/liveSessionsReport.js +112 -0
- package/lib/core/offload.js +504 -0
- package/lib/core/org-override.js +52 -0
- package/lib/core/orgResolve.js +70 -0
- package/lib/core/output.js +239 -0
- package/lib/core/peek.js +126 -0
- package/lib/core/prodEnv.js +7 -0
- package/lib/core/profileUsers.js +51 -0
- package/lib/core/promptCancel.js +18 -0
- package/lib/core/quoxglyph.js +158 -0
- package/lib/core/repoPath.js +11 -0
- package/lib/core/residentAlarm.js +282 -0
- package/lib/core/residentAuth.js +243 -0
- package/lib/core/residentPump.js +229 -0
- package/lib/core/residentSeed.js +106 -0
- package/lib/core/rootOptions.js +39 -0
- package/lib/core/router.js +168 -0
- package/lib/core/selfUpdate.js +188 -0
- package/lib/core/sessionHeartbeat.js +192 -0
- package/lib/core/sessionsOverview.js +224 -0
- package/lib/core/slotKeeper.js +527 -0
- package/lib/core/slotWake.js +120 -0
- package/lib/core/supervisorEngine.js +933 -0
- package/lib/core/systemdInstaller.js +256 -0
- package/lib/core/version.js +87 -0
- package/lib/core/vm.js +361 -0
- package/lib/core/vmTui.js +86 -0
- package/lib/core/walkthrough.js +35 -0
- package/lib/hyperion/deck.js +29 -0
- package/lib/lucid/LucidCard.jsx +68 -0
- package/lib/lucid/LucidIntro.jsx +92 -0
- package/lib/lucid/blind.js +71 -0
- package/lib/lucid/cards.js +86 -0
- package/lib/lucid/deck.js +32 -0
- package/lib/lucid/fmt.js +139 -0
- package/lib/lucid/markdown.js +81 -0
- package/lib/lucid/motion.js +56 -0
- package/lib/lucid/sitrep.js +173 -0
- package/lib/plugins/loader.js +93 -0
- package/lib/quoxon/activity.js +116 -0
- package/lib/quoxon/aocl.js +117 -0
- package/lib/quoxon/api.js +952 -0
- package/lib/quoxon/app.js +4032 -0
- package/lib/quoxon/approvalFacts.js +94 -0
- package/lib/quoxon/approvalsView.js +325 -0
- package/lib/quoxon/asideView.js +40 -0
- package/lib/quoxon/ask.js +121 -0
- package/lib/quoxon/away.js +52 -0
- package/lib/quoxon/bang.js +224 -0
- package/lib/quoxon/bulkRisk.js +17 -0
- package/lib/quoxon/capabilities.js +82 -0
- package/lib/quoxon/cells.js +53 -0
- package/lib/quoxon/commandShort.js +112 -0
- package/lib/quoxon/commands.js +479 -0
- package/lib/quoxon/connect.js +654 -0
- package/lib/quoxon/connectCard.js +45 -0
- package/lib/quoxon/consent.js +86 -0
- package/lib/quoxon/context.js +68 -0
- package/lib/quoxon/copy.js +34 -0
- package/lib/quoxon/countdownLine.js +11 -0
- package/lib/quoxon/demo.autoplay.js +29 -0
- package/lib/quoxon/demo.fixtures.js +24 -0
- package/lib/quoxon/demo.js +76 -0
- package/lib/quoxon/devObserver.js +20 -0
- package/lib/quoxon/dividerAocl.js +191 -0
- package/lib/quoxon/dividerRule.js +57 -0
- package/lib/quoxon/dragonModes.js +150 -0
- package/lib/quoxon/dragonView.js +41 -0
- package/lib/quoxon/earlyInput.js +40 -0
- package/lib/quoxon/echo.js +15 -0
- package/lib/quoxon/egg.js +36 -0
- package/lib/quoxon/events.js +677 -0
- package/lib/quoxon/feedback.js +50 -0
- package/lib/quoxon/gallery.js +237 -0
- package/lib/quoxon/handoffOffer.js +78 -0
- package/lib/quoxon/hatSwitch.js +37 -0
- package/lib/quoxon/headless.js +161 -0
- package/lib/quoxon/hostUrls.js +41 -0
- package/lib/quoxon/indicator.js +197 -0
- package/lib/quoxon/intent.js +52 -0
- package/lib/quoxon/keys.js +164 -0
- package/lib/quoxon/launcher.js +103 -0
- package/lib/quoxon/main.js +176 -0
- package/lib/quoxon/markdown.js +341 -0
- package/lib/quoxon/markdownSettle.js +19 -0
- package/lib/quoxon/matrixDomains.json +46 -0
- package/lib/quoxon/mentions.js +90 -0
- package/lib/quoxon/mind.js +103 -0
- package/lib/quoxon/mode.js +46 -0
- package/lib/quoxon/model.js +311 -0
- package/lib/quoxon/modelPrefs.js +345 -0
- package/lib/quoxon/motion/clock.js +70 -0
- package/lib/quoxon/motion/color.js +35 -0
- package/lib/quoxon/motion/frame.js +14 -0
- package/lib/quoxon/motion/level.js +91 -0
- package/lib/quoxon/motion/reveal.js +54 -0
- package/lib/quoxon/motion/ring.js +79 -0
- package/lib/quoxon/mouse.js +211 -0
- package/lib/quoxon/noai.js +57 -0
- package/lib/quoxon/objects/agent.js +61 -0
- package/lib/quoxon/objects/away.js +72 -0
- package/lib/quoxon/objects/crystal.js +100 -0
- package/lib/quoxon/objects/fetch.js +182 -0
- package/lib/quoxon/objects/fleet.js +149 -0
- package/lib/quoxon/objects/health.js +186 -0
- package/lib/quoxon/objects/index.js +106 -0
- package/lib/quoxon/objects/ladder.js +71 -0
- package/lib/quoxon/objects/memory.js +44 -0
- package/lib/quoxon/objects/mirror.js +137 -0
- package/lib/quoxon/objects/model.js +118 -0
- package/lib/quoxon/objects/peek.js +17 -0
- package/lib/quoxon/objects/proof.js +110 -0
- package/lib/quoxon/objects/prove.js +130 -0
- package/lib/quoxon/objects/replay.js +125 -0
- package/lib/quoxon/objects/sitrep.js +58 -0
- package/lib/quoxon/objects/skill.js +105 -0
- package/lib/quoxon/objects/view.js +87 -0
- package/lib/quoxon/objects/workflow.js +119 -0
- package/lib/quoxon/observers.js +42 -0
- package/lib/quoxon/onboarding/copy.js +263 -0
- package/lib/quoxon/onboarding/credential.js +108 -0
- package/lib/quoxon/onboarding/detect.js +22 -0
- package/lib/quoxon/onboarding/dockerOffer.js +45 -0
- package/lib/quoxon/onboarding/failureCause.js +33 -0
- package/lib/quoxon/onboarding/finish.js +134 -0
- package/lib/quoxon/onboarding/index.js +94 -0
- package/lib/quoxon/onboarding/installRunner.js +284 -0
- package/lib/quoxon/onboarding/intent.js +53 -0
- package/lib/quoxon/onboarding/journey.js +73 -0
- package/lib/quoxon/onboarding/preflight.js +156 -0
- package/lib/quoxon/onboarding/probe.js +65 -0
- package/lib/quoxon/onboarding/runner.js +58 -0
- package/lib/quoxon/onboarding/view.js +682 -0
- package/lib/quoxon/orgLabel.js +10 -0
- package/lib/quoxon/orgSwitch.js +33 -0
- package/lib/quoxon/ownBroadcast.js +22 -0
- package/lib/quoxon/palette.js +43 -0
- package/lib/quoxon/print.js +98 -0
- package/lib/quoxon/profileSwitch.js +53 -0
- package/lib/quoxon/promptHistory.js +41 -0
- package/lib/quoxon/providers.js +48 -0
- package/lib/quoxon/qart.js +348 -0
- package/lib/quoxon/qdragon.js +410 -0
- package/lib/quoxon/qdragonFly.js +61 -0
- package/lib/quoxon/qdragonScenes.js +282 -0
- package/lib/quoxon/qeyes.js +213 -0
- package/lib/quoxon/qglyph.js +143 -0
- package/lib/quoxon/qhello.js +58 -0
- package/lib/quoxon/qmotion.js +132 -0
- package/lib/quoxon/render.js +1167 -0
- package/lib/quoxon/resend.js +72 -0
- package/lib/quoxon/roster.js +307 -0
- package/lib/quoxon/route.js +39 -0
- package/lib/quoxon/rows.js +711 -0
- package/lib/quoxon/rowsStore.js +80 -0
- package/lib/quoxon/rules.js +130 -0
- package/lib/quoxon/screenContext.js +150 -0
- package/lib/quoxon/screenFrames.js +254 -0
- package/lib/quoxon/session.js +238 -0
- package/lib/quoxon/sessionDead.js +17 -0
- package/lib/quoxon/signin.js +125 -0
- package/lib/quoxon/skills.js +30 -0
- package/lib/quoxon/slash/agents.js +112 -0
- package/lib/quoxon/slash/argSources.js +65 -0
- package/lib/quoxon/slash/args.js +65 -0
- package/lib/quoxon/slash/automate.js +89 -0
- package/lib/quoxon/slash/broadcast.js +140 -0
- package/lib/quoxon/slash/broadcastRun.js +108 -0
- package/lib/quoxon/slash/card.js +30 -0
- package/lib/quoxon/slash/challenge.js +114 -0
- package/lib/quoxon/slash/cliCommand.js +53 -0
- package/lib/quoxon/slash/cliLeaves.json +948 -0
- package/lib/quoxon/slash/compact.js +90 -0
- package/lib/quoxon/slash/confirm.js +30 -0
- package/lib/quoxon/slash/crystallize.js +69 -0
- package/lib/quoxon/slash/dashboard.js +136 -0
- package/lib/quoxon/slash/draft.js +54 -0
- package/lib/quoxon/slash/hatWalk.js +206 -0
- package/lib/quoxon/slash/inverses.js +77 -0
- package/lib/quoxon/slash/killer.js +24 -0
- package/lib/quoxon/slash/killerApi.js +16 -0
- package/lib/quoxon/slash/ledger.js +88 -0
- package/lib/quoxon/slash/listView.js +30 -0
- package/lib/quoxon/slash/modelCmd.js +261 -0
- package/lib/quoxon/slash/palette.js +118 -0
- package/lib/quoxon/slash/paletteController.js +169 -0
- package/lib/quoxon/slash/panels.js +116 -0
- package/lib/quoxon/slash/picker.js +56 -0
- package/lib/quoxon/slash/restart.js +202 -0
- package/lib/quoxon/slash/resume.js +59 -0
- package/lib/quoxon/slash/rowCmd.js +157 -0
- package/lib/quoxon/slash/rowWalk.js +175 -0
- package/lib/quoxon/slash/settings.js +60 -0
- package/lib/quoxon/slash/spawn.js +177 -0
- package/lib/quoxon/slash/stepUp.js +274 -0
- package/lib/quoxon/slash/stepUpCard.js +60 -0
- package/lib/quoxon/slash/stepUpCmds.js +78 -0
- package/lib/quoxon/slash/undoApi.js +38 -0
- package/lib/quoxon/slash/undoCmd.js +49 -0
- package/lib/quoxon/slash/undoWish.js +15 -0
- package/lib/quoxon/slash/watch.js +164 -0
- package/lib/quoxon/slash/wish.js +23 -0
- package/lib/quoxon/slash/wishCmd.js +32 -0
- package/lib/quoxon/slotChat.js +300 -0
- package/lib/quoxon/slotFormat.js +195 -0
- package/lib/quoxon/slotRun.js +131 -0
- package/lib/quoxon/sound/index.js +186 -0
- package/lib/quoxon/sound/mapping.js +120 -0
- package/lib/quoxon/sound/output.js +52 -0
- package/lib/quoxon/sound/synth.js +122 -0
- package/lib/quoxon/stray.js +22 -0
- package/lib/quoxon/suggestCommand.js +59 -0
- package/lib/quoxon/term.js +141 -0
- package/lib/quoxon/textBuffer.js +416 -0
- package/lib/quoxon/theme.js +286 -0
- package/lib/quoxon/tips.js +433 -0
- package/lib/quoxon/toolError.js +41 -0
- package/lib/quoxon/transcript.js +188 -0
- package/lib/quoxon/web/qface.js +89 -0
- package/lib/quoxon/welcome.js +52 -0
- package/lib/quoxon/whatsnew.js +136 -0
- package/lib/quoxon/whatsnew.jsonl +89 -0
- package/lib/quoxon/windowOrg.js +113 -0
- package/lib/server/diag.js +129 -0
- package/lib/server/doctor.js +71 -0
- package/lib/server/install.js +149 -0
- package/lib/server/pluginEnable.js +161 -0
- package/lib/server/skew.js +56 -0
- package/lib/server/snapshot.js +131 -0
- package/lib/server/status.js +128 -0
- package/lib/server/sys.js +65 -0
- package/lib/server/uninstall.js +63 -0
- package/lib/server/update.js +234 -0
- package/lib/toolOutputShape.js +315 -0
- package/lib/tui/app.jsx +289 -0
- package/lib/tui/components/Breadcrumb.jsx +42 -0
- package/lib/tui/components/ChatInput.jsx +68 -0
- package/lib/tui/components/Confirm.jsx +32 -0
- package/lib/tui/components/DataTable.jsx +270 -0
- package/lib/tui/components/DetailPanel.jsx +241 -0
- package/lib/tui/components/HelpOverlay.jsx +67 -0
- package/lib/tui/components/Layout.jsx +129 -0
- package/lib/tui/components/Palette.jsx +141 -0
- package/lib/tui/components/SearchInput.jsx +125 -0
- package/lib/tui/components/Sparkline.jsx +55 -0
- package/lib/tui/components/StatusBar.jsx +133 -0
- package/lib/tui/components/Toast.jsx +52 -0
- package/lib/tui/hooks/useApi.js +44 -0
- package/lib/tui/hooks/useHealth.js +90 -0
- package/lib/tui/hooks/usePolledApi.js +86 -0
- package/lib/tui/hooks/useTerminalSize.js +46 -0
- package/lib/tui/index.js +56 -0
- package/lib/tui/intro/Intro.jsx +332 -0
- package/lib/tui/jsx-loader.js +32 -0
- package/lib/tui/keys.js +87 -0
- package/lib/tui/registry.js +49 -0
- package/lib/tui/theme.js +103 -0
- package/lib/tui/views/AdminView.jsx +398 -0
- package/lib/tui/views/AgentView.jsx +204 -0
- package/lib/tui/views/BackupView.jsx +225 -0
- package/lib/tui/views/BrainView.jsx +223 -0
- package/lib/tui/views/ChatView.jsx +468 -0
- package/lib/tui/views/FilesView.jsx +218 -0
- package/lib/tui/views/FleetView.jsx +234 -0
- package/lib/tui/views/GovernanceView.jsx +453 -0
- package/lib/tui/views/HealthView.jsx +216 -0
- package/lib/tui/views/HyperionDeck.jsx +79 -0
- package/lib/tui/views/InboxView.jsx +228 -0
- package/lib/tui/views/LucidDeck.jsx +719 -0
- package/lib/tui/views/MainMenu.jsx +123 -0
- package/lib/tui/views/MemoryView.jsx +377 -0
- package/lib/tui/views/ObjectivesView.jsx +230 -0
- package/lib/tui/views/OrgView.jsx +229 -0
- package/lib/tui/views/ToolView.jsx +221 -0
- package/lib/tui/views/VaultView.jsx +422 -0
- package/lib/tui/views/WorkflowView.jsx +329 -0
- package/package.json +75 -4
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backup commands: CRUD, verify, restore, schedule
|
|
3
|
+
*
|
|
4
|
+
* TWO LANES, deliberately distinct (G2d slice 3):
|
|
5
|
+
* `quox backup …` — the per-ORG tenant lane (one org's data).
|
|
6
|
+
* `quox backup server …` — the SERVER-WIDE lane: the whole box, every org,
|
|
7
|
+
* instance-admin only, executed by the governed
|
|
8
|
+
* host-side runner. Its restore is the most
|
|
9
|
+
* destructive verb in the product, so it is
|
|
10
|
+
* dry-run by default and needs both --execute and
|
|
11
|
+
* an interactive confirmation.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import chalk from 'chalk';
|
|
15
|
+
import { createHash } from 'crypto';
|
|
16
|
+
import { createWriteStream } from 'fs';
|
|
17
|
+
import { Readable } from 'stream';
|
|
18
|
+
import { pipeline } from 'stream/promises';
|
|
19
|
+
import * as path from 'path';
|
|
20
|
+
import { formatOutput, formatDetail, printSuccess, printInfo, printWarning } from '../core/output.js';
|
|
21
|
+
import { resolveOrgId } from './helpers.js';
|
|
22
|
+
import { resolveEndpoint } from '../api/endpoints.js';
|
|
23
|
+
|
|
24
|
+
export function registerBackupCommands(program, ctx) {
|
|
25
|
+
const { client, auth } = ctx;
|
|
26
|
+
const sleep = ctx.sleep || ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
27
|
+
|
|
28
|
+
const backup = program
|
|
29
|
+
.command('backup')
|
|
30
|
+
.description('Manage backups');
|
|
31
|
+
|
|
32
|
+
backup
|
|
33
|
+
.command('list')
|
|
34
|
+
.description('List backups')
|
|
35
|
+
.option('--limit <n>', 'max results', '20')
|
|
36
|
+
.action(async (options) => {
|
|
37
|
+
auth.requireAuth();
|
|
38
|
+
const orgId = resolveOrgId(auth, program);
|
|
39
|
+
const data = await client.get(resolveEndpoint('backups.list', { orgId }).path, { service: resolveEndpoint('backups.list', { orgId }).service, query: { limit: options.limit } });
|
|
40
|
+
formatOutput({
|
|
41
|
+
// fleet #392: backups has name/backup_type/archive_size_bytes.
|
|
42
|
+
columns: ['id', 'name', 'backup_type', 'archive_size_bytes', 'status', 'created_at'],
|
|
43
|
+
headers: ['ID', 'Name', 'Type', 'Size (bytes)', 'Status', 'Created'],
|
|
44
|
+
rows: data.items || data.backups || data,
|
|
45
|
+
}, { format: program.opts().output });
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
backup
|
|
49
|
+
.command('get')
|
|
50
|
+
.description('Get backup details')
|
|
51
|
+
.argument('<backupId>', 'backup ID')
|
|
52
|
+
.action(async (backupId) => {
|
|
53
|
+
auth.requireAuth();
|
|
54
|
+
const orgId = resolveOrgId(auth, program);
|
|
55
|
+
const data = await client.get(resolveEndpoint('backups.get', { orgId, backupId }).path, { service: resolveEndpoint('backups.get', { orgId, backupId }).service });
|
|
56
|
+
formatDetail(data.backup || data, { format: program.opts().output });
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
backup
|
|
60
|
+
.command('create')
|
|
61
|
+
.description('Create a backup')
|
|
62
|
+
.option('--label <label>', 'backup label (stored as the backup name)')
|
|
63
|
+
.option('--type <type>', 'backup type: full, quick, selective', 'full')
|
|
64
|
+
.option('--components <list>', 'comma-separated components to include')
|
|
65
|
+
.action(async (options) => {
|
|
66
|
+
auth.requireAuth();
|
|
67
|
+
const orgId = resolveOrgId(auth, program);
|
|
68
|
+
// #1017: the server reads backup_type and name (services/auth/routes/backups.js); type/label were dropped,
|
|
69
|
+
// and a type outside the backups.backup_type CHECK would only fail later inside the server.
|
|
70
|
+
const TYPES = ['full', 'quick', 'selective'];
|
|
71
|
+
if (!TYPES.includes(options.type)) throw new Error(`--type must be one of: ${TYPES.join(', ')}`);
|
|
72
|
+
const body = { backup_type: options.type };
|
|
73
|
+
if (options.label) body.name = options.label;
|
|
74
|
+
if (options.components) body.components = options.components.split(',').map(c => c.trim());
|
|
75
|
+
|
|
76
|
+
const ora = (await import('ora')).default;
|
|
77
|
+
const spinner = ora('Creating backup...').start();
|
|
78
|
+
try {
|
|
79
|
+
const data = await client.post(resolveEndpoint('backups.create', { orgId }).path, { service: resolveEndpoint('backups.create', { orgId }).service, body, timeout: 300000 });
|
|
80
|
+
spinner.succeed('Backup created');
|
|
81
|
+
if (data.backup) formatDetail(data.backup, { format: program.opts().output });
|
|
82
|
+
} catch (err) {
|
|
83
|
+
spinner.fail('Backup failed');
|
|
84
|
+
throw err;
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
backup
|
|
89
|
+
.command('delete')
|
|
90
|
+
.description('Delete a backup')
|
|
91
|
+
.argument('<backupId>', 'backup ID')
|
|
92
|
+
.action(async (backupId) => {
|
|
93
|
+
auth.requireAuth();
|
|
94
|
+
const orgId = resolveOrgId(auth, program);
|
|
95
|
+
await client.delete(resolveEndpoint('backups.delete', { orgId, backupId }).path, { service: resolveEndpoint('backups.delete', { orgId, backupId }).service });
|
|
96
|
+
printSuccess('Backup deleted.');
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
backup
|
|
100
|
+
.command('verify')
|
|
101
|
+
.description('Verify backup integrity')
|
|
102
|
+
.argument('<backupId>', 'backup ID')
|
|
103
|
+
.action(async (backupId) => {
|
|
104
|
+
auth.requireAuth();
|
|
105
|
+
const orgId = resolveOrgId(auth, program);
|
|
106
|
+
const data = await client.post(resolveEndpoint('backups.verify', { orgId, backupId }).path, { service: resolveEndpoint('backups.verify', { orgId, backupId }).service });
|
|
107
|
+
let result = data;
|
|
108
|
+
// The auth route verifies ASYNC ("Verification started", status verifying) and
|
|
109
|
+
// writes the outcome to the backup row. Reading `valid` off the start reply
|
|
110
|
+
// reported "failed: unknown" for a backup that went on to verify cleanly.
|
|
111
|
+
if (data && data.valid === undefined && data.status === 'verifying') {
|
|
112
|
+
const ep = resolveEndpoint('backups.get', { orgId, backupId });
|
|
113
|
+
const deadline = Date.now() + 30 * 60 * 1000;
|
|
114
|
+
for (;;) {
|
|
115
|
+
const g = await client.get(ep.path, { service: ep.service });
|
|
116
|
+
const b = (g && g.backup) || g || {};
|
|
117
|
+
if (b.status && b.status !== 'verifying') {
|
|
118
|
+
let v = null;
|
|
119
|
+
try { v = b.verification_json ? JSON.parse(b.verification_json) : (b.verification || null); } catch { v = null; }
|
|
120
|
+
result = { valid: b.status === 'verified' && (!v || v.valid !== false), errors: v && (v.errors || (v.mismatches && v.mismatches.length ? v.mismatches : undefined)), status: b.status };
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
if (Date.now() > deadline) throw new Error('Backup verification still running after 30 minutes; check `quox backup get ' + backupId + '`');
|
|
124
|
+
await sleep(5000);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (result.valid) {
|
|
128
|
+
printSuccess('Backup is valid.');
|
|
129
|
+
} else {
|
|
130
|
+
const detail = result.errors ? JSON.stringify(result.errors) : (result.status ? `status ${result.status}` : 'unknown');
|
|
131
|
+
throw new Error(`Backup verification failed: ${detail}`);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
backup
|
|
136
|
+
.command('restore')
|
|
137
|
+
.description('Restore from a backup')
|
|
138
|
+
.argument('<backupId>', 'backup ID')
|
|
139
|
+
.option('--dry-run', 'show what would be restored without doing it')
|
|
140
|
+
.option('--components <list>', 'comma-separated components to restore')
|
|
141
|
+
.action(async (backupId, options) => {
|
|
142
|
+
auth.requireAuth();
|
|
143
|
+
const orgId = resolveOrgId(auth, program);
|
|
144
|
+
const body = {};
|
|
145
|
+
if (options.dryRun) body.dry_run = true;
|
|
146
|
+
if (options.components) body.components = options.components.split(',').map(c => c.trim());
|
|
147
|
+
|
|
148
|
+
if (options.dryRun) {
|
|
149
|
+
printInfo('DRY RUN - No changes will be made');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const ora = (await import('ora')).default;
|
|
153
|
+
const spinner = ora('Restoring...').start();
|
|
154
|
+
try {
|
|
155
|
+
const data = await client.post(resolveEndpoint('backups.restore', { orgId, backupId }).path, { service: resolveEndpoint('backups.restore', { orgId, backupId }).service, body, timeout: 300000 });
|
|
156
|
+
spinner.succeed('Restore complete');
|
|
157
|
+
if (data.restore) formatDetail(data.restore, { format: program.opts().output });
|
|
158
|
+
} catch (err) {
|
|
159
|
+
spinner.fail('Restore failed');
|
|
160
|
+
throw err;
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// Schedule subcommand
|
|
165
|
+
const schedule = backup
|
|
166
|
+
.command('schedule')
|
|
167
|
+
.description('Manage backup schedules');
|
|
168
|
+
|
|
169
|
+
schedule
|
|
170
|
+
.command('list')
|
|
171
|
+
.description('List backup schedules')
|
|
172
|
+
.action(async () => {
|
|
173
|
+
auth.requireAuth();
|
|
174
|
+
const orgId = resolveOrgId(auth, program);
|
|
175
|
+
const data = await client.get(resolveEndpoint('backup-schedules.list', { orgId }).path, { service: resolveEndpoint('backup-schedules.list', { orgId }).service });
|
|
176
|
+
formatOutput({
|
|
177
|
+
// fleet #392: backup_schedules has cron_expression/backup_type/next_run_at.
|
|
178
|
+
columns: ['id', 'name', 'cron_expression', 'backup_type', 'enabled', 'next_run_at'],
|
|
179
|
+
headers: ['ID', 'Name', 'Cron', 'Type', 'Enabled', 'Next Run'],
|
|
180
|
+
rows: data.schedules || [data.schedule].filter(Boolean) || data,
|
|
181
|
+
}, { format: program.opts().output });
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
schedule
|
|
185
|
+
.command('create')
|
|
186
|
+
.description('Create a backup schedule')
|
|
187
|
+
.requiredOption('--name <name>', 'schedule name')
|
|
188
|
+
.requiredOption('--cron <expr>', 'cron expression')
|
|
189
|
+
.option('--type <type>', 'backup type', 'full')
|
|
190
|
+
.option('--retention <days>', 'retention in days', '30')
|
|
191
|
+
.action(async (options) => {
|
|
192
|
+
auth.requireAuth();
|
|
193
|
+
const orgId = resolveOrgId(auth, program);
|
|
194
|
+
// Field names match services/auth/routes/backups.js POST /orgs/:orgId/backup-schedules
|
|
195
|
+
// (name required; cron -> cron_expression; type -> backup_type).
|
|
196
|
+
await client.post(resolveEndpoint('backup-schedules.create', { orgId }).path, {
|
|
197
|
+
service: resolveEndpoint('backup-schedules.create', { orgId }).service,
|
|
198
|
+
body: {
|
|
199
|
+
name: options.name,
|
|
200
|
+
cron_expression: options.cron,
|
|
201
|
+
backup_type: options.type,
|
|
202
|
+
retention_days: parseInt(options.retention, 10),
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
printSuccess('Backup schedule created.');
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// ── `quox backup server …` — the instance-admin, SERVER-WIDE lane ────────
|
|
209
|
+
//
|
|
210
|
+
// Style-matched to `quox build` (lib/commands/build.js): the dispatch verbs
|
|
211
|
+
// say plainly that a 200 is a QUEUE acknowledgement and not a finished job,
|
|
212
|
+
// and every read verb names which half of the picture it is showing.
|
|
213
|
+
//
|
|
214
|
+
// Every route behind these verbs is instance-admin gated server-side
|
|
215
|
+
// (services/auth/routes/admin-backups.js); nothing here re-implements that
|
|
216
|
+
// check, it just surfaces the refusal honestly.
|
|
217
|
+
const server = backup
|
|
218
|
+
.command('server')
|
|
219
|
+
.description('Server-wide backup/restore (whole box, every org; instance admin only)');
|
|
220
|
+
|
|
221
|
+
server
|
|
222
|
+
.command('create')
|
|
223
|
+
.description('Dispatch a server-wide backup on the configured runner host')
|
|
224
|
+
.option('--mode <mode>', 'backup mode: full, quick', 'full')
|
|
225
|
+
.action(async (options) => {
|
|
226
|
+
auth.requireAuth();
|
|
227
|
+
if (!['full', 'quick'].includes(options.mode)) {
|
|
228
|
+
throw new Error(`--mode must be one of: full, quick (got "${options.mode}")`);
|
|
229
|
+
}
|
|
230
|
+
const endpoint = resolveEndpoint('backups.server.create');
|
|
231
|
+
const data = await client.post(endpoint.path, {
|
|
232
|
+
service: endpoint.service,
|
|
233
|
+
body: { mode: options.mode },
|
|
234
|
+
});
|
|
235
|
+
formatDetail(data, { format: program.opts().output, title: 'Server-wide backup dispatched' });
|
|
236
|
+
printSuccess(`${options.mode} backup queued on ${data.runner_host || 'the runner host'}.`);
|
|
237
|
+
printWarning('Queued is not backed up: a 200 here is the dispatch acknowledgement only. '
|
|
238
|
+
+ 'Check `quox backup server status` and the receipt before claiming the box is backed up.');
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
server
|
|
242
|
+
.command('status')
|
|
243
|
+
.description('Runner readiness and live state, plus the latest durable receipts')
|
|
244
|
+
.action(async () => {
|
|
245
|
+
auth.requireAuth();
|
|
246
|
+
const endpoint = resolveEndpoint('backups.server.status');
|
|
247
|
+
const data = await client.get(endpoint.path, { service: endpoint.service });
|
|
248
|
+
formatDetail(data.runner || {}, {
|
|
249
|
+
format: program.opts().output,
|
|
250
|
+
title: `Runner state: ${data.runner_host || 'unknown host'}`,
|
|
251
|
+
});
|
|
252
|
+
if (data.receipts_error) {
|
|
253
|
+
// Never render a clean board when a half could not be read.
|
|
254
|
+
printWarning(`Receipts could not be read: ${data.receipts_error}`);
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
formatOutput(data.receipts || [], {
|
|
258
|
+
format: program.opts().output,
|
|
259
|
+
columns: ['created_at', 'kind', 'result', 'host', 'archive_id', 'archive_size_bytes', 'duration_seconds'],
|
|
260
|
+
emptyMessage: 'No backup receipts recorded yet.',
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
server
|
|
265
|
+
.command('list')
|
|
266
|
+
.description('Archives the runner host has registered')
|
|
267
|
+
.action(async () => {
|
|
268
|
+
auth.requireAuth();
|
|
269
|
+
const endpoint = resolveEndpoint('backups.server.list');
|
|
270
|
+
const data = await client.get(endpoint.path, { service: endpoint.service });
|
|
271
|
+
const rows = (data.archives || []).map((a) => ({
|
|
272
|
+
id: a.id,
|
|
273
|
+
size_bytes: a.size_bytes,
|
|
274
|
+
created_at: a.created_at,
|
|
275
|
+
sha256: typeof a.sha256 === 'string' ? `${a.sha256.replace(/^sha256:/, '').slice(0, 12)}…` : '-',
|
|
276
|
+
}));
|
|
277
|
+
formatOutput(rows, {
|
|
278
|
+
format: program.opts().output,
|
|
279
|
+
columns: ['id', 'size_bytes', 'created_at', 'sha256'],
|
|
280
|
+
headers: ['Archive ID', 'Size (bytes)', 'Created', 'SHA-256'],
|
|
281
|
+
emptyMessage: 'No archives registered on the runner host.',
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
server
|
|
286
|
+
.command('download')
|
|
287
|
+
.description('Download a server-wide archive to a local file')
|
|
288
|
+
.argument('<archiveId>', 'archive id from `quox backup server list`')
|
|
289
|
+
.option('--out <path>', 'output file (default ./<archiveId>.tar.gz)')
|
|
290
|
+
.action(async (archiveId, options) => {
|
|
291
|
+
auth.requireAuth();
|
|
292
|
+
const endpoint = resolveEndpoint('backups.server.download', { archiveId });
|
|
293
|
+
const res = await client.get(endpoint.path, { service: endpoint.service, raw: true, timeout: 1800000 });
|
|
294
|
+
if (!res.ok) {
|
|
295
|
+
let detail = '';
|
|
296
|
+
try { detail = JSON.stringify(await res.json()); } catch { detail = res.statusText; }
|
|
297
|
+
throw new Error(`Download failed with status ${res.status}: ${detail}`);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const outPath = path.resolve(options.out || `./${archiveId.endsWith('.tar.gz') ? archiveId : `${archiveId}.tar.gz`}`);
|
|
301
|
+
// Hash WHAT WAS WRITTEN, not what the server said it would send: the
|
|
302
|
+
// operator needs to compare the bytes on their disk against the
|
|
303
|
+
// archive's registered sha256, and a hash taken anywhere else proves
|
|
304
|
+
// nothing about the file they now hold.
|
|
305
|
+
const hash = createHash('sha256');
|
|
306
|
+
let bytes = 0;
|
|
307
|
+
const sink = createWriteStream(outPath);
|
|
308
|
+
const source = Readable.fromWeb(res.body);
|
|
309
|
+
source.on('data', (chunk) => { bytes += chunk.length; hash.update(chunk); });
|
|
310
|
+
await pipeline(source, sink);
|
|
311
|
+
|
|
312
|
+
printSuccess(`Wrote ${bytes} bytes to ${outPath}`);
|
|
313
|
+
printInfo(`sha256(${path.basename(outPath)}) = ${hash.digest('hex')}`);
|
|
314
|
+
printInfo('Compare that against the SHA-256 column in `quox backup server list` before trusting the copy.');
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
server
|
|
318
|
+
.command('restore')
|
|
319
|
+
.description('Restore the whole box from a server-wide archive (DRY RUN unless --execute)')
|
|
320
|
+
.argument('<archiveId>', 'archive id from `quox backup server list`')
|
|
321
|
+
.option('--execute', 'perform a REAL restore (destroys current data), not a dry run')
|
|
322
|
+
.option('--stores <list>', 'comma-separated store names to restore (default: all in the archive)')
|
|
323
|
+
.action(async (archiveId, options) => {
|
|
324
|
+
auth.requireAuth();
|
|
325
|
+
const body = {};
|
|
326
|
+
if (options.stores) body.stores = options.stores.split(',').map((s) => s.trim()).filter(Boolean);
|
|
327
|
+
|
|
328
|
+
if (!options.execute) {
|
|
329
|
+
// dry_run is left ABSENT rather than sent as true: the engine's own
|
|
330
|
+
// default is dry-run, and asserting a posture the operator did not
|
|
331
|
+
// state is how a real restore eventually happens by accident.
|
|
332
|
+
printInfo('DRY RUN: nothing will be written. Re-run with --execute to restore for real.');
|
|
333
|
+
} else {
|
|
334
|
+
printWarning(`REAL RESTORE of ${archiveId}. This OVERWRITES this instance's data for EVERY org `
|
|
335
|
+
+ 'from the archive. Current data not in the archive is lost.');
|
|
336
|
+
const { confirmDestructive } = await import('../core/confirm.js');
|
|
337
|
+
const ok = await confirmDestructive(
|
|
338
|
+
program,
|
|
339
|
+
options,
|
|
340
|
+
`Restore ${archiveId} over this instance, destroying current data?`,
|
|
341
|
+
);
|
|
342
|
+
if (!ok) {
|
|
343
|
+
printInfo('Aborted. Nothing was dispatched.');
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
body.dry_run = false;
|
|
347
|
+
body.confirm = 'RESTORE';
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
const endpoint = resolveEndpoint('backups.server.restore', { archiveId });
|
|
351
|
+
const data = await client.post(endpoint.path, { service: endpoint.service, body });
|
|
352
|
+
formatDetail(data, { format: program.opts().output, title: `Restore dispatched: ${archiveId}` });
|
|
353
|
+
printWarning('Dispatched, not finished: poll `quox backup server restore-status` for the outcome.');
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
server
|
|
357
|
+
.command('restore-status')
|
|
358
|
+
.description('Live restore-engine state on the runner host, plus recent restore receipts')
|
|
359
|
+
.action(async () => {
|
|
360
|
+
auth.requireAuth();
|
|
361
|
+
const endpoint = resolveEndpoint('backups.server.restoreStatus');
|
|
362
|
+
const data = await client.get(endpoint.path, { service: endpoint.service });
|
|
363
|
+
formatDetail(data.runner || {}, {
|
|
364
|
+
format: program.opts().output,
|
|
365
|
+
title: `Restore engine: ${data.runner_host || 'unknown host'}`,
|
|
366
|
+
});
|
|
367
|
+
if (data.receipts_error) {
|
|
368
|
+
printWarning(`Restore receipts could not be read: ${data.receipts_error}`);
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
formatOutput(data.receipts || [], {
|
|
372
|
+
format: program.opts().output,
|
|
373
|
+
columns: ['created_at', 'result', 'archive_id', 'dry_run', 'host', 'duration_seconds'],
|
|
374
|
+
emptyMessage: 'No restore receipts recorded yet.',
|
|
375
|
+
});
|
|
376
|
+
});
|
|
377
|
+
}
|