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,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSO commands: org SSO provider registry (OIDC + SAML admin CRUD)
|
|
3
|
+
*
|
|
4
|
+
* quox sso providers list|get|create|update|delete|saml-metadata
|
|
5
|
+
*
|
|
6
|
+
* Backend: services/auth/routes/sso.js, mounted at plain `/api`
|
|
7
|
+
* (org-scoped IN the URL for admin routes: /api/orgs/:orgId/sso/providers...).
|
|
8
|
+
* Enterprise-tier + ORG_MANAGE_SSO gated — expect 402/403 on non-enterprise
|
|
9
|
+
* orgs.
|
|
10
|
+
*
|
|
11
|
+
* `saml-metadata` is the one exception: its backend route has NO orgId
|
|
12
|
+
* segment (`/api/sso/providers/:providerId/saml-metadata`) and is public
|
|
13
|
+
* (no auth chain) — see endpoints/sso.js for the full finding. It only
|
|
14
|
+
* works for providers whose protocol is 'saml'.
|
|
15
|
+
*
|
|
16
|
+
* The browser-flow login/callback/discover routes are intentionally not
|
|
17
|
+
* exposed here — they're 302-redirect handshakes, not CLI-shaped.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { readFileSync } from 'node:fs';
|
|
21
|
+
import { formatOutput, formatDetail, printSuccess, printWarning, printInfo } from '../core/output.js';
|
|
22
|
+
import { resolveOrgId, parseJSON } from './helpers.js';
|
|
23
|
+
import { resolveEndpoint } from '../api/endpoints.js';
|
|
24
|
+
|
|
25
|
+
/** Build a create/update body from the shared provider flags. */
|
|
26
|
+
function buildProviderBody(options) {
|
|
27
|
+
const body = {};
|
|
28
|
+
if (options.protocol) body.protocol = options.protocol;
|
|
29
|
+
if (options.key) body.provider_key = options.key;
|
|
30
|
+
if (options.displayName) body.display_name = options.displayName;
|
|
31
|
+
if (options.enabled) body.enabled = true;
|
|
32
|
+
if (options.disabled) body.enabled = false;
|
|
33
|
+
if (options.ssoOnly) body.sso_only = true;
|
|
34
|
+
if (options.emailDomains) {
|
|
35
|
+
body.email_domains = options.emailDomains.split(',').map(d => d.trim()).filter(Boolean);
|
|
36
|
+
}
|
|
37
|
+
// OIDC
|
|
38
|
+
if (options.issuer) body.issuer = options.issuer;
|
|
39
|
+
if (options.clientId) body.client_id = options.clientId;
|
|
40
|
+
if (options.clientSecret) body.client_secret = options.clientSecret;
|
|
41
|
+
if (options.authzUrl) body.authz_url = options.authzUrl;
|
|
42
|
+
if (options.tokenUrl) body.token_url = options.tokenUrl;
|
|
43
|
+
if (options.userinfoUrl) body.userinfo_url = options.userinfoUrl;
|
|
44
|
+
if (options.jwksUri) body.jwks_uri = options.jwksUri;
|
|
45
|
+
if (options.scopes) body.scopes = options.scopes.split(',').map(s => s.trim()).filter(Boolean);
|
|
46
|
+
// SAML
|
|
47
|
+
if (options.entityId) body.entity_id = options.entityId;
|
|
48
|
+
if (options.ssoUrl) body.sso_url = options.ssoUrl;
|
|
49
|
+
if (options.sloUrl) body.slo_url = options.sloUrl;
|
|
50
|
+
if (options.x509CertFile) body.x509_cert = readFileSync(options.x509CertFile, 'utf-8');
|
|
51
|
+
if (options.nameidFormat) body.nameid_format = options.nameidFormat;
|
|
52
|
+
if (options.attributeMap) body.attribute_map = parseJSON(options.attributeMap, '--attribute-map');
|
|
53
|
+
if (options.groupRoleMap) body.group_role_map = parseJSON(options.groupRoleMap, '--group-role-map');
|
|
54
|
+
return body;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function addProviderFlags(cmd) {
|
|
58
|
+
return cmd
|
|
59
|
+
.option('--protocol <protocol>', 'oidc|saml (create defaults to oidc)')
|
|
60
|
+
.option('--display-name <name>', 'human-readable name')
|
|
61
|
+
.option('--enabled', 'enable the provider')
|
|
62
|
+
.option('--disabled', 'disable the provider')
|
|
63
|
+
.option('--sso-only', 'require SSO for matching email domains (disable password login)')
|
|
64
|
+
.option('--email-domains <domains>', 'comma-separated email domains routed to this provider')
|
|
65
|
+
.option('--issuer <url>', '[oidc] issuer URL')
|
|
66
|
+
.option('--client-id <id>', '[oidc] client ID')
|
|
67
|
+
.option('--client-secret <secret>', '[oidc] client secret')
|
|
68
|
+
.option('--authz-url <url>', '[oidc] authorization endpoint (optional, discovered if omitted)')
|
|
69
|
+
.option('--token-url <url>', '[oidc] token endpoint')
|
|
70
|
+
.option('--userinfo-url <url>', '[oidc] userinfo endpoint')
|
|
71
|
+
.option('--jwks-uri <url>', '[oidc] JWKS URI')
|
|
72
|
+
.option('--scopes <scopes>', '[oidc] comma-separated scopes (default: openid,email,profile)')
|
|
73
|
+
.option('--entity-id <id>', '[saml] IdP entity ID')
|
|
74
|
+
.option('--sso-url <url>', '[saml] IdP SSO URL')
|
|
75
|
+
.option('--slo-url <url>', '[saml] IdP SLO URL')
|
|
76
|
+
.option('--x509-cert-file <path>', '[saml] path to the IdP\'s PEM-encoded x509 certificate')
|
|
77
|
+
.option('--nameid-format <format>', '[saml] NameID format')
|
|
78
|
+
.option('--attribute-map <json>', '[saml] attribute mapping as a JSON object')
|
|
79
|
+
.option('--group-role-map <json>', '[saml] group-to-role mapping as a JSON object');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function registerSsoCommands(program, ctx) {
|
|
83
|
+
const { client, auth } = ctx;
|
|
84
|
+
|
|
85
|
+
const sso = program
|
|
86
|
+
.command('sso')
|
|
87
|
+
.description('Manage org SSO providers (enterprise — OIDC/SAML admin)');
|
|
88
|
+
|
|
89
|
+
const providers = sso
|
|
90
|
+
.command('providers')
|
|
91
|
+
.description('Manage SSO provider configurations');
|
|
92
|
+
|
|
93
|
+
// ── sso providers list ──────────────────────────────────────────────────────
|
|
94
|
+
|
|
95
|
+
providers
|
|
96
|
+
.command('list')
|
|
97
|
+
.description('List SSO providers for the active org')
|
|
98
|
+
.action(async () => {
|
|
99
|
+
auth.requireAuth();
|
|
100
|
+
const orgId = resolveOrgId(auth, program);
|
|
101
|
+
const ep = resolveEndpoint('sso.providers.list', { orgId });
|
|
102
|
+
const data = await client.get(ep.path, { service: ep.service });
|
|
103
|
+
const rows = data.providers || data || [];
|
|
104
|
+
|
|
105
|
+
formatOutput({
|
|
106
|
+
columns: ['id', 'protocol', 'provider_key', 'display_name', 'enabled', 'sso_only', 'created_at'],
|
|
107
|
+
headers: ['ID', 'Protocol', 'Key', 'Display Name', 'Enabled', 'SSO Only', 'Created'],
|
|
108
|
+
rows,
|
|
109
|
+
}, { format: program.opts().output, emptyMessage: 'No SSO providers configured.' });
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// ── sso providers get ───────────────────────────────────────────────────────
|
|
113
|
+
|
|
114
|
+
providers
|
|
115
|
+
.command('get')
|
|
116
|
+
.description('Show SSO provider details')
|
|
117
|
+
.argument('<providerId>', 'provider ID')
|
|
118
|
+
.action(async (providerId) => {
|
|
119
|
+
auth.requireAuth();
|
|
120
|
+
const orgId = resolveOrgId(auth, program);
|
|
121
|
+
const ep = resolveEndpoint('sso.providers.get', { orgId, providerId });
|
|
122
|
+
const data = await client.get(ep.path, { service: ep.service });
|
|
123
|
+
const provider = data.provider || data;
|
|
124
|
+
|
|
125
|
+
formatDetail(provider, {
|
|
126
|
+
format: program.opts().output,
|
|
127
|
+
title: `SSO Provider: ${provider.display_name || provider.provider_key || providerId}`,
|
|
128
|
+
fields: [
|
|
129
|
+
'id', 'protocol', 'provider_key', 'display_name', 'enabled', 'sso_only',
|
|
130
|
+
'issuer', 'client_id', 'authz_url', 'token_url', 'userinfo_url', 'jwks_uri', 'scopes',
|
|
131
|
+
'entity_id', 'sso_url', 'slo_url', 'nameid_format', 'attribute_map', 'group_role_map',
|
|
132
|
+
'email_domains', 'created_at', 'updated_at',
|
|
133
|
+
],
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// ── sso providers create ────────────────────────────────────────────────────
|
|
138
|
+
|
|
139
|
+
addProviderFlags(
|
|
140
|
+
providers
|
|
141
|
+
.command('create')
|
|
142
|
+
.description('Create an SSO provider')
|
|
143
|
+
.requiredOption('--key <providerKey>', 'unique provider key (e.g. "okta", "google-workspace")'),
|
|
144
|
+
).action(async (options) => {
|
|
145
|
+
auth.requireAuth();
|
|
146
|
+
const orgId = resolveOrgId(auth, program);
|
|
147
|
+
const body = buildProviderBody(options);
|
|
148
|
+
|
|
149
|
+
const ep = resolveEndpoint('sso.providers.create', { orgId });
|
|
150
|
+
const data = await client.post(ep.path, { service: ep.service, body });
|
|
151
|
+
printSuccess(`SSO provider "${options.key}" created.`);
|
|
152
|
+
formatDetail(data.provider || data, { format: program.opts().output });
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// ── sso providers update ────────────────────────────────────────────────────
|
|
156
|
+
|
|
157
|
+
addProviderFlags(
|
|
158
|
+
providers
|
|
159
|
+
.command('update')
|
|
160
|
+
.description('Update an SSO provider')
|
|
161
|
+
.argument('<providerId>', 'provider ID'),
|
|
162
|
+
).action(async (providerId, options) => {
|
|
163
|
+
auth.requireAuth();
|
|
164
|
+
const orgId = resolveOrgId(auth, program);
|
|
165
|
+
const body = buildProviderBody(options);
|
|
166
|
+
|
|
167
|
+
if (Object.keys(body).length === 0) {
|
|
168
|
+
throw new Error('Specify at least one field to update.');
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const ep = resolveEndpoint('sso.providers.update', { orgId, providerId });
|
|
172
|
+
const data = await client.patch(ep.path, { service: ep.service, body });
|
|
173
|
+
printSuccess('SSO provider updated.');
|
|
174
|
+
formatDetail(data.provider || data, { format: program.opts().output });
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// ── sso providers delete ────────────────────────────────────────────────────
|
|
178
|
+
|
|
179
|
+
providers
|
|
180
|
+
.command('delete')
|
|
181
|
+
.description('Delete an SSO provider')
|
|
182
|
+
.argument('<providerId>', 'provider ID')
|
|
183
|
+
.option('--force', 'skip confirmation')
|
|
184
|
+
.action(async (providerId, options) => {
|
|
185
|
+
auth.requireAuth();
|
|
186
|
+
const orgId = resolveOrgId(auth, program);
|
|
187
|
+
|
|
188
|
+
if (!options.force && !program.opts().yes) {
|
|
189
|
+
const { default: inquirer } = await import('inquirer');
|
|
190
|
+
const ans = await inquirer.prompt([{
|
|
191
|
+
type: 'confirm',
|
|
192
|
+
name: 'confirm',
|
|
193
|
+
message: `Delete SSO provider ${providerId}? Users routed to it will fall back to password login.`,
|
|
194
|
+
default: false,
|
|
195
|
+
}]);
|
|
196
|
+
if (!ans.confirm) {
|
|
197
|
+
printInfo('Cancelled.');
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const ep = resolveEndpoint('sso.providers.delete', { orgId, providerId });
|
|
203
|
+
await client.delete(ep.path, { service: ep.service });
|
|
204
|
+
printSuccess('SSO provider deleted.');
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// ── sso providers saml-metadata ─────────────────────────────────────────────
|
|
208
|
+
|
|
209
|
+
providers
|
|
210
|
+
.command('saml-metadata')
|
|
211
|
+
.description('Fetch the SP metadata XML for a SAML provider (paste into your IdP)')
|
|
212
|
+
.argument('<providerId>', 'provider ID (must be a SAML provider)')
|
|
213
|
+
.action(async (providerId) => {
|
|
214
|
+
auth.requireAuth();
|
|
215
|
+
// This backend route is public and NOT org-scoped in the URL — see
|
|
216
|
+
// endpoints/sso.js's header note. No orgId is sent.
|
|
217
|
+
const ep = resolveEndpoint('sso.providers.saml-metadata', { providerId });
|
|
218
|
+
const data = await client.get(ep.path, { service: ep.service });
|
|
219
|
+
// The route returns `application/xml`, so client.get() hands back
|
|
220
|
+
// `{ success: true, text: '<...xml...>' }` (its non-JSON-content-type
|
|
221
|
+
// fallback) rather than a parsed body.
|
|
222
|
+
const xml = data?.text ?? data;
|
|
223
|
+
if (program.opts().output === 'json') {
|
|
224
|
+
console.log(JSON.stringify({ metadata: xml }, null, 2));
|
|
225
|
+
} else {
|
|
226
|
+
console.log(typeof xml === 'string' ? xml : JSON.stringify(xml, null, 2));
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* quox status — Platform Pulse
|
|
3
|
+
*
|
|
4
|
+
* Displays a one-screen overview of the entire Quox platform:
|
|
5
|
+
* services, fleet, sessions, vault, memory, AEE, workflows.
|
|
6
|
+
*
|
|
7
|
+
* CLI-3a (Stream CLI Phase 3)
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import chalk from 'chalk';
|
|
11
|
+
import { emitCliEvent } from '../core/aee.js';
|
|
12
|
+
import { resolveEndpoint } from '../api/endpoints.js';
|
|
13
|
+
|
|
14
|
+
const STATUS_ICON = {
|
|
15
|
+
ok: chalk.green('●'),
|
|
16
|
+
degraded: chalk.yellow('●'),
|
|
17
|
+
down: chalk.red('●'),
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
function statusDot(status) {
|
|
21
|
+
return STATUS_ICON[status] || chalk.dim('○');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function renderPulse(data) {
|
|
25
|
+
const lines = [];
|
|
26
|
+
|
|
27
|
+
// Header
|
|
28
|
+
const scoreColor = data.score >= 90 ? chalk.green : data.score >= 70 ? chalk.yellow : chalk.red;
|
|
29
|
+
lines.push('');
|
|
30
|
+
lines.push(chalk.bold(` QUOX PLATFORM STATUS`) + chalk.dim(` ${scoreColor(`Health: ${data.score}%`)} ${data.timestamp || ''}`));
|
|
31
|
+
lines.push(chalk.dim(' ' + '─'.repeat(60)));
|
|
32
|
+
|
|
33
|
+
// Services
|
|
34
|
+
const svcLine = Object.entries(data.services || {})
|
|
35
|
+
.map(([name, s]) => `${statusDot(s.status)} ${name}`)
|
|
36
|
+
.join(' ');
|
|
37
|
+
lines.push(` Services ${svcLine}`);
|
|
38
|
+
|
|
39
|
+
// Fleet
|
|
40
|
+
const f = data.fleet || {};
|
|
41
|
+
lines.push(` Fleet ${f.total || 0} agents (${chalk.green(f.healthy || 0)} healthy, ${chalk.yellow(f.degraded || 0)} degraded, ${chalk.red(f.down || 0)} down)`);
|
|
42
|
+
|
|
43
|
+
// Sessions
|
|
44
|
+
const s = data.sessions || {};
|
|
45
|
+
const providers = Object.entries(s.providers || {}).map(([k, v]) => `${v} ${k}`).join(', ');
|
|
46
|
+
lines.push(` Sessions ${s.active || 0} active ${providers ? `(${providers})` : ''} ${chalk.dim(`$${(s.cost_today_usd || 0).toFixed(2)} today`)}`);
|
|
47
|
+
|
|
48
|
+
// Workflows
|
|
49
|
+
const w = data.workflows || {};
|
|
50
|
+
const wfParts = [];
|
|
51
|
+
if (w.running) wfParts.push(`${w.running} running`);
|
|
52
|
+
if (w.pending_approval) wfParts.push(`${w.pending_approval} pending approval`);
|
|
53
|
+
if (wfParts.length) lines.push(` Workflows ${wfParts.join(', ')}`);
|
|
54
|
+
|
|
55
|
+
// Vault
|
|
56
|
+
const v = data.vault || {};
|
|
57
|
+
if (v.total) {
|
|
58
|
+
const vaultWarn = v.expiring_soon > 0 ? chalk.yellow(` (${v.expiring_soon} expiring soon)`) : '';
|
|
59
|
+
lines.push(` Vault ${v.total} creds (${chalk.green(v.healthy)} healthy)${vaultWarn}`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Memory
|
|
63
|
+
const m = data.memory || {};
|
|
64
|
+
if (m.entries) {
|
|
65
|
+
const size = m.vector_size_gb ? ` ${m.vector_size_gb}GB vectors` : '';
|
|
66
|
+
lines.push(` Memory ${m.entries.toLocaleString()} entries${size}`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// AEE
|
|
70
|
+
const a = data.aee || {};
|
|
71
|
+
if (a.envelopes_today) {
|
|
72
|
+
const integrity = a.chain_ok ? chalk.green('✓') : chalk.red('✗');
|
|
73
|
+
lines.push(` AEE ${a.envelopes_today.toLocaleString()} envelopes today chain integrity ${integrity}`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
lines.push('');
|
|
77
|
+
return lines.join('\n');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function registerStatusCommand(program, ctx) {
|
|
81
|
+
const { client } = ctx;
|
|
82
|
+
|
|
83
|
+
program
|
|
84
|
+
.command('status')
|
|
85
|
+
.description('Show platform health and status overview')
|
|
86
|
+
.action(async (opts, cmd) => {
|
|
87
|
+
const outputFormat = cmd.parent?.opts()?.output || 'table';
|
|
88
|
+
const isJson = outputFormat === 'json' || cmd.parent?.opts()?.json;
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
// fleet #602: this used to pass noAuth: true, which suppressed the
|
|
92
|
+
// Authorization header the client would otherwise attach. The TUI's
|
|
93
|
+
// useHealth/HealthView poll this same endpoint WITH the normal client
|
|
94
|
+
// auth, as does a comparable authenticated route (backup.js).
|
|
95
|
+
// (monitoring.js's `health` verb had the identical noAuth bug — fixed
|
|
96
|
+
// in the same change.) Dropping noAuth here matches that pattern: the
|
|
97
|
+
// request still works
|
|
98
|
+
// for a logged-out session (client.js sends no Authorization header
|
|
99
|
+
// when there's nothing stored), but a logged-in session's token now
|
|
100
|
+
// actually reaches the collector instead of being withheld.
|
|
101
|
+
const data = await client.get(resolveEndpoint('v1.health.aggregate.list').path, {
|
|
102
|
+
service: resolveEndpoint('v1.health.aggregate.list').service,
|
|
103
|
+
timeout: 15000, // #930: the aggregate fans out to several services; 5s was too tight under load
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
if (isJson) {
|
|
107
|
+
console.log(JSON.stringify(data, null, 2));
|
|
108
|
+
} else {
|
|
109
|
+
console.log(renderPulse(data));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
emitCliEvent(client, {
|
|
113
|
+
command: 'status',
|
|
114
|
+
intent: 'quox.cli.status',
|
|
115
|
+
payload: { score: data.score, services: Object.keys(data.services || {}).length },
|
|
116
|
+
});
|
|
117
|
+
} catch (err) {
|
|
118
|
+
if (isJson) {
|
|
119
|
+
console.log(JSON.stringify({ error: 'collector_unavailable', message: err.message }));
|
|
120
|
+
} else {
|
|
121
|
+
console.log('');
|
|
122
|
+
console.log(chalk.red(' Platform status unavailable'));
|
|
123
|
+
console.log(chalk.dim(` Collector not reachable: ${err.message}`));
|
|
124
|
+
console.log('');
|
|
125
|
+
}
|
|
126
|
+
// fleet #602: a real request failure (network error, non-2xx from
|
|
127
|
+
// the collector) was printing the message above and still exiting
|
|
128
|
+
// 0, hiding the failure from scripts/CI that check the exit code.
|
|
129
|
+
// client.get only reaches this catch on an actual error (thrown
|
|
130
|
+
// QuoxApiError / QuoxNetworkError / QuoxAuthError, see
|
|
131
|
+
// lib/core/client.js) — never on a successful 2xx — so it's safe to
|
|
132
|
+
// fail the process here without risking a false failure on a
|
|
133
|
+
// legitimately-empty-but-200 status payload.
|
|
134
|
+
process.exitCode = 1;
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tag commands
|
|
3
|
+
*
|
|
4
|
+
* quox tag list|create|update|delete
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { formatOutput, formatDetail, printSuccess, printInfo } from '../core/output.js';
|
|
8
|
+
import { resolveOrgId } from './helpers.js';
|
|
9
|
+
import { resolveEndpoint } from '../api/endpoints.js';
|
|
10
|
+
import { confirmDestructive } from '../core/confirm.js';
|
|
11
|
+
|
|
12
|
+
export function registerTagCommands(program, ctx) {
|
|
13
|
+
const { client, auth } = ctx;
|
|
14
|
+
|
|
15
|
+
const tag = program
|
|
16
|
+
.command('tag')
|
|
17
|
+
.description('Manage tags');
|
|
18
|
+
|
|
19
|
+
tag
|
|
20
|
+
.command('list')
|
|
21
|
+
.description('List tags')
|
|
22
|
+
.action(async () => {
|
|
23
|
+
auth.requireAuth();
|
|
24
|
+
const orgId = resolveOrgId(auth, program);
|
|
25
|
+
// fleet #392: the route only computes usage when include_counts=true,
|
|
26
|
+
// which was never sent — so Count was hardcoded 0 for every tag.
|
|
27
|
+
const data = await client.get(resolveEndpoint('tags.list', { orgId }).path, { service: resolveEndpoint('tags.list', { orgId }).service, query: { include_counts: 'true' } });
|
|
28
|
+
const tags = data.tags || data || [];
|
|
29
|
+
formatOutput({
|
|
30
|
+
columns: ['id', 'name', 'color', 'count'],
|
|
31
|
+
headers: ['ID', 'Name', 'Color', 'Count'],
|
|
32
|
+
rows: tags.map(t => ({ id: t.id, name: t.name, color: t.color || '-', count: t.total_usage ?? 0 })),
|
|
33
|
+
}, { format: program.opts().output });
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
tag
|
|
37
|
+
.command('create')
|
|
38
|
+
.description('Create a tag')
|
|
39
|
+
.requiredOption('--name <name>', 'Tag name')
|
|
40
|
+
.option('--color <color>', 'Tag color (hex)')
|
|
41
|
+
.action(async (opts) => {
|
|
42
|
+
auth.requireAuth();
|
|
43
|
+
const orgId = resolveOrgId(auth, program);
|
|
44
|
+
const body = { name: opts.name };
|
|
45
|
+
if (opts.color) body.color = opts.color;
|
|
46
|
+
// fleet #399: the id wasn't surfaced, so a script had to call
|
|
47
|
+
// `tag list` to recover it after create.
|
|
48
|
+
const data = await client.post(resolveEndpoint('tags.create', { orgId }).path, { service: resolveEndpoint('tags.create', { orgId }).service, body });
|
|
49
|
+
const t = data.tag || data;
|
|
50
|
+
printSuccess(`Tag "${opts.name}" created (id: ${t.id}).`);
|
|
51
|
+
formatDetail(t, { format: program.opts().output });
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
tag
|
|
55
|
+
.command('update')
|
|
56
|
+
.argument('<tagId>', 'tag ID')
|
|
57
|
+
.description('Update a tag')
|
|
58
|
+
.option('--name <name>', 'New name')
|
|
59
|
+
.option('--color <color>', 'New color')
|
|
60
|
+
.action(async (tagId, opts) => {
|
|
61
|
+
auth.requireAuth();
|
|
62
|
+
const orgId = resolveOrgId(auth, program);
|
|
63
|
+
const body = {};
|
|
64
|
+
if (opts.name) body.name = opts.name;
|
|
65
|
+
if (opts.color) body.color = opts.color;
|
|
66
|
+
await client.patch(resolveEndpoint('tags.update', { orgId, tagId }).path, { service: resolveEndpoint('tags.update', { orgId, tagId }).service, body });
|
|
67
|
+
printSuccess('Tag updated.');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
tag
|
|
71
|
+
.command('delete')
|
|
72
|
+
.argument('<tagId>', 'tag ID')
|
|
73
|
+
.description('Delete a tag')
|
|
74
|
+
.option('--force', 'skip confirmation')
|
|
75
|
+
.action(async (tagId, options) => {
|
|
76
|
+
auth.requireAuth();
|
|
77
|
+
const orgId = resolveOrgId(auth, program);
|
|
78
|
+
|
|
79
|
+
// fleet #399: this deleted immediately with no confirmation and no
|
|
80
|
+
// --force option, inconsistent with `prompt delete` which is equally
|
|
81
|
+
// destructive.
|
|
82
|
+
const confirmed = await confirmDestructive(program, options, `Delete tag ${tagId}? This cannot be undone.`);
|
|
83
|
+
if (!confirmed) {
|
|
84
|
+
printInfo('Cancelled.');
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
await client.delete(resolveEndpoint('tags.delete', { orgId, tagId }).path, { service: resolveEndpoint('tags.delete', { orgId, tagId }).service });
|
|
89
|
+
printSuccess('Tag deleted.');
|
|
90
|
+
});
|
|
91
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Team commands: CRUD + members
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { formatOutput, formatDetail, printSuccess } from '../core/output.js';
|
|
6
|
+
import { resolveOrgId } from './helpers.js';
|
|
7
|
+
import { resolveEndpoint } from '../api/endpoints.js';
|
|
8
|
+
|
|
9
|
+
export function registerTeamCommands(program, ctx) {
|
|
10
|
+
const { client, auth } = ctx;
|
|
11
|
+
|
|
12
|
+
const team = program
|
|
13
|
+
.command('team')
|
|
14
|
+
.description('Manage teams');
|
|
15
|
+
|
|
16
|
+
team
|
|
17
|
+
.command('list')
|
|
18
|
+
.description('List teams')
|
|
19
|
+
.option('--division <divId>', 'filter by division')
|
|
20
|
+
.action(async (options) => {
|
|
21
|
+
auth.requireAuth();
|
|
22
|
+
const orgId = resolveOrgId(auth, program);
|
|
23
|
+
const query = {};
|
|
24
|
+
if (options.division) query.division_id = options.division;
|
|
25
|
+
// fleet #392: division_name and member_count only exist when
|
|
26
|
+
// includeStats=true, which was never sent — both columns were dashes.
|
|
27
|
+
query.includeStats = 'true';
|
|
28
|
+
const data = await client.get(resolveEndpoint('teams.list', { orgId }).path, { service: resolveEndpoint('teams.list', { orgId }).service, query });
|
|
29
|
+
formatOutput({
|
|
30
|
+
columns: ['id', 'name', 'division_name', 'member_count', 'created_at'],
|
|
31
|
+
headers: ['ID', 'Name', 'Division', 'Members', 'Created'],
|
|
32
|
+
rows: data.teams || data,
|
|
33
|
+
}, { format: program.opts().output });
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
team
|
|
37
|
+
.command('get')
|
|
38
|
+
.description('Get team details')
|
|
39
|
+
.argument('<teamId>', 'team ID')
|
|
40
|
+
.action(async (teamId) => {
|
|
41
|
+
auth.requireAuth();
|
|
42
|
+
const orgId = resolveOrgId(auth, program);
|
|
43
|
+
const data = await client.get(resolveEndpoint('teams.get', { orgId, teamId }).path, { service: resolveEndpoint('teams.get', { orgId, teamId }).service });
|
|
44
|
+
formatDetail(data.team || data, { format: program.opts().output, title: data.team?.name || data.name });
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
team
|
|
48
|
+
.command('create')
|
|
49
|
+
.description('Create a team')
|
|
50
|
+
.requiredOption('--name <name>', 'team name')
|
|
51
|
+
.option('--division <divId>', 'division ID')
|
|
52
|
+
.option('--department <deptId>', 'department ID')
|
|
53
|
+
.option('--description <desc>', 'description')
|
|
54
|
+
.action(async (options) => {
|
|
55
|
+
auth.requireAuth();
|
|
56
|
+
const orgId = resolveOrgId(auth, program);
|
|
57
|
+
await client.post(resolveEndpoint('teams.create', { orgId }).path, {
|
|
58
|
+
service: resolveEndpoint('teams.create', { orgId }).service,
|
|
59
|
+
body: {
|
|
60
|
+
name: options.name,
|
|
61
|
+
division_id: options.division,
|
|
62
|
+
department_id: options.department,
|
|
63
|
+
description: options.description,
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
printSuccess(`Team "${options.name}" created.`);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
team
|
|
70
|
+
.command('update')
|
|
71
|
+
.description('Update a team')
|
|
72
|
+
.argument('<teamId>', 'team ID')
|
|
73
|
+
.option('--name <name>', 'new name')
|
|
74
|
+
.option('--description <desc>', 'new description')
|
|
75
|
+
.action(async (teamId, options) => {
|
|
76
|
+
auth.requireAuth();
|
|
77
|
+
const orgId = resolveOrgId(auth, program);
|
|
78
|
+
const body = {};
|
|
79
|
+
if (options.name) body.name = options.name;
|
|
80
|
+
if (options.description) body.description = options.description;
|
|
81
|
+
await client.patch(resolveEndpoint('teams.update', { orgId, teamId }).path, { service: resolveEndpoint('teams.update', { orgId, teamId }).service, body });
|
|
82
|
+
printSuccess('Team updated.');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
team
|
|
86
|
+
.command('delete')
|
|
87
|
+
.description('Delete a team')
|
|
88
|
+
.argument('<teamId>', 'team ID')
|
|
89
|
+
.action(async (teamId) => {
|
|
90
|
+
auth.requireAuth();
|
|
91
|
+
const orgId = resolveOrgId(auth, program);
|
|
92
|
+
await client.delete(resolveEndpoint('teams.delete', { orgId, teamId }).path, { service: resolveEndpoint('teams.delete', { orgId, teamId }).service });
|
|
93
|
+
printSuccess('Team deleted.');
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
team
|
|
97
|
+
.command('provision-room')
|
|
98
|
+
.description('Provision (or adopt) the governed Matrix room for a team')
|
|
99
|
+
.argument('<teamId>', 'team ID')
|
|
100
|
+
.action(async (teamId) => {
|
|
101
|
+
auth.requireAuth();
|
|
102
|
+
const orgId = resolveOrgId(auth, program);
|
|
103
|
+
const ep = resolveEndpoint('teams.provisionRoom', { orgId, teamId });
|
|
104
|
+
const data = await client.post(ep.path, { service: ep.service, body: {} });
|
|
105
|
+
printSuccess('Team Matrix room provisioned.');
|
|
106
|
+
const room = data.room || data;
|
|
107
|
+
formatDetail(room, { format: program.opts().output, title: 'Matrix Room' });
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Team members
|
|
111
|
+
const members = team
|
|
112
|
+
.command('members')
|
|
113
|
+
.description('Manage team members');
|
|
114
|
+
|
|
115
|
+
members
|
|
116
|
+
.command('add')
|
|
117
|
+
.description('Add a member to a team')
|
|
118
|
+
.argument('<teamId>', 'team ID')
|
|
119
|
+
.requiredOption('--user <userId>', 'user ID')
|
|
120
|
+
.option('--role <role>', 'team role', 'member')
|
|
121
|
+
.action(async (teamId, options) => {
|
|
122
|
+
auth.requireAuth();
|
|
123
|
+
const orgId = resolveOrgId(auth, program);
|
|
124
|
+
await client.post(resolveEndpoint('teams.members.create', { orgId, teamId }).path, {
|
|
125
|
+
service: resolveEndpoint('teams.members.create', { orgId, teamId }).service,
|
|
126
|
+
body: { user_id: options.user, role: options.role },
|
|
127
|
+
});
|
|
128
|
+
printSuccess('Member added to team.');
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
members
|
|
132
|
+
.command('remove')
|
|
133
|
+
.description('Remove a member from a team')
|
|
134
|
+
.argument('<teamId>', 'team ID')
|
|
135
|
+
.requiredOption('--user <userId>', 'user ID')
|
|
136
|
+
.action(async (teamId, options) => {
|
|
137
|
+
auth.requireAuth();
|
|
138
|
+
const orgId = resolveOrgId(auth, program);
|
|
139
|
+
await client.delete(resolveEndpoint('teams.members.delete', { orgId, teamId, user: options.user }).path, { service: resolveEndpoint('teams.members.delete', { orgId, teamId, user: options.user }).service });
|
|
140
|
+
printSuccess('Member removed from team.');
|
|
141
|
+
});
|
|
142
|
+
}
|