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,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `quox contacts selftest [--agent]`: drives the ContactsQ READ path against a dedicated demo
|
|
3
|
+
* contact and prints a pass/fail table. Never dials, sends or leases context (those file
|
|
4
|
+
* approvals). With --agent the same checks run through the attached agent's tool scope
|
|
5
|
+
* (POST /api/v1/tools/execute with the attach token, exactly like `quox agent exec`).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { QuoxApiError, QuoxError } from '../core/errors.js';
|
|
9
|
+
import { line as glyphLine, printEvent } from '../core/quoxglyph.js';
|
|
10
|
+
import { resolveEndpoint } from '../api/endpoints.js';
|
|
11
|
+
import { ensureFreshAttachToken, execResultFailed } from './agentAttach.js';
|
|
12
|
+
|
|
13
|
+
export const DEMO_NAME = 'ContactsQ Selftest (demo)';
|
|
14
|
+
export const DEMO_PHONE = '+44 7911 123000';
|
|
15
|
+
export const DEMO_EMAIL = 'selftest@example.com';
|
|
16
|
+
export const DEMO_TAG = 'selftest';
|
|
17
|
+
const AGENT_ID = 'contactsq';
|
|
18
|
+
|
|
19
|
+
const errText = (e) => (e instanceof QuoxApiError ? `${e.status} ${(e.body && e.body.error) || e.message}` : (e && e.message) || String(e));
|
|
20
|
+
|
|
21
|
+
/** Find the demo contact or create it (human path). Idempotent. */
|
|
22
|
+
export async function ensureDemoContact(client) {
|
|
23
|
+
const list = resolveEndpoint('contactsq.contacts.list');
|
|
24
|
+
const found = await client.get(list.path, { service: list.service, query: { q: 'Selftest', limit: 50 } });
|
|
25
|
+
const hit = (found.contacts || []).find((c) => c.display_name === DEMO_NAME);
|
|
26
|
+
if (hit) return { id: hit.id, created: false };
|
|
27
|
+
const create = resolveEndpoint('contactsq.contacts.create');
|
|
28
|
+
const made = await client.post(create.path, {
|
|
29
|
+
service: create.service,
|
|
30
|
+
body: { display_name: DEMO_NAME, identifiers: [{ channel: 'phone', value: DEMO_PHONE, is_primary: true }, { channel: 'email', value: DEMO_EMAIL, is_primary: true }] },
|
|
31
|
+
});
|
|
32
|
+
const id = made.contact && made.contact.id;
|
|
33
|
+
if (!id) throw new QuoxError('Could not create the selftest demo contact.', 1);
|
|
34
|
+
const upd = resolveEndpoint('contactsq.contacts.update', { id });
|
|
35
|
+
// Tagging is a human edit: an attached agent creates the demo contact but may not tag it (403 human_required).
|
|
36
|
+
// The tag is a convenience for people browsing the book, so a refusal here never fails the selftest.
|
|
37
|
+
try {
|
|
38
|
+
await client.put(upd.path, { service: upd.service, body: { tags: [DEMO_TAG] } });
|
|
39
|
+
} catch (e) {
|
|
40
|
+
if (!(e && (e.status === 403 || e.statusCode === 403))) throw e;
|
|
41
|
+
}
|
|
42
|
+
return { id, created: true };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Direct (human) transport: the governed HTTP routes. */
|
|
46
|
+
function directOps(client, id) {
|
|
47
|
+
const get = (key, params, query) => { const ep = resolveEndpoint(key, params); return client.get(ep.path, { service: ep.service, query }); };
|
|
48
|
+
const post = (key, params, body) => { const ep = resolveEndpoint(key, params); return client.post(ep.path, { service: ep.service, body }); };
|
|
49
|
+
return {
|
|
50
|
+
search: (q) => get('contactsq.search', {}, { q }),
|
|
51
|
+
find: (q) => get('contactsq.contacts.list', {}, { q }),
|
|
52
|
+
resolve: (channel, value) => post('contactsq.resolve', {}, { channel, value }),
|
|
53
|
+
// No HTTP route for best_channel: the policy check is the same engine, per channel.
|
|
54
|
+
best_channel: async () => {
|
|
55
|
+
const out = [];
|
|
56
|
+
for (const channel of ['voice', 'email']) {
|
|
57
|
+
const r = await post('contactsq.policy', { id }, { purpose: 'service', channel });
|
|
58
|
+
out.push({ channel, decision: r.decision || (r.policy && r.policy.decision) || null });
|
|
59
|
+
}
|
|
60
|
+
return { alternatives: out };
|
|
61
|
+
},
|
|
62
|
+
timeline: () => get('contactsq.timeline', { id }, {}),
|
|
63
|
+
log: () => post('contactsq.touchpoints.add', { id }, { surface: 'manual', direction: 'internal', outcome: 'selftest' }),
|
|
64
|
+
brief: () => get('contactsq.brief', {}, {}),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Agent transport: the attached agent's own tool scope through /api/v1/tools/execute. */
|
|
69
|
+
async function agentOps(client, id, orgId) {
|
|
70
|
+
const token = await ensureFreshAttachToken(client, AGENT_ID);
|
|
71
|
+
const ep = resolveEndpoint('v1.tools.execute');
|
|
72
|
+
const exec = async (tool, input) => {
|
|
73
|
+
let data;
|
|
74
|
+
try {
|
|
75
|
+
data = await client.post(ep.path, { service: ep.service, noAuth: true, headers: { Authorization: `Bearer ${token}` }, body: { tool_name: tool, input, org_id: orgId } });
|
|
76
|
+
} catch (e) {
|
|
77
|
+
if (e instanceof QuoxApiError && (e.status === 401 || e.status === 403)) {
|
|
78
|
+
throw new Error(`${tool}: attach token for "${AGENT_ID}" refused (${e.status}). Re-attach with \`quox agent attach ${AGENT_ID}\`.`);
|
|
79
|
+
}
|
|
80
|
+
throw e;
|
|
81
|
+
}
|
|
82
|
+
// Tool envelopes vary: unwrap { result } if present, then require success.
|
|
83
|
+
const res = data && typeof data.result === 'object' && data.result ? data.result : data;
|
|
84
|
+
if (execResultFailed(res) || execResultFailed(data)) throw new Error(`${tool}: ${res.error || data.error || 'tool reported failure'}`);
|
|
85
|
+
return res;
|
|
86
|
+
};
|
|
87
|
+
return {
|
|
88
|
+
search: (q) => exec('contacts_search', { q }),
|
|
89
|
+
find: (q) => exec('contacts_find', { q }),
|
|
90
|
+
resolve: (channel, value) => exec('contacts_resolve', { channel, value }),
|
|
91
|
+
best_channel: () => exec('contacts_best_channel', { contact_id: id }),
|
|
92
|
+
timeline: () => exec('contacts_timeline', { contact_id: id }),
|
|
93
|
+
log: () => exec('contacts_log_touchpoint', { contact_id: id, surface: 'manual', direction: 'internal', outcome: 'selftest' }),
|
|
94
|
+
brief: () => exec('contacts_brief', {}),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const idsOf = (r) => [...(r.candidates || []), ...(r.contacts || [])].map((c) => c.id);
|
|
99
|
+
|
|
100
|
+
/** The checks, transport-agnostic. Each returns a short result string or throws. */
|
|
101
|
+
export function buildChecks(ops, id) {
|
|
102
|
+
return [
|
|
103
|
+
['search', async () => { const r = await ops.search('ContactsQ Selftest'); if (!idsOf(r).includes(id)) throw new Error('demo contact not in results'); return `${idsOf(r).length} hit(s)`; }],
|
|
104
|
+
['search (sound-alike)', async () => { const r = await ops.search('Selftast'); if (!idsOf(r).includes(id)) throw new Error('sound-alike did not reach the demo contact'); return 'Selftast -> Selftest'; }],
|
|
105
|
+
['find', async () => { const r = await ops.find('Selftest'); if (!idsOf(r).includes(id)) throw new Error('demo contact not found'); return `${idsOf(r).length} hit(s)`; }],
|
|
106
|
+
['resolve by email', async () => { const r = await ops.resolve('email', DEMO_EMAIL); if (!r.match || r.match.id !== id) throw new Error('email did not resolve to the demo contact'); return 'matched'; }],
|
|
107
|
+
['best_channel', async () => { const r = await ops.best_channel(); const n = (r.alternatives || []).length; if (!n) throw new Error('no channel evaluation returned'); return r.channel ? `chose ${r.channel}` : `${n} evaluated`; }],
|
|
108
|
+
['timeline', async () => { const r = await ops.timeline(); if (!Array.isArray(r.timeline)) throw new Error('no timeline array'); return `${r.timeline.length} entr(ies)`; }],
|
|
109
|
+
['log touchpoint', async () => { const r = await ops.log(); const t = r.touchpoint || r; if (!t.id) throw new Error('no touchpoint id returned'); return t.id; }],
|
|
110
|
+
['brief', async () => { const r = await ops.brief(); if (typeof r.candidates_to_review !== 'number' || !Array.isArray(r.sync)) throw new Error('brief shape wrong'); return `${r.candidates_to_review} candidates, ${r.duplicates} dupes`; }],
|
|
111
|
+
];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export async function runSelftest({ client, auth, program, options, orgId, print = console.log }) {
|
|
115
|
+
auth.requireAuth();
|
|
116
|
+
const demo = await ensureDemoContact(client);
|
|
117
|
+
const mode = options.agent ? 'agent' : 'direct';
|
|
118
|
+
const ops = options.agent ? await agentOps(client, demo.id, orgId) : directOps(client, demo.id);
|
|
119
|
+
const rows = [];
|
|
120
|
+
for (const [name, fn] of buildChecks(ops, demo.id)) {
|
|
121
|
+
try { rows.push({ check: name, ok: true, detail: await fn() }); } catch (e) { rows.push({ check: name, ok: false, detail: errText(e) }); }
|
|
122
|
+
}
|
|
123
|
+
const failed = rows.filter((r) => !r.ok).length;
|
|
124
|
+
if (program.opts().output === 'json') {
|
|
125
|
+
print(JSON.stringify({ mode, demo_contact: demo.id, created: demo.created, passed: rows.length - failed, failed, checks: rows }, null, 2));
|
|
126
|
+
} else {
|
|
127
|
+
for (const r of rows) print(`${r.ok ? '✔' : '✖'} ${r.check.padEnd(22)} ${r.detail}`);
|
|
128
|
+
printEvent(glyphLine('contactsq', `selftest (${mode})`, { result: `${rows.length - failed}/${rows.length} passed`, status: failed ? 'fail' : 'ok' }));
|
|
129
|
+
}
|
|
130
|
+
if (failed) process.exitCode = 1;
|
|
131
|
+
return { rows, failed };
|
|
132
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conversation commands
|
|
3
|
+
*
|
|
4
|
+
* quox conversation list|get|search|stats
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { formatOutput, formatDetail } from '../core/output.js';
|
|
8
|
+
import { resolveEndpoint } from '../api/endpoints.js';
|
|
9
|
+
|
|
10
|
+
export function registerConversationCommands(program, ctx) {
|
|
11
|
+
const { client, auth } = ctx;
|
|
12
|
+
|
|
13
|
+
const conv = program
|
|
14
|
+
.command('conversation')
|
|
15
|
+
.description('Manage conversations');
|
|
16
|
+
|
|
17
|
+
conv
|
|
18
|
+
.command('list')
|
|
19
|
+
.description('List your chat conversations (newest first); --archive lists the imported conversation archive')
|
|
20
|
+
.option('--limit <n>', 'Max results', '20')
|
|
21
|
+
.option('--offset <n>', 'Skip results (archive only)', '0')
|
|
22
|
+
.option('--archive', 'list the imported conversation archive instead of chat conversations')
|
|
23
|
+
.action(async (opts) => {
|
|
24
|
+
auth.requireAuth();
|
|
25
|
+
if (!opts.archive) {
|
|
26
|
+
const ep = resolveEndpoint('conversations.chat.list');
|
|
27
|
+
const data = await client.get(ep.path, { service: ep.service, query: { limit: opts.limit } });
|
|
28
|
+
const rows = data.conversations || [];
|
|
29
|
+
formatOutput({
|
|
30
|
+
columns: ['id', 'title', 'turns', 'agent', 'updated_at'],
|
|
31
|
+
headers: ['ID', 'Title', 'Turns', 'Agent', 'Updated'],
|
|
32
|
+
rows: rows.map((c) => ({
|
|
33
|
+
id: c.id,
|
|
34
|
+
title: (c.title || 'Untitled').slice(0, 50),
|
|
35
|
+
turns: c.turn_count ?? 0,
|
|
36
|
+
agent: c.agent || '-',
|
|
37
|
+
updated_at: c.updated_at ? new Date(c.updated_at).toLocaleString() : '-',
|
|
38
|
+
})),
|
|
39
|
+
}, { format: program.opts().output });
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const query = { limit: opts.limit, offset: opts.offset };
|
|
43
|
+
const data = await client.get(resolveEndpoint('conversations.list').path, { service: resolveEndpoint('conversations.list').service, query });
|
|
44
|
+
const conversations = data.conversations || data || [];
|
|
45
|
+
formatOutput({
|
|
46
|
+
columns: ['id', 'title', 'messages', 'created_at'],
|
|
47
|
+
headers: ['ID', 'Title', 'Messages', 'Created'],
|
|
48
|
+
rows: conversations.map(c => ({
|
|
49
|
+
id: c.id,
|
|
50
|
+
title: (c.title || 'Untitled').slice(0, 50),
|
|
51
|
+
messages: c.message_count || c.messages?.length || 0,
|
|
52
|
+
created_at: c.created_at ? new Date(c.created_at).toLocaleDateString() : '-',
|
|
53
|
+
})),
|
|
54
|
+
}, { format: program.opts().output });
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
conv
|
|
58
|
+
.command('get')
|
|
59
|
+
.argument('<id>', 'conversation ID')
|
|
60
|
+
.description('Show a chat conversation\'s turns; --archive reads the imported conversation archive')
|
|
61
|
+
.option('--limit <n>', 'Max turns (chat only)', '50')
|
|
62
|
+
.option('--archive', 'read the imported conversation archive instead of chat conversations')
|
|
63
|
+
.action(async (id, opts) => {
|
|
64
|
+
auth.requireAuth();
|
|
65
|
+
if (!opts.archive) {
|
|
66
|
+
const ep = resolveEndpoint('conversations.chat.turns', { id });
|
|
67
|
+
const data = await client.get(ep.path, { service: ep.service, query: { limit: opts.limit } });
|
|
68
|
+
const turns = data.turns || [];
|
|
69
|
+
formatOutput({
|
|
70
|
+
columns: ['ts', 'role', 'content'],
|
|
71
|
+
headers: ['Time', 'Role', 'Content'],
|
|
72
|
+
rows: turns.map((t) => ({ ts: t.ts ? new Date(t.ts).toLocaleString() : '-', role: t.role, content: t.content })),
|
|
73
|
+
}, { format: program.opts().output });
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const data = await client.get(resolveEndpoint('conversations.get', { id }).path, { service: resolveEndpoint('conversations.get', { id }).service });
|
|
77
|
+
formatDetail(data.conversation || data, { format: program.opts().output, title: 'Conversation' });
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
conv
|
|
81
|
+
.command('search')
|
|
82
|
+
.description('Search conversations')
|
|
83
|
+
.requiredOption('--query <q>', 'Search query')
|
|
84
|
+
.option('--limit <n>', 'Max results', '10')
|
|
85
|
+
.action(async (opts) => {
|
|
86
|
+
auth.requireAuth();
|
|
87
|
+
const query = { query: opts.query, limit: opts.limit };
|
|
88
|
+
const data = await client.get(resolveEndpoint('conversations.search.list').path, { service: resolveEndpoint('conversations.search.list').service, query });
|
|
89
|
+
const results = data.results || data || [];
|
|
90
|
+
formatOutput({
|
|
91
|
+
columns: ['id', 'title', 'score'],
|
|
92
|
+
headers: ['ID', 'Title', 'Score'],
|
|
93
|
+
rows: results.map(r => ({ id: r.id, title: (r.title || 'Untitled').slice(0, 50), score: r.score != null ? r.score.toFixed(2) : '-' })),
|
|
94
|
+
}, { format: program.opts().output });
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
conv
|
|
98
|
+
.command('stats')
|
|
99
|
+
.description('Conversation statistics')
|
|
100
|
+
.action(async () => {
|
|
101
|
+
auth.requireAuth();
|
|
102
|
+
const data = await client.get(resolveEndpoint('conversations.stats.list').path, { service: resolveEndpoint('conversations.stats.list').service });
|
|
103
|
+
formatDetail(data.stats || data, { format: program.opts().output, title: 'Conversation Stats' });
|
|
104
|
+
});
|
|
105
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `quox dashboard [page]`: open the web dashboard already signed in, via a one-time link
|
|
3
|
+
* (10 minutes, single use). Same engine as /dashboard in the Quox client (lib/quoxon/slash/dashboard.js).
|
|
4
|
+
* Over SSH it prints the link and does not open a browser. The link is a credential: it is printed
|
|
5
|
+
* to the terminal only, never logged.
|
|
6
|
+
*/
|
|
7
|
+
import { resolveEndpoint } from '../api/endpoints.js';
|
|
8
|
+
import { runDashboard, dashboardLines, PAGES } from '../quoxon/slash/dashboard.js';
|
|
9
|
+
import { supportsHyperlinks } from '../quoxon/markdown.js';
|
|
10
|
+
import { resolveDashboardBase, detectLanIp } from '../quoxon/hostUrls.js';
|
|
11
|
+
import { loadJourney } from '../quoxon/onboarding/journey.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Z2H-R4: the address to print, resolved exactly like /dashboard in the Quox client (api.js
|
|
15
|
+
* dashboardBase): server app URL, else a non-loopback profile URL, else the install finale's URL,
|
|
16
|
+
* else this machine's LAN IP. Over SSH a localhost link only works on the Quox box itself.
|
|
17
|
+
*/
|
|
18
|
+
export async function commandDashboardBase({ client, config, journey = loadJourney, lanIp = detectLanIp() } = {}) {
|
|
19
|
+
const profileUrl = config.getActiveProfile?.()?.url || config.getBaseUrl();
|
|
20
|
+
let serverApp = null;
|
|
21
|
+
try { const ep = resolveEndpoint('admin.instance.basics.get'); const r = await client.get(ep.path, { service: ep.service, retries: 0 }); serverApp = r?.effective?.appBaseUrl || null; } catch { serverApp = null; }
|
|
22
|
+
let journeyUrl = null; try { journeyUrl = journey()?.dashboardUrl || null; } catch { journeyUrl = null; }
|
|
23
|
+
return resolveDashboardBase({ serverApp, profileUrl, journeyUrl, lanIp }).url;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function registerDashboardCommands(program, ctx) {
|
|
27
|
+
const { client, auth, config, lanIp = detectLanIp, journey = loadJourney } = ctx;
|
|
28
|
+
program
|
|
29
|
+
.command('dashboard')
|
|
30
|
+
.description(`Open the web dashboard signed in (one-time link, 10 minutes). Pages: ${Object.keys(PAGES).join(', ')}`)
|
|
31
|
+
.argument('[page]', 'dashboard page to land on')
|
|
32
|
+
.action(async (page) => {
|
|
33
|
+
auth.requireAuth();
|
|
34
|
+
const baseUrl = await commandDashboardBase({ client, config, journey, lanIp: lanIp() });
|
|
35
|
+
const r = await runDashboard({ page, baseUrl, mint: () => { const ep = resolveEndpoint('auth.login-link'); return client.post(ep.path, { service: ep.service, body: {}, retries: 0 }); } });
|
|
36
|
+
if (program.opts().output === 'json') {
|
|
37
|
+
console.log(JSON.stringify({ kind: r.kind, url: r.url ?? null, opened: Boolean(r.opened), remote: Boolean(r.remote), error: r.error ?? null }, null, 2));
|
|
38
|
+
} else {
|
|
39
|
+
for (const l of dashboardLines(r, { hyperlinks: supportsHyperlinks() })) console.log(l.text);
|
|
40
|
+
}
|
|
41
|
+
if (r.kind === 'error') process.exitCode = 1;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Department commands: CRUD
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { formatOutput, printSuccess } from '../core/output.js';
|
|
6
|
+
import { resolveOrgId } from './helpers.js';
|
|
7
|
+
import { resolveEndpoint } from '../api/endpoints.js';
|
|
8
|
+
|
|
9
|
+
export function registerDepartmentCommands(program, ctx) {
|
|
10
|
+
const { client, auth } = ctx;
|
|
11
|
+
|
|
12
|
+
const dept = program
|
|
13
|
+
.command('department')
|
|
14
|
+
.description('Manage departments within divisions');
|
|
15
|
+
|
|
16
|
+
dept
|
|
17
|
+
.command('list')
|
|
18
|
+
.description('List departments (all divisions unless --division; division ids: quox org divisions list)')
|
|
19
|
+
.option('--division <divId>', 'only this division')
|
|
20
|
+
.action(async (options) => {
|
|
21
|
+
auth.requireAuth();
|
|
22
|
+
const orgId = resolveOrgId(auth, program);
|
|
23
|
+
const listFor = async (division) => {
|
|
24
|
+
const ep = resolveEndpoint('divisions.departments.list', { orgId, division });
|
|
25
|
+
const data = await client.get(ep.path, { service: ep.service });
|
|
26
|
+
return data.departments || data || [];
|
|
27
|
+
};
|
|
28
|
+
if (options.division) {
|
|
29
|
+
formatOutput({
|
|
30
|
+
columns: ['id', 'name', 'description', 'created_at'],
|
|
31
|
+
headers: ['ID', 'Name', 'Description', 'Created'],
|
|
32
|
+
rows: await listFor(options.division),
|
|
33
|
+
}, { format: program.opts().output });
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
// quox#922: no --division lists every division's departments, so the read
|
|
37
|
+
// needs no id the department group cannot show.
|
|
38
|
+
const divEp = resolveEndpoint('divisions.list', { orgId });
|
|
39
|
+
const divData = await client.get(divEp.path, { service: divEp.service });
|
|
40
|
+
const divisions = divData.divisions || divData || [];
|
|
41
|
+
const rows = [];
|
|
42
|
+
for (const d of divisions) {
|
|
43
|
+
for (const dept of await listFor(d.id)) rows.push({ ...dept, division: d.name || d.id });
|
|
44
|
+
}
|
|
45
|
+
formatOutput({
|
|
46
|
+
columns: ['id', 'name', 'division', 'description', 'created_at'],
|
|
47
|
+
headers: ['ID', 'Name', 'Division', 'Description', 'Created'],
|
|
48
|
+
rows,
|
|
49
|
+
}, { format: program.opts().output, emptyMessage: 'No departments.' });
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
dept
|
|
53
|
+
.command('create')
|
|
54
|
+
.description('Create a department')
|
|
55
|
+
.requiredOption('--division <divId>', 'division ID')
|
|
56
|
+
.requiredOption('--name <name>', 'department name')
|
|
57
|
+
.option('--description <desc>', 'description')
|
|
58
|
+
.action(async (options) => {
|
|
59
|
+
auth.requireAuth();
|
|
60
|
+
const orgId = resolveOrgId(auth, program);
|
|
61
|
+
await client.post(resolveEndpoint('divisions.departments.create', { orgId, division: options.division }).path, {
|
|
62
|
+
service: resolveEndpoint('divisions.departments.create', { orgId, division: options.division }).service,
|
|
63
|
+
body: { name: options.name, description: options.description },
|
|
64
|
+
});
|
|
65
|
+
printSuccess(`Department "${options.name}" created.`);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
dept
|
|
69
|
+
.command('update')
|
|
70
|
+
.description('Update a department')
|
|
71
|
+
.argument('<deptId>', 'department ID')
|
|
72
|
+
.requiredOption('--division <divId>', 'division ID')
|
|
73
|
+
.option('--name <name>', 'new name')
|
|
74
|
+
.option('--description <desc>', 'new description')
|
|
75
|
+
.action(async (deptId, 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('divisions.departments.update', { orgId, division: options.division, deptId }).path, { service: resolveEndpoint('divisions.departments.update', { orgId, division: options.division, deptId }).service, body });
|
|
82
|
+
printSuccess('Department updated.');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
dept
|
|
86
|
+
.command('delete')
|
|
87
|
+
.description('Delete a department')
|
|
88
|
+
.argument('<deptId>', 'department ID')
|
|
89
|
+
.requiredOption('--division <divId>', 'division ID')
|
|
90
|
+
.action(async (deptId, options) => {
|
|
91
|
+
auth.requireAuth();
|
|
92
|
+
const orgId = resolveOrgId(auth, program);
|
|
93
|
+
await client.delete(resolveEndpoint('divisions.departments.delete', { orgId, division: options.division, deptId }).path, { service: resolveEndpoint('divisions.departments.delete', { orgId, division: options.division, deptId }).service });
|
|
94
|
+
printSuccess('Department deleted.');
|
|
95
|
+
});
|
|
96
|
+
}
|