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,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Approvals commands: result (quox#791), grants list|create|revoke (fleet standing grants, 2026-10-13)
|
|
3
|
+
*
|
|
4
|
+
* After a human approves a held tool call (e.g. a gated ssh_exec) the collector
|
|
5
|
+
* runs it and stores the outcome. `quox approvals result <id>` reads it back.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { resolveEndpoint } from '../api/endpoints.js';
|
|
9
|
+
|
|
10
|
+
import { attachWalkthrough } from './walkthrough.js';
|
|
11
|
+
|
|
12
|
+
export function registerApprovalsCommands(program, ctx) {
|
|
13
|
+
const { client, auth } = ctx;
|
|
14
|
+
|
|
15
|
+
const approvals = program
|
|
16
|
+
.command('approvals')
|
|
17
|
+
.description('Tool approvals (held actions awaiting or past a human decision)');
|
|
18
|
+
attachWalkthrough(approvals, ctx, program);
|
|
19
|
+
|
|
20
|
+
approvals
|
|
21
|
+
.command('result <approvalId>')
|
|
22
|
+
.description('Show the status and stored output of an approved tool call')
|
|
23
|
+
.option('--org <id>', 'org ID (service-key automation callers; defaults to active org / QUOX_ORG_ID)')
|
|
24
|
+
.action(async (approvalId, options) => {
|
|
25
|
+
auth.requireAuth();
|
|
26
|
+
const ep = resolveEndpoint('v1.approvals.result', { id: approvalId });
|
|
27
|
+
const orgId = auth.getOrgId(options.org || process.env.QUOX_ORG_ID);
|
|
28
|
+
const query = orgId ? { org_id: orgId } : undefined;
|
|
29
|
+
const data = await client.get(ep.path, { service: ep.service, ...(query ? { query } : {}) });
|
|
30
|
+
|
|
31
|
+
if (program.opts().output === 'json') {
|
|
32
|
+
console.log(JSON.stringify(data, null, 2));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
console.log(`Approval ${data.approval_id} tool: ${data.tool} status: ${data.status}`
|
|
36
|
+
+ (data.executed_at ? ` executed: ${data.executed_at}` : ''));
|
|
37
|
+
if (data.result === null || data.result === undefined) {
|
|
38
|
+
if (data.status === 'pending') console.log('Still pending: a human has not decided yet.');
|
|
39
|
+
else if (data.status === 'resuming') console.log('Approved, executing. Re-run shortly.');
|
|
40
|
+
else console.log('No stored output.');
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const r = data.result;
|
|
44
|
+
if (typeof r === 'string') { console.log(r); return; }
|
|
45
|
+
if (r.success === false) console.log(`Failed: ${r.error || 'unknown error'}`);
|
|
46
|
+
const out = r.output ?? r.stdout ?? r.result;
|
|
47
|
+
if (out !== undefined) console.log(typeof out === 'string' ? out : JSON.stringify(out, null, 2));
|
|
48
|
+
else console.log(JSON.stringify(r, null, 2));
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Fleet standing grants: an org admin pre-approves ONE host + an anchored command
|
|
52
|
+
// shape + a VMID range until an expiry, for ssh_exec. Every use still lands in
|
|
53
|
+
// approvals history with an AEE envelope; anything outside the grant files HITL.
|
|
54
|
+
const grants = approvals
|
|
55
|
+
.command('grants')
|
|
56
|
+
.description('Standing grants: org-admin pre-approved fleet command lanes (ssh_exec)');
|
|
57
|
+
|
|
58
|
+
grants
|
|
59
|
+
.command('list')
|
|
60
|
+
.description('List active standing grants (--all includes revoked and expired)')
|
|
61
|
+
.option('--all', 'include revoked and expired grants')
|
|
62
|
+
.action(async (options) => {
|
|
63
|
+
auth.requireAuth();
|
|
64
|
+
const ep = resolveEndpoint('v1.approvals.grants.list');
|
|
65
|
+
const data = await client.get(ep.path, { service: ep.service, ...(options.all ? { query: { all: '1' } } : {}) });
|
|
66
|
+
if (program.opts().output === 'json') { console.log(JSON.stringify(data, null, 2)); return; }
|
|
67
|
+
const rows = data.grants || [];
|
|
68
|
+
if (!rows.length) { console.log('No standing grants.'); return; }
|
|
69
|
+
for (const g of rows) {
|
|
70
|
+
const state = g.revoked_at ? `revoked ${g.revoked_at}` : `expires ${g.expires_at}`;
|
|
71
|
+
const range = g.vmid_min != null ? ` vmids ${g.vmid_min}-${g.vmid_max}` : '';
|
|
72
|
+
console.log(`${g.grant_id} ${g.tool}@${g.host}${range} ${g.preset || `${g.patterns.length} patterns`} uses ${g.use_count} ${state}`);
|
|
73
|
+
console.log(` reason: ${g.reason} (by ${g.created_by})`);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
grants
|
|
78
|
+
.command('create')
|
|
79
|
+
.description('Create a standing grant (human org admin only)')
|
|
80
|
+
.requiredOption('--host <hostId>', 'the ONE host the grant covers')
|
|
81
|
+
.requiredOption('--reason <text>', 'why (shown in history and evidence)')
|
|
82
|
+
.option('--preset <name>', 'proxmox-test-vm-lane (clone/power/destroy/guest-exec in a VMID range)')
|
|
83
|
+
.option('--template <vmid>', 'template VMID the lane clones from (preset)')
|
|
84
|
+
.option('--vmid-range <min-max>', 'VMID range, e.g. 9100-9199')
|
|
85
|
+
.option('--name-prefix <prefix>', 'VM name prefix the lane may create (preset)', 'z2h')
|
|
86
|
+
.option('--pattern <regex>', 'custom anchored command regex (repeatable; instead of --preset)', (v, a) => (a || []).concat([v]))
|
|
87
|
+
.option('--days <n>', 'expiry in days (max 30)', '14')
|
|
88
|
+
.action(async (options) => {
|
|
89
|
+
auth.requireAuth();
|
|
90
|
+
const body = { tool: 'ssh_exec', host: options.host, reason: options.reason, expires_in_days: Number(options.days) };
|
|
91
|
+
if (options.vmidRange) {
|
|
92
|
+
const m = /^(\d+)-(\d+)$/.exec(options.vmidRange);
|
|
93
|
+
if (!m) { console.error('--vmid-range must look like 9100-9199'); process.exitCode = 1; return; }
|
|
94
|
+
body.vmid_min = Number(m[1]); body.vmid_max = Number(m[2]);
|
|
95
|
+
}
|
|
96
|
+
if (options.preset) {
|
|
97
|
+
body.preset = options.preset; body.template_vmid = Number(options.template); body.name_prefix = options.namePrefix;
|
|
98
|
+
} else {
|
|
99
|
+
body.patterns = options.pattern || [];
|
|
100
|
+
}
|
|
101
|
+
const ep = resolveEndpoint('v1.approvals.grants.create');
|
|
102
|
+
const data = await client.post(ep.path, { service: ep.service, body });
|
|
103
|
+
if (program.opts().output === 'json') { console.log(JSON.stringify(data, null, 2)); return; }
|
|
104
|
+
const g = data.grant || {};
|
|
105
|
+
console.log(`Created ${g.grant_id}: ${g.tool}@${g.host}${g.vmid_min != null ? ` vmids ${g.vmid_min}-${g.vmid_max}` : ''}, expires ${g.expires_at}`);
|
|
106
|
+
console.log(`Revoke any time: quox approvals grants revoke ${g.grant_id}`);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
grants
|
|
110
|
+
.command('revoke <grantId>')
|
|
111
|
+
.description('Revoke a standing grant now (human org admin only)')
|
|
112
|
+
.action(async (grantId) => {
|
|
113
|
+
auth.requireAuth();
|
|
114
|
+
const ep = resolveEndpoint('v1.approvals.grants.revoke', { id: grantId });
|
|
115
|
+
const data = await client.post(ep.path, { service: ep.service, body: {} });
|
|
116
|
+
if (program.opts().output === 'json') { console.log(JSON.stringify(data, null, 2)); return; }
|
|
117
|
+
console.log(`Revoked ${data.grant?.grant_id || grantId} at ${data.grant?.revoked_at || 'now'}.`);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* quox aside "<question>"
|
|
3
|
+
*
|
|
4
|
+
* A read-only side question: the model gets no tools and no conversation, so nothing it says can change
|
|
5
|
+
* anything or land in a conversation's history. The TUI's /aside is the same call with the recent
|
|
6
|
+
* exchanges passed as read-only context.
|
|
7
|
+
*/
|
|
8
|
+
import { askAside } from '../core/aside.js';
|
|
9
|
+
|
|
10
|
+
export function registerAsideCommand(program, ctx) {
|
|
11
|
+
const { client, auth } = ctx;
|
|
12
|
+
program
|
|
13
|
+
.command('aside')
|
|
14
|
+
.description('Ask a read-only side question: no tools, not saved to any conversation')
|
|
15
|
+
.argument('<question...>', 'the question')
|
|
16
|
+
.option('--agent <id>', 'who answers (default quox)')
|
|
17
|
+
.action(async (words, opts) => {
|
|
18
|
+
auth.requireAuth();
|
|
19
|
+
const r = await askAside(client, { question: words.join(' '), agent: opts.agent });
|
|
20
|
+
if (program.opts().output === 'json') { console.log(JSON.stringify({ answer: r.text, model: r.model, provider: r.provider, tools_used: r.tools, read_only: true }, null, 2)); return; }
|
|
21
|
+
console.log(r.text || '(no answer)');
|
|
22
|
+
console.log(`· aside, read only: no tools, not saved${r.model ? ` · ${r.provider ? `${r.provider}/` : ''}${r.model}` : ''}`);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `quox ask`: a session puts a fork in front of a human through the Approvals inbox (one inbox item, kind decision).
|
|
3
|
+
* Who is asking, what, why, the options, the recommendation and the expiry travel with it, so ONE HITL session
|
|
4
|
+
* can answer for twenty terminals. Not an approval of an action: no step-up PIN unless --high-risk.
|
|
5
|
+
*/
|
|
6
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
7
|
+
import { execFileSync } from 'node:child_process';
|
|
8
|
+
import { homedir } from 'node:os';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { resolveEndpoint } from '../api/endpoints.js';
|
|
11
|
+
import { resolveOrgId } from './helpers.js';
|
|
12
|
+
import { readPresence, approvalPresenceFields } from './presence.js';
|
|
13
|
+
import { toRepoRelative, LOOSENING_HINT } from '../core/repoPath.js';
|
|
14
|
+
import { parseOptions, parseDuration, YN_OPTIONS, waitForDecision, EXIT_NO_ANSWER } from '../core/askDecision.js';
|
|
15
|
+
|
|
16
|
+
function heldSlotFor(session) {
|
|
17
|
+
try {
|
|
18
|
+
const all = JSON.parse(readFileSync(join(homedir(), '.quox', 'held-slots.json'), 'utf8'));
|
|
19
|
+
const want = String(session || '').toLowerCase();
|
|
20
|
+
return Object.keys(all).find((k) => String(all[k]?.session || '').toLowerCase() === want) || null;
|
|
21
|
+
} catch { return null; }
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function registerAskCommands(program, { client, auth }) {
|
|
25
|
+
const err = (s) => process.stderr.write(`${s}\n`);
|
|
26
|
+
|
|
27
|
+
async function waitAndPrint(orgId, id, { timeoutSec = null } = {}) {
|
|
28
|
+
const r = await waitForDecision({
|
|
29
|
+
poll: (w) => { const ep = resolveEndpoint('inbox.decision.get', { orgId, id }); return client.get(ep.path, { service: ep.service, query: { wait: w }, timeout: (w + 15) * 1000, retries: 0 }); },
|
|
30
|
+
log: err,
|
|
31
|
+
maxWaitMs: timeoutSec != null ? timeoutSec * 1000 : null,
|
|
32
|
+
});
|
|
33
|
+
if (r.stdout) console.log(r.stdout);
|
|
34
|
+
process.exitCode = r.code;
|
|
35
|
+
return r;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const ask = program
|
|
39
|
+
.command('ask')
|
|
40
|
+
.description('Ask a human a question through the Approvals inbox: who asks, what, why, the options. Use this instead of asking in your own terminal')
|
|
41
|
+
.option('--session <name>', 'which session is asking (default: $QUOX_SESSION)')
|
|
42
|
+
.option('--title <text>', 'what you are asking, one line')
|
|
43
|
+
.option('--why <text>', 'a simple why: what the human needs to know to decide')
|
|
44
|
+
.option('--justify <text>', 'for a loosening (a check made easier to pass): why it is safe, in plain words; the card shows it on its JUSTIFY line and defaults to No without one')
|
|
45
|
+
.option('--options <list>', 'the choices: "a: Ship now|b: Wait for review|c: Drop it"')
|
|
46
|
+
.option('--yn', 'shorthand for a yes/no question (options y and n)')
|
|
47
|
+
.option('--default <key>', 'the option you would take if nobody answers (shown, never applied for you)')
|
|
48
|
+
.option('--recommend <key>', 'the option you recommend')
|
|
49
|
+
.option('--expires <dur>', 'how long it stays open: 30m, 2h, 1d (default 24h, max 30d)')
|
|
50
|
+
.option('--slot <name>', 'your slot, so the answer is also posted there (default: found from held slots)')
|
|
51
|
+
.option('--agent <name>', 'the agent asking, when it is an agent rather than a session')
|
|
52
|
+
.option('--high-risk', 'the answer needs the human step-up PIN')
|
|
53
|
+
.option('--wait', 'block until answered; prints the chosen option key (and any note) on stdout, exits 2 on expiry or deny')
|
|
54
|
+
.option('--timeout <dur>', 'with --wait: stop waiting after this long (the question stays open)')
|
|
55
|
+
.action((options) => fileAsk(options));
|
|
56
|
+
|
|
57
|
+
async function fileAsk(options) {
|
|
58
|
+
auth.requireAuth();
|
|
59
|
+
const orgId = resolveOrgId(auth, program);
|
|
60
|
+
const session = options.session || process.env.QUOX_SESSION;
|
|
61
|
+
if (!session) throw new Error('say which session is asking: --session <NAME>');
|
|
62
|
+
if (!options.title) throw new Error('say what you are asking: --title "<what>"');
|
|
63
|
+
if (options.yn && options.options) throw new Error('use --yn or --options, not both');
|
|
64
|
+
if (!options.yn && !options.options) throw new Error('give the choices: --options "a: Ship now|b: Wait" (or --yn)');
|
|
65
|
+
// QUOXON 2026-10-17: a high-risk ask (a loosening, anything the owner must PIN) carries a plain justification
|
|
66
|
+
// 2026-10-19: three PIN approvals were wasted on loosening asks filed without --high-risk or with unusable paths
|
|
67
|
+
if (!options.highRisk && /^\s*approve\s+(?:loosening|test)/i.test(options.title)) { err(`A test-edit approval must go through the loosening verb, which sets --high-risk and repo-relative paths for you:\n ${LOOSENING_HINT}`); process.exitCode = 2; return; }
|
|
68
|
+
if (options.highRisk && !String(options.justify || '').trim()) { err('High-risk asks need --justify "<2-3 plain lines the owner can judge>"'); process.exitCode = 2; return; }
|
|
69
|
+
const opts = options.yn ? YN_OPTIONS : parseOptions(options.options);
|
|
70
|
+
const body = {
|
|
71
|
+
session, title: options.title, why: options.why, options: opts,
|
|
72
|
+
...(options.justify ? { justification: options.justify } : {}),
|
|
73
|
+
default: options.default, recommend: options.recommend,
|
|
74
|
+
...(options.expires ? { expires_in_seconds: parseDuration(options.expires) } : {}),
|
|
75
|
+
high_risk: Boolean(options.highRisk),
|
|
76
|
+
slot: options.slot || heldSlotFor(session) || undefined,
|
|
77
|
+
profile: program.opts().profile || process.env.QUOX_PROFILE || undefined,
|
|
78
|
+
agent: options.agent,
|
|
79
|
+
};
|
|
80
|
+
const ep = resolveEndpoint('inbox.decision.create', { orgId });
|
|
81
|
+
const data = await client.post(ep.path, { service: ep.service, body });
|
|
82
|
+
// PRESENCE (owner 2026-10-16): say now whether the human is away, so this session can work on
|
|
83
|
+
// something else instead of waiting. The question is filed and queued exactly as before.
|
|
84
|
+
const presence = approvalPresenceFields(await readPresence(client, orgId));
|
|
85
|
+
const d = { ...data.decision, ...presence };
|
|
86
|
+
if (program.opts().output === 'json' && !options.wait) { console.log(JSON.stringify(d, null, 2)); return; }
|
|
87
|
+
err(`asked: ${d.id} (${session}: ${d.title}); it shows in /approvals${d.expires_at ? `, open until ${d.expires_at}` : ''}`);
|
|
88
|
+
if (presence.owner_away) err(`${presence.owner_away_notice}. Expect a wait: work on something else meanwhile.`);
|
|
89
|
+
if (!options.wait) { console.log(d.id); return; }
|
|
90
|
+
await waitAndPrint(orgId, d.id, { timeoutSec: options.timeout ? parseDuration(options.timeout) : null });
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
ask
|
|
94
|
+
.command('loosening')
|
|
95
|
+
.description('Ask a human to approve edits to test files (a check made easier to pass). Files a yes/no, high-risk (PIN) ask with repo-relative paths')
|
|
96
|
+
.option('--paths <files...>', 'every test file the commit edits (absolute, worktree or repo-relative: all are normalised)')
|
|
97
|
+
.option('--justify <text>', 'why it is safe, in plain words (required)')
|
|
98
|
+
.option('--why <text>', 'detail: the findings, before and after lines')
|
|
99
|
+
.option('--session <name>', 'which session is asking (default: $QUOX_SESSION)')
|
|
100
|
+
.option('--slot <name>', 'your slot')
|
|
101
|
+
.option('--expires <dur>', 'how long it stays open')
|
|
102
|
+
.option('--wait', 'block until answered')
|
|
103
|
+
.option('--timeout <dur>', 'with --wait: stop waiting after this long')
|
|
104
|
+
.action(async (subOptions) => {
|
|
105
|
+
// commander lets the parent `ask` swallow flags it shares with this verb (--justify, --why, --session...), so merge both
|
|
106
|
+
const options = { ...ask.opts(), ...Object.fromEntries(Object.entries(subOptions).filter(([, v]) => v !== undefined)) };
|
|
107
|
+
if (!String(options.justify || '').trim()) { err('say why it is safe: --justify "<plain words>"'); process.exitCode = 2; return; }
|
|
108
|
+
const raw = [].concat(options.paths || []).flatMap((x) => String(x).split(',')).map((x) => x.trim()).filter(Boolean);
|
|
109
|
+
let root;
|
|
110
|
+
try { root = execFileSync('git', ['rev-parse', '--show-toplevel'], { encoding: 'utf8' }).trim(); } catch { root = process.cwd(); }
|
|
111
|
+
const paths = [...new Set(raw.map(toRepoRelative))];
|
|
112
|
+
const missing = paths.filter((p) => !p || !existsSync(join(root, p)));
|
|
113
|
+
if (!paths.length || missing.length) { err(`not found in this repo (${root}): ${missing.join(', ') || '(no paths)'}. Run from the worktree and name files that exist.`); process.exitCode = 2; return; }
|
|
114
|
+
// 2026-10-19: the server truncates long titles, and the attestation names only paths found in title+body,
|
|
115
|
+
// so a 7-file ask covered 3. Every path also goes in the body.
|
|
116
|
+
const files = `Files (${paths.length}):\n${paths.map((p) => `- ${p}`).join('\n')}`;
|
|
117
|
+
await fileAsk({ ...options, title: `Approve test edits: ${paths.join(' ')}`, why: options.why ? `${files}\n\n${options.why}` : files, yn: true, highRisk: true, justify: options.justify });
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
ask
|
|
121
|
+
.command('status')
|
|
122
|
+
.description('Show where a question stands: pending, answered, denied or expired, with the answer')
|
|
123
|
+
.argument('<id>', 'the id `quox ask` printed')
|
|
124
|
+
.action(async (id) => {
|
|
125
|
+
auth.requireAuth();
|
|
126
|
+
const orgId = resolveOrgId(auth, program);
|
|
127
|
+
const ep = resolveEndpoint('inbox.decision.get', { orgId, id });
|
|
128
|
+
const d = (await client.get(ep.path, { service: ep.service })).decision;
|
|
129
|
+
if (program.opts().output === 'json') { console.log(JSON.stringify(d, null, 2)); return; }
|
|
130
|
+
console.log(`${d.state}${d.answer?.option ? ` ${d.answer.option}` : ''}${d.answer?.note ? ` (${d.answer.note})` : ''}`);
|
|
131
|
+
if (d.state === 'expired' || d.state === 'denied') process.exitCode = EXIT_NO_ANSWER;
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
ask
|
|
135
|
+
.command('wait')
|
|
136
|
+
.description('Block until a question is answered; prints the chosen option key (and note), exits 2 on expiry or deny')
|
|
137
|
+
.argument('<id>', 'the id `quox ask` printed')
|
|
138
|
+
.option('--timeout <dur>', 'stop waiting after this long (the question stays open)')
|
|
139
|
+
.action(async (id, options) => {
|
|
140
|
+
auth.requireAuth();
|
|
141
|
+
const orgId = resolveOrgId(auth, program);
|
|
142
|
+
await waitAndPrint(orgId, id, { timeoutSec: options.timeout ? parseDuration(options.timeout) : null });
|
|
143
|
+
});
|
|
144
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Assistant commands: CRUD, deploy, fork
|
|
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
|
+
import { QuoxError } from '../core/errors.js';
|
|
9
|
+
|
|
10
|
+
// #1049: auth routes/assistants.js DEPLOYMENT_MODES (the server is the authority).
|
|
11
|
+
const DEPLOY_MODES = ['private', 'shared', 'public'];
|
|
12
|
+
|
|
13
|
+
export function registerAssistantCommands(program, ctx) {
|
|
14
|
+
const { client, auth } = ctx;
|
|
15
|
+
|
|
16
|
+
const assistant = program
|
|
17
|
+
.command('assistant')
|
|
18
|
+
.description('Manage assistants');
|
|
19
|
+
|
|
20
|
+
assistant
|
|
21
|
+
.command('list')
|
|
22
|
+
.description('List assistants')
|
|
23
|
+
.action(async () => {
|
|
24
|
+
auth.requireAuth();
|
|
25
|
+
const orgId = resolveOrgId(auth, program);
|
|
26
|
+
const data = await client.get(resolveEndpoint('assistants.list', { orgId }).path, { service: resolveEndpoint('assistants.list', { orgId }).service });
|
|
27
|
+
formatOutput({
|
|
28
|
+
// fleet #392: route returns active_deployments, not deployed.
|
|
29
|
+
columns: ['id', 'name', 'status', 'active_deployments', 'created_at'],
|
|
30
|
+
headers: ['ID', 'Name', 'Status', 'Deployed', 'Created'],
|
|
31
|
+
rows: data.items || data.assistants || data,
|
|
32
|
+
}, { format: program.opts().output });
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
assistant
|
|
36
|
+
.command('get')
|
|
37
|
+
.description('Get assistant details')
|
|
38
|
+
.argument('<assistantId>', 'assistant ID')
|
|
39
|
+
.action(async (assistantId) => {
|
|
40
|
+
auth.requireAuth();
|
|
41
|
+
const orgId = resolveOrgId(auth, program);
|
|
42
|
+
const data = await client.get(resolveEndpoint('assistants.get', { orgId, assistantId }).path, { service: resolveEndpoint('assistants.get', { orgId, assistantId }).service });
|
|
43
|
+
formatDetail(data.assistant || data, { format: program.opts().output, title: data.assistant?.name || data.name });
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
assistant
|
|
47
|
+
.command('create')
|
|
48
|
+
.description('Create an assistant')
|
|
49
|
+
.requiredOption('--name <name>', 'assistant name')
|
|
50
|
+
.option('--persona <text>', 'persona/system prompt')
|
|
51
|
+
.option('--description <desc>', 'description')
|
|
52
|
+
.action(async (options) => {
|
|
53
|
+
auth.requireAuth();
|
|
54
|
+
const orgId = resolveOrgId(auth, program);
|
|
55
|
+
const body = { name: options.name };
|
|
56
|
+
if (options.persona) body.persona = options.persona;
|
|
57
|
+
if (options.description) body.description = options.description;
|
|
58
|
+
await client.post(resolveEndpoint('assistants.create', { orgId }).path, { service: resolveEndpoint('assistants.create', { orgId }).service, body });
|
|
59
|
+
printSuccess(`Assistant "${options.name}" created.`);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
assistant
|
|
63
|
+
.command('update')
|
|
64
|
+
.description('Update an assistant')
|
|
65
|
+
.argument('<assistantId>', 'assistant ID')
|
|
66
|
+
.option('--name <name>', 'new name')
|
|
67
|
+
.option('--persona <text>', 'new persona')
|
|
68
|
+
.option('--description <desc>', 'new description')
|
|
69
|
+
.action(async (assistantId, options) => {
|
|
70
|
+
auth.requireAuth();
|
|
71
|
+
const orgId = resolveOrgId(auth, program);
|
|
72
|
+
const body = {};
|
|
73
|
+
if (options.name) body.name = options.name;
|
|
74
|
+
if (options.persona) body.persona = options.persona;
|
|
75
|
+
if (options.description) body.description = options.description;
|
|
76
|
+
await client.patch(resolveEndpoint('assistants.update', { orgId, assistantId }).path, { service: resolveEndpoint('assistants.update', { orgId, assistantId }).service, body });
|
|
77
|
+
printSuccess('Assistant updated.');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
assistant
|
|
81
|
+
.command('delete')
|
|
82
|
+
.description('Delete an assistant')
|
|
83
|
+
.argument('<assistantId>', 'assistant ID')
|
|
84
|
+
.action(async (assistantId) => {
|
|
85
|
+
auth.requireAuth();
|
|
86
|
+
const orgId = resolveOrgId(auth, program);
|
|
87
|
+
await client.delete(resolveEndpoint('assistants.delete', { orgId, assistantId }).path, { service: resolveEndpoint('assistants.delete', { orgId, assistantId }).service });
|
|
88
|
+
printSuccess('Assistant deleted.');
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
assistant
|
|
92
|
+
.command('publish')
|
|
93
|
+
.description('Publish a draft assistant (draft to active), so it can be deployed')
|
|
94
|
+
.argument('<assistantId>', 'assistant ID')
|
|
95
|
+
.action(async (assistantId) => {
|
|
96
|
+
auth.requireAuth();
|
|
97
|
+
const orgId = resolveOrgId(auth, program);
|
|
98
|
+
// #1028: create makes a draft and deploy refuses anything not active; this is the step between.
|
|
99
|
+
const ep = resolveEndpoint('assistants.publish', { orgId, assistantId });
|
|
100
|
+
await client.post(ep.path, { service: ep.service });
|
|
101
|
+
printSuccess('Assistant published.');
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
assistant
|
|
105
|
+
.command('deploy')
|
|
106
|
+
.description('Deploy an active assistant to a scope (scope ids: quox org divisions list, quox department list, quox team list)')
|
|
107
|
+
.argument('<assistantId>', 'assistant ID')
|
|
108
|
+
.option('--scope <scopeId>', 'scope ID to deploy to (required)')
|
|
109
|
+
.option('--target <scopeId>', 'alias for --scope')
|
|
110
|
+
.option('--mode <mode>', `${DEPLOY_MODES.join(', ')} (default shared)`)
|
|
111
|
+
.action(async (assistantId, options) => {
|
|
112
|
+
auth.requireAuth();
|
|
113
|
+
const orgId = resolveOrgId(auth, program);
|
|
114
|
+
// #998: the auth route requires scope_id; the CLI used to send { target }.
|
|
115
|
+
const scopeId = options.scope || options.target;
|
|
116
|
+
if (!scopeId) throw new QuoxError('assistant deploy needs --scope <scopeId>.', 1);
|
|
117
|
+
// #1049: the server's modes (auth routes/assistants.js DEPLOYMENT_MODES); refuse anything else here.
|
|
118
|
+
if (options.mode && !DEPLOY_MODES.includes(options.mode)) {
|
|
119
|
+
throw new QuoxError(`--mode must be one of: ${DEPLOY_MODES.join(', ')} (got "${options.mode}").`, 1);
|
|
120
|
+
}
|
|
121
|
+
const body = { scope_id: scopeId };
|
|
122
|
+
if (options.mode) body.mode = options.mode;
|
|
123
|
+
await client.post(resolveEndpoint('assistants.deploy', { orgId, assistantId }).path, { service: resolveEndpoint('assistants.deploy', { orgId, assistantId }).service, body });
|
|
124
|
+
printSuccess('Assistant deployed.');
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
assistant
|
|
128
|
+
.command('undeploy')
|
|
129
|
+
.description('Remove a deployment of an assistant (by --deployment id, or the active one at --scope)')
|
|
130
|
+
.argument('<assistantId>', 'assistant ID')
|
|
131
|
+
.option('--deployment <deploymentId>', 'deployment ID to remove (see quox assistant get)')
|
|
132
|
+
.option('--scope <scopeId>', 'remove the active deployment at this scope')
|
|
133
|
+
.action(async (assistantId, options) => {
|
|
134
|
+
auth.requireAuth();
|
|
135
|
+
const orgId = resolveOrgId(auth, program);
|
|
136
|
+
// #1049: a deployed assistant could not be removed from the CLI.
|
|
137
|
+
let deploymentId = options.deployment;
|
|
138
|
+
if (!deploymentId) {
|
|
139
|
+
if (!options.scope) throw new QuoxError('assistant undeploy needs --deployment <id> or --scope <scopeId>.', 1);
|
|
140
|
+
const g = resolveEndpoint('assistants.get', { orgId, assistantId });
|
|
141
|
+
const data = await client.get(g.path, { service: g.service });
|
|
142
|
+
const deps = (data && data.assistant && data.assistant.deployments) || (data && data.deployments) || [];
|
|
143
|
+
const live = deps.filter((d) => d.status === 'active');
|
|
144
|
+
const hit = live.find((d) => d.scope_id === options.scope);
|
|
145
|
+
if (!hit) {
|
|
146
|
+
const where = live.length ? live.map((d) => `${d.scope_id} (${d.id})`).join(', ') : 'nowhere';
|
|
147
|
+
throw new QuoxError(`No active deployment of ${assistantId} at scope ${options.scope}. It is deployed at: ${where}.`, 1);
|
|
148
|
+
}
|
|
149
|
+
deploymentId = hit.id;
|
|
150
|
+
}
|
|
151
|
+
const ep = resolveEndpoint('assistants.undeploy', { orgId, assistantId, deploymentId });
|
|
152
|
+
await client.delete(ep.path, { service: ep.service });
|
|
153
|
+
printSuccess(`Deployment ${deploymentId} removed.`);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
assistant
|
|
157
|
+
.command('fork')
|
|
158
|
+
.description('Fork an assistant')
|
|
159
|
+
.argument('<assistantId>', 'assistant ID to fork')
|
|
160
|
+
.option('--name <name>', 'name for the fork')
|
|
161
|
+
.action(async (assistantId, options) => {
|
|
162
|
+
auth.requireAuth();
|
|
163
|
+
const orgId = resolveOrgId(auth, program);
|
|
164
|
+
const body = {};
|
|
165
|
+
if (options.name) body.name = options.name;
|
|
166
|
+
await client.post(resolveEndpoint('assistants.fork', { orgId, assistantId }).path, { service: resolveEndpoint('assistants.fork', { orgId, assistantId }).service, body });
|
|
167
|
+
printSuccess('Assistant forked.');
|
|
168
|
+
});
|
|
169
|
+
}
|