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,649 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin commands: org-scoped plugin install registry (PD-1..PD-8)
|
|
3
|
+
*
|
|
4
|
+
* quox plugin list|get|install|update|uninstall|mine
|
|
5
|
+
* quox plugin enable <id> (PLUGIN-IMG #1012: prebuilt private image, licence first)
|
|
6
|
+
* quox plugin data list|get|set|delete
|
|
7
|
+
* quox plugin secrets list|set|reveal|delete
|
|
8
|
+
* quox plugin assign list|add|remove
|
|
9
|
+
* quox plugin trusted-keys list|add|remove
|
|
10
|
+
* quox plugin revocations list|add|remove
|
|
11
|
+
*
|
|
12
|
+
* Backend: services/auth/routes/plugins.js, mounted org-scoped at
|
|
13
|
+
* `/api/orgs/:orgId/...` (server.js). Install/update/uninstall and all
|
|
14
|
+
* secrets writes are admin-only per the PD stream's locked "admin-only
|
|
15
|
+
* install model" decision; read endpoints require org membership only.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { registerPluginDoctor } from './plugin-doctor.js';
|
|
19
|
+
import { readFileSync } from 'node:fs';
|
|
20
|
+
import { formatOutput, formatDetail, printSuccess, printWarning, printInfo } from '../core/output.js';
|
|
21
|
+
import { resolveOrgId, parseJSON } from './helpers.js';
|
|
22
|
+
import { resolveEndpoint } from '../api/endpoints.js';
|
|
23
|
+
import { enablePlugin, entitlementFrom } from '../server/pluginEnable.js';
|
|
24
|
+
import { resolveInstall, readEnvKeys } from '../server/install.js';
|
|
25
|
+
import { createSys } from '../server/sys.js';
|
|
26
|
+
|
|
27
|
+
/** Read + JSON.parse a file, wrapping errors with the file path for context. */
|
|
28
|
+
function readJsonFile(filePath, label) {
|
|
29
|
+
let raw;
|
|
30
|
+
try {
|
|
31
|
+
raw = readFileSync(filePath, 'utf-8');
|
|
32
|
+
} catch (err) {
|
|
33
|
+
throw new Error(`Could not read ${label} file "${filePath}": ${err.message}`);
|
|
34
|
+
}
|
|
35
|
+
return parseJSON(raw, label);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Read a file and base64-encode its bytes (bundle_b64 / css_b64 shape). */
|
|
39
|
+
function readBase64File(filePath, label) {
|
|
40
|
+
try {
|
|
41
|
+
return readFileSync(filePath).toString('base64');
|
|
42
|
+
} catch (err) {
|
|
43
|
+
throw new Error(`Could not read ${label} file "${filePath}": ${err.message}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Best-effort JSON parse for a data value; falls back to the raw string. */
|
|
48
|
+
function coerceDataValue(raw) {
|
|
49
|
+
try {
|
|
50
|
+
return JSON.parse(raw);
|
|
51
|
+
} catch {
|
|
52
|
+
return raw;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function confirmOrSkip(program, message) {
|
|
57
|
+
const { default: inquirer } = await import('inquirer');
|
|
58
|
+
const ans = await inquirer.prompt([{ type: 'confirm', name: 'confirm', message, default: false }]);
|
|
59
|
+
return ans.confirm;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function registerPluginCommands(program, ctx) {
|
|
63
|
+
const { client, auth } = ctx;
|
|
64
|
+
|
|
65
|
+
const plugin = program
|
|
66
|
+
.command('plugin')
|
|
67
|
+
.description('Manage org-installed plugins');
|
|
68
|
+
|
|
69
|
+
registerPluginDoctor(plugin);
|
|
70
|
+
|
|
71
|
+
// ── plugin licence ──────────────────────────────────────────────────────────
|
|
72
|
+
|
|
73
|
+
plugin
|
|
74
|
+
.command('licence')
|
|
75
|
+
.alias('license')
|
|
76
|
+
.description('Show whether a plugin is licence governed and entitled for this org (band, org id, entitlement errors)')
|
|
77
|
+
.argument('<pluginId>', 'plugin id, e.g. notesq')
|
|
78
|
+
.action(async (pluginId) => {
|
|
79
|
+
auth.requireAuth();
|
|
80
|
+
const ep = resolveEndpoint('setup.licensing.entitlements.list');
|
|
81
|
+
const data = await client.get(ep.path, { service: ep.service });
|
|
82
|
+
const entitlements = Array.isArray(data.entitlements) ? data.entitlements : [];
|
|
83
|
+
const governed = (Array.isArray(data.governed) ? data.governed : []).includes(pluginId);
|
|
84
|
+
const match = entitlements.find((e) => e === pluginId || String(e).startsWith(`${pluginId}@`)) || null;
|
|
85
|
+
// `entitlements` is the resolved (band-stripped) list; the band string lives on the licence itself.
|
|
86
|
+
const licenceEnts = (Array.isArray(data.licenses) ? data.licenses : []).flatMap((l) => (Array.isArray(l.entitlements) ? l.entitlements : []));
|
|
87
|
+
const banded = licenceEnts.find((e) => String(e).startsWith(`${pluginId}@`)) || null;
|
|
88
|
+
const bandInfo = (data.org_bands && data.org_bands[pluginId]) || null;
|
|
89
|
+
// A plugin outside the governed set is never licence gated (same rule as the server).
|
|
90
|
+
const entitled = governed ? match !== null : true;
|
|
91
|
+
const summary = {
|
|
92
|
+
plugin: pluginId,
|
|
93
|
+
governed,
|
|
94
|
+
entitled,
|
|
95
|
+
band: banded || (match && match.includes('@') ? match : null),
|
|
96
|
+
seats_used: bandInfo && typeof bandInfo.assigned_count === 'number' ? bandInfo.assigned_count : null,
|
|
97
|
+
seats_allowed: bandInfo && typeof bandInfo.allowance === 'number' ? bandInfo.allowance : null,
|
|
98
|
+
seat_holders: bandInfo && Array.isArray(bandInfo.assigned_orgs) ? bandInfo.assigned_orgs : [],
|
|
99
|
+
org_id: data.org_id || null,
|
|
100
|
+
org_licensed: bandInfo ? bandInfo.org_licensed ?? null : null,
|
|
101
|
+
entitlement_errors: Array.isArray(data.entitlement_errors) ? data.entitlement_errors : [],
|
|
102
|
+
};
|
|
103
|
+
if (program.opts().output === 'json') {
|
|
104
|
+
console.log(JSON.stringify(summary, null, 2));
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
formatDetail({
|
|
108
|
+
plugin: summary.plugin,
|
|
109
|
+
governed: summary.governed ? 'yes' : 'no',
|
|
110
|
+
entitled: summary.entitled ? 'yes' : 'no',
|
|
111
|
+
band: summary.band || '(none)',
|
|
112
|
+
org_seats: summary.seats_allowed === null ? '(no band)' : `${summary.seats_used} of ${summary.seats_allowed} used`,
|
|
113
|
+
org_id: summary.org_id || '(instance scoped)',
|
|
114
|
+
org_licensed: summary.org_licensed === null ? '(unknown)' : summary.org_licensed ? 'yes' : 'no',
|
|
115
|
+
entitlement_errors: summary.entitlement_errors.length
|
|
116
|
+
? summary.entitlement_errors.map((e) => (typeof e === 'string' ? e : JSON.stringify(e))).join('; ')
|
|
117
|
+
: '(none)',
|
|
118
|
+
}, { title: `Licence: ${pluginId}` });
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// ── plugin enable (PLUGIN-IMG #1012) ────────────────────────────────────────
|
|
122
|
+
// Starts a licensed plugin from its prebuilt private image on this
|
|
123
|
+
// self-hosted install. Licence first: unlicensed means nothing runs.
|
|
124
|
+
|
|
125
|
+
plugin
|
|
126
|
+
.command('enable')
|
|
127
|
+
.description('Start a licensed plugin from its prebuilt image on this self-hosted install (QuoxPlan for now). Unlicensed: refused, nothing pulled.')
|
|
128
|
+
.argument('<pluginId>', 'plugin id, e.g. quoxplan')
|
|
129
|
+
.option('--dir <path>', 'the install directory (default: the one Getting started recorded)')
|
|
130
|
+
.action(async (pluginId, opts) => {
|
|
131
|
+
auth.requireAuth();
|
|
132
|
+
const deps = ctx.serverDeps || {};
|
|
133
|
+
const env = deps.env || process.env;
|
|
134
|
+
const sys = deps.sys || createSys();
|
|
135
|
+
const checkEntitlement = async (id) => {
|
|
136
|
+
const ep = resolveEndpoint('setup.licensing.entitlements.list');
|
|
137
|
+
const data = await client.get(ep.path, { service: ep.service });
|
|
138
|
+
return entitlementFrom(data, id);
|
|
139
|
+
};
|
|
140
|
+
// Licence before anything that touches the box: an unlicensed enable must not even look for the install.
|
|
141
|
+
let ent;
|
|
142
|
+
try { ent = await checkEntitlement(pluginId); } catch (err) { ent = err; }
|
|
143
|
+
const resolveFirst = !(ent instanceof Error) && ent && ent.entitled;
|
|
144
|
+
let install = null;
|
|
145
|
+
if (resolveFirst) {
|
|
146
|
+
const i = await resolveInstall({ dir: opts.dir, env, sys, journey: deps.journey });
|
|
147
|
+
if (i.error) { const e = new Error(i.error); e.exitCode = 2; throw e; }
|
|
148
|
+
install = i;
|
|
149
|
+
}
|
|
150
|
+
const tag = install ? (env.QUOX_IMAGE_TAG || readEnvKeys(install.repoDir, ['QUOX_IMAGE_TAG']).QUOX_IMAGE_TAG || '') : '';
|
|
151
|
+
const result = await enablePlugin({
|
|
152
|
+
pluginId,
|
|
153
|
+
checkEntitlement: async () => { if (ent instanceof Error) throw ent; return ent; },
|
|
154
|
+
install: install || { repoDir: '' },
|
|
155
|
+
sys,
|
|
156
|
+
tag,
|
|
157
|
+
...(deps.getPullCredential ? { getPullCredential: deps.getPullCredential } : {}),
|
|
158
|
+
...(deps.sleep ? { sleep: deps.sleep } : {}),
|
|
159
|
+
log: (l) => printInfo(l),
|
|
160
|
+
});
|
|
161
|
+
if (program.opts().output === 'json') {
|
|
162
|
+
console.log(JSON.stringify({ plugin: pluginId, ok: result.ok, stage: result.stage, message: result.message }, null, 2));
|
|
163
|
+
} else if (result.ok) {
|
|
164
|
+
printSuccess(result.message);
|
|
165
|
+
} else {
|
|
166
|
+
printWarning(result.message);
|
|
167
|
+
}
|
|
168
|
+
if (!result.ok) process.exitCode = result.stage === 'licence' ? 3 : 1;
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// ── plugin list ─────────────────────────────────────────────────────────────
|
|
172
|
+
|
|
173
|
+
plugin
|
|
174
|
+
.command('list')
|
|
175
|
+
.description('List installed plugins for the active org')
|
|
176
|
+
.action(async () => {
|
|
177
|
+
auth.requireAuth();
|
|
178
|
+
const orgId = resolveOrgId(auth, program);
|
|
179
|
+
const ep = resolveEndpoint('plugins.list', { orgId });
|
|
180
|
+
const data = await client.get(ep.path, { service: ep.service });
|
|
181
|
+
const plugins = data.plugins || data || [];
|
|
182
|
+
formatOutput({
|
|
183
|
+
columns: ['plugin_id', 'version', 'is_enabled', 'installed_by', 'installed_at', 'upgraded_at'],
|
|
184
|
+
headers: ['Plugin ID', 'Version', 'Enabled', 'Installed By', 'Installed', 'Upgraded'],
|
|
185
|
+
rows: plugins,
|
|
186
|
+
}, { format: program.opts().output, emptyMessage: 'No plugins installed.' });
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
// ── plugin get ──────────────────────────────────────────────────────────────
|
|
190
|
+
|
|
191
|
+
plugin
|
|
192
|
+
.command('get')
|
|
193
|
+
.description('Show plugin install details')
|
|
194
|
+
.argument('<pluginId>', 'plugin ID (slug) or install-record id')
|
|
195
|
+
.action(async (pluginId) => {
|
|
196
|
+
auth.requireAuth();
|
|
197
|
+
const orgId = resolveOrgId(auth, program);
|
|
198
|
+
const getFor = (id) => {
|
|
199
|
+
const ep = resolveEndpoint('plugins.get', { orgId, pluginId: id });
|
|
200
|
+
return client.get(ep.path, { service: ep.service });
|
|
201
|
+
};
|
|
202
|
+
let resolvedId = pluginId;
|
|
203
|
+
let data;
|
|
204
|
+
try {
|
|
205
|
+
data = await getFor(resolvedId);
|
|
206
|
+
} catch (err) {
|
|
207
|
+
// quox-plugin-sdk#2(B): `plugin list --json` emits the install-record
|
|
208
|
+
// ULID as `id`, but get resolves by plugin_id (slug) and 404s on the
|
|
209
|
+
// ULID — so `plugin list --json | jq .id | xargs quox plugin get` broke.
|
|
210
|
+
// On a 404, treat the arg as an install id and map it to its plugin_id
|
|
211
|
+
// via the list, so BOTH identifiers round-trip. Slugs stay the fast path.
|
|
212
|
+
if (err && err.status === 404) {
|
|
213
|
+
const listEp = resolveEndpoint('plugins.list', { orgId });
|
|
214
|
+
const listData = await client.get(listEp.path, { service: listEp.service });
|
|
215
|
+
const rows = listData.plugins || listData || [];
|
|
216
|
+
const match = rows.find(p => p.id === pluginId || p.install_id === pluginId);
|
|
217
|
+
if (match && match.plugin_id && match.plugin_id !== pluginId) {
|
|
218
|
+
resolvedId = match.plugin_id;
|
|
219
|
+
data = await getFor(resolvedId);
|
|
220
|
+
} else {
|
|
221
|
+
throw err;
|
|
222
|
+
}
|
|
223
|
+
} else {
|
|
224
|
+
throw err;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
formatDetail(data.plugin || data, {
|
|
228
|
+
format: program.opts().output,
|
|
229
|
+
title: `Plugin: ${resolvedId}`,
|
|
230
|
+
fields: ['id', 'plugin_id', 'version', 'is_enabled', 'bundle_sha256', 'installed_by', 'installed_at', 'upgraded_at', 'manifest', 'signature'],
|
|
231
|
+
labels: {
|
|
232
|
+
id: 'Install ID', plugin_id: 'Plugin ID', version: 'Version', is_enabled: 'Enabled',
|
|
233
|
+
bundle_sha256: 'Bundle SHA256', installed_by: 'Installed By', installed_at: 'Installed',
|
|
234
|
+
upgraded_at: 'Upgraded', manifest: 'Manifest', signature: 'Signature',
|
|
235
|
+
},
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
// ── plugin install ──────────────────────────────────────────────────────────
|
|
240
|
+
|
|
241
|
+
plugin
|
|
242
|
+
.command('install')
|
|
243
|
+
.description('Install a plugin (admin only)')
|
|
244
|
+
.requiredOption('--manifest <file>', 'path to a manifest JSON file (must include id, name, version)')
|
|
245
|
+
.requiredOption('--bundle <file>', 'path to the plugin bundle JS file')
|
|
246
|
+
.option('--css <file>', 'path to a CSS file for the plugin')
|
|
247
|
+
.option('--signature <file>', 'path to a signature JSON file (required if the org has trusted keys)')
|
|
248
|
+
.action(async (options) => {
|
|
249
|
+
auth.requireAuth();
|
|
250
|
+
const orgId = resolveOrgId(auth, program);
|
|
251
|
+
|
|
252
|
+
const manifest = readJsonFile(options.manifest, '--manifest');
|
|
253
|
+
const body = { manifest, bundle_b64: readBase64File(options.bundle, '--bundle') };
|
|
254
|
+
if (options.css) body.css_b64 = readBase64File(options.css, '--css');
|
|
255
|
+
if (options.signature) body.signature = readJsonFile(options.signature, '--signature');
|
|
256
|
+
|
|
257
|
+
const ep = resolveEndpoint('plugins.install', { orgId });
|
|
258
|
+
const data = await client.post(ep.path, { service: ep.service, body });
|
|
259
|
+
printSuccess(`Plugin "${manifest.id}" installed.`);
|
|
260
|
+
formatDetail(data.plugin || data, { format: program.opts().output });
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
// ── plugin update ───────────────────────────────────────────────────────────
|
|
264
|
+
|
|
265
|
+
plugin
|
|
266
|
+
.command('update')
|
|
267
|
+
.description('Upgrade a plugin bundle and/or toggle its enabled state (admin only)')
|
|
268
|
+
.argument('<pluginId>', 'plugin ID')
|
|
269
|
+
.option('--enable', 'enable the plugin')
|
|
270
|
+
.option('--disable', 'disable the plugin')
|
|
271
|
+
.option('--manifest <file>', 'path to a new manifest JSON file (required together with --bundle)')
|
|
272
|
+
.option('--bundle <file>', 'path to a new bundle JS file (required together with --manifest)')
|
|
273
|
+
.option('--css <file>', 'path to a new CSS file')
|
|
274
|
+
.option('--signature <file>', 'path to a new signature JSON file')
|
|
275
|
+
.action(async (pluginId, options) => {
|
|
276
|
+
auth.requireAuth();
|
|
277
|
+
const orgId = resolveOrgId(auth, program);
|
|
278
|
+
|
|
279
|
+
if (options.enable && options.disable) {
|
|
280
|
+
throw new Error('Specify only one of --enable or --disable.');
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const body = {};
|
|
284
|
+
if (options.enable) body.is_enabled = true;
|
|
285
|
+
if (options.disable) body.is_enabled = false;
|
|
286
|
+
|
|
287
|
+
if (options.manifest || options.bundle) {
|
|
288
|
+
if (!options.manifest || !options.bundle) {
|
|
289
|
+
throw new Error('--manifest and --bundle must be provided together for an upgrade.');
|
|
290
|
+
}
|
|
291
|
+
body.manifest = readJsonFile(options.manifest, '--manifest');
|
|
292
|
+
body.bundle_b64 = readBase64File(options.bundle, '--bundle');
|
|
293
|
+
if (options.css) body.css_b64 = readBase64File(options.css, '--css');
|
|
294
|
+
if (options.signature) body.signature = readJsonFile(options.signature, '--signature');
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (Object.keys(body).length === 0) {
|
|
298
|
+
throw new Error('Specify --enable, --disable, or --manifest/--bundle to upgrade.');
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const ep = resolveEndpoint('plugins.update', { orgId, pluginId });
|
|
302
|
+
const data = await client.patch(ep.path, { service: ep.service, body });
|
|
303
|
+
printSuccess('Plugin updated.');
|
|
304
|
+
formatDetail(data.plugin || data, { format: program.opts().output });
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
// ── plugin uninstall ────────────────────────────────────────────────────────
|
|
308
|
+
|
|
309
|
+
plugin
|
|
310
|
+
.command('uninstall')
|
|
311
|
+
.description('Uninstall a plugin (admin only)')
|
|
312
|
+
.argument('<pluginId>', 'plugin ID')
|
|
313
|
+
.option('--force', 'skip confirmation')
|
|
314
|
+
.action(async (pluginId, options) => {
|
|
315
|
+
auth.requireAuth();
|
|
316
|
+
const orgId = resolveOrgId(auth, program);
|
|
317
|
+
|
|
318
|
+
if (!options.force && !program.opts().yes) {
|
|
319
|
+
const ok = await confirmOrSkip(program, `Uninstall plugin ${pluginId}? This cannot be undone.`);
|
|
320
|
+
if (!ok) { printInfo('Cancelled.'); return; }
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const ep = resolveEndpoint('plugins.uninstall', { orgId, pluginId });
|
|
324
|
+
await client.delete(ep.path, { service: ep.service });
|
|
325
|
+
printSuccess('Plugin uninstalled.');
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
// ── plugin mine ─────────────────────────────────────────────────────────────
|
|
329
|
+
|
|
330
|
+
plugin
|
|
331
|
+
.command('mine')
|
|
332
|
+
.description('List plugins visible to the current user (respects assignments)')
|
|
333
|
+
.action(async () => {
|
|
334
|
+
auth.requireAuth();
|
|
335
|
+
const orgId = resolveOrgId(auth, program);
|
|
336
|
+
const ep = resolveEndpoint('plugins.mine.list', { orgId });
|
|
337
|
+
const data = await client.get(ep.path, { service: ep.service });
|
|
338
|
+
const plugins = data.plugins || data || [];
|
|
339
|
+
formatOutput({
|
|
340
|
+
columns: ['plugin_id', 'version', 'is_enabled', 'installed_at'],
|
|
341
|
+
headers: ['Plugin ID', 'Version', 'Enabled', 'Installed'],
|
|
342
|
+
rows: plugins,
|
|
343
|
+
}, { format: program.opts().output, emptyMessage: 'No plugins visible to you in this org.' });
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
// ── plugin data ─────────────────────────────────────────────────────────────
|
|
347
|
+
|
|
348
|
+
const data = plugin
|
|
349
|
+
.command('data')
|
|
350
|
+
.description('Manage plugin-scoped durable data (KV)');
|
|
351
|
+
|
|
352
|
+
data
|
|
353
|
+
.command('list')
|
|
354
|
+
.description('List data keys for a plugin')
|
|
355
|
+
.argument('<pluginId>', 'plugin ID')
|
|
356
|
+
.option('--scope <scope>', 'org|user', 'org')
|
|
357
|
+
.action(async (pluginId, options) => {
|
|
358
|
+
auth.requireAuth();
|
|
359
|
+
const orgId = resolveOrgId(auth, program);
|
|
360
|
+
const ep = resolveEndpoint('plugins.data.list', { orgId, pluginId });
|
|
361
|
+
const result = await client.get(ep.path, { service: ep.service, query: { scope: options.scope } });
|
|
362
|
+
const keys = result.keys || [];
|
|
363
|
+
if (keys.length === 0) {
|
|
364
|
+
printInfo('No data keys found.');
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
formatOutput({ columns: ['key'], headers: ['Key'], rows: keys.map(key => ({ key })) }, { format: program.opts().output });
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
data
|
|
371
|
+
.command('get')
|
|
372
|
+
.description('Get a plugin data value')
|
|
373
|
+
.argument('<pluginId>', 'plugin ID')
|
|
374
|
+
.argument('<key>', 'data key')
|
|
375
|
+
.option('--scope <scope>', 'org|user', 'org')
|
|
376
|
+
.action(async (pluginId, key, options) => {
|
|
377
|
+
auth.requireAuth();
|
|
378
|
+
const orgId = resolveOrgId(auth, program);
|
|
379
|
+
const ep = resolveEndpoint('plugins.data.get', { orgId, pluginId, key });
|
|
380
|
+
const row = await client.get(ep.path, { service: ep.service, query: { scope: options.scope } });
|
|
381
|
+
formatDetail(row, { format: program.opts().output });
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
data
|
|
385
|
+
.command('set')
|
|
386
|
+
.description('Set a plugin data value')
|
|
387
|
+
.argument('<pluginId>', 'plugin ID')
|
|
388
|
+
.argument('<key>', 'data key')
|
|
389
|
+
.requiredOption('--value <value>', 'value to store (JSON is parsed automatically; otherwise stored as a string)')
|
|
390
|
+
.option('--scope <scope>', 'org|user', 'org')
|
|
391
|
+
.action(async (pluginId, key, options) => {
|
|
392
|
+
auth.requireAuth();
|
|
393
|
+
const orgId = resolveOrgId(auth, program);
|
|
394
|
+
const ep = resolveEndpoint('plugins.data.set', { orgId, pluginId, key });
|
|
395
|
+
const row = await client.put(ep.path, {
|
|
396
|
+
service: ep.service,
|
|
397
|
+
query: { scope: options.scope },
|
|
398
|
+
body: { value: coerceDataValue(options.value) },
|
|
399
|
+
});
|
|
400
|
+
printSuccess(`Data key "${key}" set.`);
|
|
401
|
+
formatDetail(row, { format: program.opts().output });
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
data
|
|
405
|
+
.command('delete')
|
|
406
|
+
.description('Delete a plugin data value')
|
|
407
|
+
.argument('<pluginId>', 'plugin ID')
|
|
408
|
+
.argument('<key>', 'data key')
|
|
409
|
+
.option('--scope <scope>', 'org|user', 'org')
|
|
410
|
+
.action(async (pluginId, key, options) => {
|
|
411
|
+
auth.requireAuth();
|
|
412
|
+
const orgId = resolveOrgId(auth, program);
|
|
413
|
+
const ep = resolveEndpoint('plugins.data.delete', { orgId, pluginId, key });
|
|
414
|
+
await client.delete(ep.path, { service: ep.service, query: { scope: options.scope } });
|
|
415
|
+
printSuccess('Data key deleted.');
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
// ── plugin secrets ──────────────────────────────────────────────────────────
|
|
419
|
+
|
|
420
|
+
const secrets = plugin
|
|
421
|
+
.command('secrets')
|
|
422
|
+
.description('Manage plugin-scoped encrypted secrets');
|
|
423
|
+
|
|
424
|
+
secrets
|
|
425
|
+
.command('list')
|
|
426
|
+
.description('List secret metadata for a plugin (no plaintext)')
|
|
427
|
+
.argument('<pluginId>', 'plugin ID')
|
|
428
|
+
.action(async (pluginId) => {
|
|
429
|
+
auth.requireAuth();
|
|
430
|
+
const orgId = resolveOrgId(auth, program);
|
|
431
|
+
const ep = resolveEndpoint('plugins.secrets.list', { orgId, pluginId });
|
|
432
|
+
const result = await client.get(ep.path, { service: ep.service });
|
|
433
|
+
const rows = result.secrets || result || [];
|
|
434
|
+
formatOutput({
|
|
435
|
+
columns: ['name', 'description', 'created_by', 'created_at', 'rotated_at'],
|
|
436
|
+
headers: ['Name', 'Description', 'Created By', 'Created', 'Rotated'],
|
|
437
|
+
rows,
|
|
438
|
+
}, { format: program.opts().output, emptyMessage: 'No secrets set for this plugin.' });
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
secrets
|
|
442
|
+
.command('set')
|
|
443
|
+
.description('Set (or rotate) a plugin secret (admin only)')
|
|
444
|
+
.argument('<pluginId>', 'plugin ID')
|
|
445
|
+
.argument('<name>', 'secret name')
|
|
446
|
+
.requiredOption('--value <text>', 'secret value')
|
|
447
|
+
.option('--description <text>', 'secret description')
|
|
448
|
+
.action(async (pluginId, name, options) => {
|
|
449
|
+
auth.requireAuth();
|
|
450
|
+
const orgId = resolveOrgId(auth, program);
|
|
451
|
+
const body = { value: options.value };
|
|
452
|
+
if (options.description) body.description = options.description;
|
|
453
|
+
const ep = resolveEndpoint('plugins.secrets.set', { orgId, pluginId, name });
|
|
454
|
+
const result = await client.put(ep.path, { service: ep.service, body });
|
|
455
|
+
printSuccess(`Secret "${name}" set.`);
|
|
456
|
+
formatDetail(result.secret || result, { format: program.opts().output });
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
secrets
|
|
460
|
+
.command('reveal')
|
|
461
|
+
.description('Reveal a plugin secret\'s plaintext value (audited)')
|
|
462
|
+
.argument('<pluginId>', 'plugin ID')
|
|
463
|
+
.argument('<name>', 'secret name')
|
|
464
|
+
.action(async (pluginId, name) => {
|
|
465
|
+
auth.requireAuth();
|
|
466
|
+
const orgId = resolveOrgId(auth, program);
|
|
467
|
+
printWarning('This reveals a plaintext secret and is recorded in the audit log.');
|
|
468
|
+
const ep = resolveEndpoint('plugins.secrets.reveal', { orgId, pluginId, name });
|
|
469
|
+
const result = await client.post(ep.path, { service: ep.service });
|
|
470
|
+
formatDetail(result, { format: program.opts().output });
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
secrets
|
|
474
|
+
.command('delete')
|
|
475
|
+
.description('Delete a plugin secret (admin only)')
|
|
476
|
+
.argument('<pluginId>', 'plugin ID')
|
|
477
|
+
.argument('<name>', 'secret name')
|
|
478
|
+
.action(async (pluginId, name) => {
|
|
479
|
+
auth.requireAuth();
|
|
480
|
+
const orgId = resolveOrgId(auth, program);
|
|
481
|
+
const ep = resolveEndpoint('plugins.secrets.delete', { orgId, pluginId, name });
|
|
482
|
+
await client.delete(ep.path, { service: ep.service });
|
|
483
|
+
printSuccess('Secret deleted.');
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
// ── plugin assign ───────────────────────────────────────────────────────────
|
|
487
|
+
|
|
488
|
+
const assign = plugin
|
|
489
|
+
.command('assign')
|
|
490
|
+
.description('Manage plugin visibility assignments (admin only)');
|
|
491
|
+
|
|
492
|
+
assign
|
|
493
|
+
.command('list')
|
|
494
|
+
.description('List assignments for a plugin')
|
|
495
|
+
.argument('<pluginId>', 'plugin ID')
|
|
496
|
+
.action(async (pluginId) => {
|
|
497
|
+
auth.requireAuth();
|
|
498
|
+
const orgId = resolveOrgId(auth, program);
|
|
499
|
+
const ep = resolveEndpoint('plugins.assignments.list', { orgId, pluginId });
|
|
500
|
+
const result = await client.get(ep.path, { service: ep.service });
|
|
501
|
+
const rows = result.assignments || result || [];
|
|
502
|
+
formatOutput({
|
|
503
|
+
columns: ['assignee_type', 'assignee_id', 'assigned_by', 'assigned_at'],
|
|
504
|
+
headers: ['Type', 'Assignee', 'Assigned By', 'Assigned'],
|
|
505
|
+
rows,
|
|
506
|
+
}, { format: program.opts().output, emptyMessage: 'No assignments set (plugin uses default visibility).' });
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
assign
|
|
510
|
+
.command('add')
|
|
511
|
+
.description('Assign a plugin to all org members, a user, or a team')
|
|
512
|
+
.argument('<pluginId>', 'plugin ID')
|
|
513
|
+
.requiredOption('--type <assigneeType>', 'all_org_members|user|team')
|
|
514
|
+
.option('--id <assigneeId>', 'assignee ID (user or team ID; omit for all_org_members)')
|
|
515
|
+
.action(async (pluginId, options) => {
|
|
516
|
+
auth.requireAuth();
|
|
517
|
+
const orgId = resolveOrgId(auth, program);
|
|
518
|
+
const body = { assignee_type: options.type };
|
|
519
|
+
if (options.id) body.assignee_id = options.id;
|
|
520
|
+
const ep = resolveEndpoint('plugins.assignments.create', { orgId, pluginId });
|
|
521
|
+
const result = await client.post(ep.path, { service: ep.service, body });
|
|
522
|
+
printSuccess('Assignment added.');
|
|
523
|
+
formatDetail(result.assignment || result, { format: program.opts().output });
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
assign
|
|
527
|
+
.command('remove')
|
|
528
|
+
.description('Remove a plugin assignment')
|
|
529
|
+
.argument('<pluginId>', 'plugin ID')
|
|
530
|
+
.argument('<assigneeType>', 'all_org_members|user|team')
|
|
531
|
+
.argument('[assigneeId]', 'assignee ID (omit for all_org_members)')
|
|
532
|
+
.action(async (pluginId, assigneeType, assigneeId) => {
|
|
533
|
+
auth.requireAuth();
|
|
534
|
+
const orgId = resolveOrgId(auth, program);
|
|
535
|
+
const ep = resolveEndpoint('plugins.assignments.delete', { orgId, pluginId, assigneeType, assigneeId });
|
|
536
|
+
await client.delete(ep.path, { service: ep.service });
|
|
537
|
+
printSuccess('Assignment removed.');
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
// ── plugin trusted-keys ─────────────────────────────────────────────────────
|
|
541
|
+
|
|
542
|
+
const trustedKeys = plugin
|
|
543
|
+
.command('trusted-keys')
|
|
544
|
+
.description('Manage per-org trusted Ed25519 signing keys (admin only)');
|
|
545
|
+
|
|
546
|
+
trustedKeys
|
|
547
|
+
.command('list')
|
|
548
|
+
.description('List trusted keys')
|
|
549
|
+
.action(async () => {
|
|
550
|
+
auth.requireAuth();
|
|
551
|
+
const orgId = resolveOrgId(auth, program);
|
|
552
|
+
const ep = resolveEndpoint('plugins.trusted-keys.list', { orgId });
|
|
553
|
+
const result = await client.get(ep.path, { service: ep.service });
|
|
554
|
+
const rows = result.trusted_keys || result || [];
|
|
555
|
+
formatOutput({
|
|
556
|
+
columns: ['id', 'label', 'public_key_hex', 'added_by', 'added_at'],
|
|
557
|
+
headers: ['ID', 'Label', 'Public Key', 'Added By', 'Added'],
|
|
558
|
+
rows,
|
|
559
|
+
}, { format: program.opts().output, emptyMessage: 'No trusted keys configured (unsigned installs are accepted).' });
|
|
560
|
+
});
|
|
561
|
+
|
|
562
|
+
trustedKeys
|
|
563
|
+
.command('add')
|
|
564
|
+
.description('Add a trusted signing key')
|
|
565
|
+
.requiredOption('--label <label>', 'key label')
|
|
566
|
+
.requiredOption('--public-key <hex>', 'Ed25519 public key, hex-encoded')
|
|
567
|
+
.action(async (options) => {
|
|
568
|
+
auth.requireAuth();
|
|
569
|
+
const orgId = resolveOrgId(auth, program);
|
|
570
|
+
const body = { label: options.label, public_key_hex: options.publicKey };
|
|
571
|
+
const ep = resolveEndpoint('plugins.trusted-keys.create', { orgId });
|
|
572
|
+
const result = await client.post(ep.path, { service: ep.service, body });
|
|
573
|
+
printSuccess('Trusted key added.');
|
|
574
|
+
formatDetail(result.trusted_key || result, { format: program.opts().output });
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
trustedKeys
|
|
578
|
+
.command('remove')
|
|
579
|
+
.description('Remove a trusted signing key')
|
|
580
|
+
.argument('<keyId>', 'trusted key ID')
|
|
581
|
+
.option('--confirm-unsigned', 'WARNING: required to remove the LAST trusted key; the org will then accept UNSIGNED plugin bundles')
|
|
582
|
+
.action(async (keyId, opts) => {
|
|
583
|
+
auth.requireAuth();
|
|
584
|
+
const orgId = resolveOrgId(auth, program);
|
|
585
|
+
const ep = resolveEndpoint('plugins.trusted-keys.delete', { orgId, keyId });
|
|
586
|
+
const reqOpts = { service: ep.service };
|
|
587
|
+
if (opts && opts.confirmUnsigned) {
|
|
588
|
+
console.error('WARNING: confirming downgrade. This org will accept UNSIGNED plugin bundles after this key is removed.');
|
|
589
|
+
reqOpts.query = { confirm_unsigned: '1' };
|
|
590
|
+
}
|
|
591
|
+
await client.delete(ep.path, reqOpts);
|
|
592
|
+
printSuccess('Trusted key removed.');
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
// ── plugin revocations (SDK-TEAM W5) ────────────────────────────────────────
|
|
596
|
+
|
|
597
|
+
const revocations = plugin
|
|
598
|
+
.command('revocations')
|
|
599
|
+
.description('Revoke a plugin signer key or one bundle digest for this org (admin only). A revoked plugin cannot be installed and stops loading on the next page load.');
|
|
600
|
+
|
|
601
|
+
revocations
|
|
602
|
+
.command('list')
|
|
603
|
+
.description('List revocations')
|
|
604
|
+
.action(async () => {
|
|
605
|
+
auth.requireAuth();
|
|
606
|
+
const orgId = resolveOrgId(auth, program);
|
|
607
|
+
const ep = resolveEndpoint('plugins.revocations.list', { orgId });
|
|
608
|
+
const result = await client.get(ep.path, { service: ep.service });
|
|
609
|
+
const rows = result.revocations || result || [];
|
|
610
|
+
formatOutput({
|
|
611
|
+
columns: ['id', 'kind', 'value', 'reason', 'revoked_by', 'revoked_at'],
|
|
612
|
+
headers: ['ID', 'Kind', 'Value', 'Reason', 'Revoked By', 'Revoked'],
|
|
613
|
+
rows,
|
|
614
|
+
}, { format: program.opts().output, emptyMessage: 'No revocations.' });
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
revocations
|
|
618
|
+
.command('add')
|
|
619
|
+
.description('Revoke a signer key or a bundle digest')
|
|
620
|
+
.option('--signer-key <hex>', 'raw Ed25519 public key (64 hex), as in signature.json public_key_hex')
|
|
621
|
+
.option('--bundle-digest <hex>', 'sha256 of plugin.esm.js (64 hex), as shown by quox plugin list')
|
|
622
|
+
.option('--reason <text>', 'why (kept in the audit trail)')
|
|
623
|
+
.action(async (options) => {
|
|
624
|
+
auth.requireAuth();
|
|
625
|
+
if (!!options.signerKey === !!options.bundleDigest) {
|
|
626
|
+
throw new Error('Specify exactly one of --signer-key or --bundle-digest.');
|
|
627
|
+
}
|
|
628
|
+
const orgId = resolveOrgId(auth, program);
|
|
629
|
+
const body = options.signerKey
|
|
630
|
+
? { kind: 'signer_key', value: options.signerKey, reason: options.reason }
|
|
631
|
+
: { kind: 'bundle_digest', value: options.bundleDigest, reason: options.reason };
|
|
632
|
+
const ep = resolveEndpoint('plugins.revocations.create', { orgId });
|
|
633
|
+
const result = await client.post(ep.path, { service: ep.service, body });
|
|
634
|
+
printSuccess('Revoked.');
|
|
635
|
+
formatDetail(result.revocation || result, { format: program.opts().output });
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
revocations
|
|
639
|
+
.command('remove')
|
|
640
|
+
.description('Lift a revocation')
|
|
641
|
+
.argument('<revocationId>', 'revocation ID')
|
|
642
|
+
.action(async (revocationId) => {
|
|
643
|
+
auth.requireAuth();
|
|
644
|
+
const orgId = resolveOrgId(auth, program);
|
|
645
|
+
const ep = resolveEndpoint('plugins.revocations.delete', { orgId, revocationId });
|
|
646
|
+
await client.delete(ep.path, { service: ep.service });
|
|
647
|
+
printSuccess('Revocation lifted.');
|
|
648
|
+
});
|
|
649
|
+
}
|