quoxcli 0.2.0 → 0.4.0
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 +1 -1
- package/README.md +2 -0
- package/bin/quox.js +99 -126
- package/lib/api/endpoints/actions.js +15 -0
- package/lib/api/endpoints/admin.js +46 -0
- package/lib/api/endpoints/agent-schedules.js +26 -0
- package/lib/api/endpoints/agents.js +7 -0
- package/lib/api/endpoints/assistants.js +12 -0
- package/lib/api/endpoints/away.js +15 -0
- package/lib/api/endpoints/blog.js +16 -0
- package/lib/api/endpoints/chat.js +14 -0
- package/lib/api/endpoints/contactsq.js +6 -0
- package/lib/api/endpoints/conversations.js +14 -0
- package/lib/api/endpoints/devServerRegistry.js +25 -0
- package/lib/api/endpoints/engagement.js +26 -0
- package/lib/api/endpoints/evidence.js +20 -0
- package/lib/api/endpoints/executions.js +13 -0
- package/lib/api/endpoints/fetchAllowlist.js +27 -0
- package/lib/api/endpoints/files.js +14 -0
- package/lib/api/endpoints/hat.js +44 -0
- package/lib/api/endpoints/inbox.js +20 -0
- package/lib/api/endpoints/index.js +26 -0
- package/lib/api/endpoints/loops.js +26 -0
- package/lib/api/endpoints/memory.js +19 -0
- package/lib/api/endpoints/mind.js +13 -0
- package/lib/api/endpoints/mon.js +179 -0
- package/lib/api/endpoints/objectives.js +12 -0
- package/lib/api/endpoints/plugins.js +18 -0
- package/lib/api/endpoints/presence.js +33 -0
- package/lib/api/endpoints/quoxplan.js +7 -0
- package/lib/api/endpoints/quoxseo.js +12 -0
- package/lib/api/endpoints/router.js +17 -0
- package/lib/api/endpoints/safety.js +7 -0
- package/lib/api/endpoints/server.js +21 -0
- package/lib/api/endpoints/setup.js +6 -0
- package/lib/api/endpoints/skills.js +20 -0
- package/lib/api/endpoints/stepup.js +20 -0
- package/lib/api/endpoints/teams.js +2 -2
- package/lib/api/endpoints/triggers.js +26 -0
- package/lib/api/endpoints/v1.js +120 -0
- package/lib/api/endpoints/ward.js +7 -0
- package/lib/api/endpoints/workflows.js +7 -0
- package/lib/api/endpoints/x.js +8 -0
- package/lib/commands/actions.js +131 -0
- package/lib/commands/admin.js +16 -0
- package/lib/commands/agent.js +170 -27
- package/lib/commands/agentAttach.js +140 -13
- package/lib/commands/approvals.js +78 -1
- package/lib/commands/aside.js +24 -0
- package/lib/commands/ask.js +146 -0
- package/lib/commands/assistant.js +59 -4
- package/lib/commands/auth.js +8 -2
- package/lib/commands/backup.js +8 -4
- package/lib/commands/blog.js +110 -0
- package/lib/commands/brain.js +105 -14
- package/lib/commands/build.js +19 -5
- package/lib/commands/chat.js +180 -26
- package/lib/commands/chatCompanion.js +27 -0
- package/lib/commands/chatState.js +45 -0
- package/lib/commands/claude.js +35 -38
- package/lib/commands/contacts.js +134 -4
- package/lib/commands/contactsSendAt.js +21 -0
- package/lib/commands/conversation.js +35 -4
- package/lib/commands/dashboard.js +43 -0
- package/lib/commands/department.js +28 -7
- package/lib/commands/devResident.js +15 -3
- package/lib/commands/devSupervisor.js +13 -1
- package/lib/commands/discord.js +75 -39
- package/lib/commands/done.js +98 -28
- package/lib/commands/engagement.js +107 -6
- package/lib/commands/evidence.js +154 -0
- package/lib/commands/ext.js +23 -0
- package/lib/commands/fetchAllowlist.js +71 -0
- package/lib/commands/file.js +38 -1
- package/lib/commands/fleet.js +336 -4
- package/lib/commands/governance.js +12 -3
- package/lib/commands/gripe.js +44 -13
- package/lib/commands/hat.js +254 -9
- package/lib/commands/helpers.js +18 -1
- package/lib/commands/hyperion.js +58 -0
- package/lib/commands/image.js +68 -0
- package/lib/commands/inbox.js +74 -23
- package/lib/commands/kuma.js +1050 -0
- package/lib/commands/kumaSla.js +174 -0
- package/lib/commands/licence.js +52 -155
- package/lib/commands/loop.js +291 -0
- package/lib/commands/lucid.js +10 -4
- package/lib/commands/memory.js +85 -8
- package/lib/commands/mind.js +71 -0
- package/lib/commands/mon.js +69 -2
- package/lib/commands/monitoring.js +1 -1
- package/lib/commands/motion.js +2 -2
- package/lib/commands/nucleus.js +48 -17
- package/lib/commands/objective.js +59 -1
- package/lib/commands/offload.js +89 -0
- package/lib/commands/onboard.js +2 -1
- package/lib/commands/org.js +30 -3
- package/lib/commands/peek.js +28 -0
- package/lib/commands/plan.js +38 -0
- package/lib/commands/plugin.js +110 -0
- package/lib/commands/presence.js +89 -0
- package/lib/commands/provider.js +217 -0
- package/lib/commands/qlarity.js +19 -3
- package/lib/commands/quoxchat.js +13 -4
- package/lib/commands/quoxseo.js +69 -0
- package/lib/commands/reach.js +2 -1
- package/lib/commands/research.js +79 -0
- package/lib/commands/router.js +77 -0
- package/lib/commands/rows.js +367 -0
- package/lib/commands/run.js +82 -10
- package/lib/commands/scope.js +2 -2
- package/lib/commands/server.js +405 -0
- package/lib/commands/setup.js +33 -7
- package/lib/commands/shortcut.js +41 -0
- package/lib/commands/skills.js +68 -9
- package/lib/commands/slot.js +260 -7
- package/lib/commands/status.js +1 -1
- package/lib/commands/team.js +3 -1
- package/lib/commands/tips.js +23 -0
- package/lib/commands/tool.js +133 -45
- package/lib/commands/trace.js +12 -7
- package/lib/commands/trigger.js +95 -0
- package/lib/commands/update.js +46 -0
- package/lib/commands/vault.js +31 -8
- package/lib/commands/vm.js +237 -0
- package/lib/commands/voice.js +34 -3
- package/lib/commands/volt.js +45 -3
- package/lib/commands/walkthrough.js +32 -0
- package/lib/commands/watch.js +73 -21
- package/lib/commands/welcome.js +14 -0
- package/lib/commands/workflow.js +189 -32
- package/lib/commands/x.js +13 -4
- package/lib/commands/youtube.js +172 -0
- package/lib/core/actingAs.js +2 -2
- package/lib/core/actionItems.js +115 -0
- package/lib/core/activeSummary.js +186 -0
- package/lib/core/agentAlias.js +2 -0
- package/lib/core/agentFamilies.js +7 -0
- package/lib/core/aside.js +54 -0
- package/lib/core/askDecision.js +60 -0
- package/lib/core/auth.js +164 -13
- package/lib/core/callerSource.js +1 -1
- package/lib/core/cliBuild.js +62 -0
- package/lib/core/client.js +152 -35
- package/lib/core/commandRegistrars.js +130 -0
- package/lib/core/config.js +143 -25
- package/lib/core/customHats.js +168 -0
- package/lib/core/doneEngineFetch.js +8 -0
- package/lib/core/errors.js +329 -20
- package/lib/core/findingReconcile.js +90 -0
- package/lib/core/global-flags.js +105 -5
- package/lib/core/governedSession.js +1 -3
- package/lib/core/hyperion.js +102 -0
- package/lib/core/inboxResolution.js +65 -0
- package/lib/core/lazyCommands.js +4 -1
- package/lib/core/liveSessionsReport.js +1 -1
- package/lib/core/loopGlyph.js +97 -0
- package/lib/core/offload.js +533 -0
- package/lib/core/org-override.js +1 -1
- package/lib/core/orgResolve.js +70 -0
- package/lib/core/output.js +11 -11
- package/lib/core/peek.js +126 -0
- package/lib/core/profileUsers.js +51 -0
- package/lib/core/promptCancel.js +18 -0
- package/lib/core/repoPath.js +11 -0
- package/lib/core/residentSeed.js +3 -1
- 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 +12 -8
- package/lib/core/sessionsOverview.js +64 -0
- package/lib/core/shortcut.js +83 -0
- package/lib/core/slotKeeper.js +248 -3
- package/lib/core/slotWake.js +120 -0
- package/lib/core/supervisorEngine.js +71 -2
- package/lib/core/version.js +1 -1
- package/lib/core/vm.js +366 -0
- package/lib/core/vmTui.js +86 -0
- package/lib/core/walkthrough.js +35 -0
- package/lib/dragon/companionView.js +34 -0
- package/lib/dragon/frames.js +118 -0
- package/lib/dragon/jobs.js +123 -0
- package/lib/dragon/renderWorker.js +15 -0
- package/lib/dragon/select.js +72 -0
- package/lib/evidence/bundleExport.js +47 -0
- package/lib/evidence/bundleVerify.js +77 -0
- package/lib/hyperion/deck.js +29 -0
- package/lib/lucid/LucidCard.jsx +68 -0
- package/lib/lucid/LucidIntro.jsx +45 -58
- package/lib/lucid/cards.js +86 -0
- package/lib/lucid/markdown.js +81 -0
- package/lib/lucid/motion.js +56 -0
- package/lib/quoxon/EXTENSIONS.md +23 -0
- package/lib/quoxon/activity.js +14 -2
- package/lib/quoxon/aocl.js +117 -0
- package/lib/quoxon/api.js +690 -25
- package/lib/quoxon/app.js +3586 -250
- package/lib/quoxon/approvalFacts.js +96 -0
- package/lib/quoxon/approvalSentence.js +44 -0
- package/lib/quoxon/approvalsView.js +384 -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 +13 -6
- package/lib/quoxon/cells.js +53 -0
- package/lib/quoxon/commandShort.js +124 -0
- package/lib/quoxon/commands.js +429 -39
- package/lib/quoxon/connect.js +210 -23
- package/lib/quoxon/connectCard.js +19 -2
- package/lib/quoxon/consent.js +86 -0
- package/lib/quoxon/copy.js +4 -3
- package/lib/quoxon/countdownLine.js +20 -0
- package/lib/quoxon/deck.js +30 -0
- package/lib/quoxon/demo.autoplay.js +29 -0
- package/lib/quoxon/demo.fixtures.js +1 -1
- package/lib/quoxon/demo.js +46 -3
- package/lib/quoxon/devObserver.js +20 -0
- package/lib/quoxon/dividerAocl.js +192 -0
- package/lib/quoxon/dividerRule.js +57 -0
- package/lib/quoxon/dragonCompanion.js +255 -0
- package/lib/quoxon/dragonModes.js +151 -0
- package/lib/quoxon/dragonMoments.js +82 -0
- package/lib/quoxon/dragonReads.js +68 -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 +2 -2
- package/lib/quoxon/events.js +266 -26
- package/lib/quoxon/extensions.js +276 -0
- package/lib/quoxon/feedback.js +50 -0
- package/lib/quoxon/gallery.js +21 -7
- 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/inboxView.js +79 -0
- package/lib/quoxon/indicator.js +6 -2
- package/lib/quoxon/installCli.js +79 -0
- package/lib/quoxon/intent.js +12 -1
- package/lib/quoxon/keys.js +51 -8
- package/lib/quoxon/launcher.js +103 -0
- package/lib/quoxon/loopCard.js +456 -0
- package/lib/quoxon/loopCards.js +180 -0
- package/lib/quoxon/loopStream.js +87 -0
- package/lib/quoxon/main.js +101 -160
- package/lib/quoxon/markdown.js +45 -21
- 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 +132 -26
- package/lib/quoxon/modelPrefs.js +345 -0
- package/lib/quoxon/motion/clock.js +3 -2
- package/lib/quoxon/motion/level.js +91 -0
- package/lib/quoxon/mouse.js +222 -0
- package/lib/quoxon/noai.js +57 -0
- package/lib/quoxon/objectiveOffer.js +82 -0
- package/lib/quoxon/objects/away.js +72 -0
- package/lib/quoxon/objects/fetch.js +17 -5
- package/lib/quoxon/objects/fleet.js +149 -0
- package/lib/quoxon/objects/health.js +186 -0
- package/lib/quoxon/objects/index.js +46 -7
- package/lib/quoxon/objects/mirror.js +137 -0
- package/lib/quoxon/objects/model.js +33 -0
- package/lib/quoxon/objects/peek.js +17 -0
- package/lib/quoxon/objects/proof.js +12 -4
- 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/view.js +11 -0
- package/lib/quoxon/onboarding/copy.js +32 -4
- package/lib/quoxon/onboarding/credential.js +17 -4
- package/lib/quoxon/onboarding/dockerOffer.js +45 -0
- package/lib/quoxon/onboarding/failureCause.js +33 -0
- package/lib/quoxon/onboarding/finish.js +15 -0
- package/lib/quoxon/onboarding/index.js +34 -7
- package/lib/quoxon/onboarding/installRunner.js +64 -5
- package/lib/quoxon/onboarding/preflight.js +17 -3
- package/lib/quoxon/onboarding/probe.js +65 -0
- package/lib/quoxon/onboarding/shortcutOffer.js +28 -0
- package/lib/quoxon/onboarding/view.js +76 -19
- package/lib/quoxon/orgLabel.js +10 -0
- package/lib/quoxon/orgSwitch.js +59 -0
- package/lib/quoxon/ownBroadcast.js +22 -0
- package/lib/quoxon/palette.js +43 -0
- package/lib/quoxon/planSteps.js +51 -0
- package/lib/quoxon/print.js +12 -5
- 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 +20 -51
- package/lib/quoxon/qdragon.js +410 -0
- package/lib/quoxon/qdragonFly.js +62 -0
- package/lib/quoxon/qdragonScenes.js +282 -0
- package/lib/quoxon/qeyes.js +213 -0
- package/lib/quoxon/qmotion.js +75 -37
- package/lib/quoxon/render.js +740 -124
- package/lib/quoxon/resend.js +72 -0
- package/lib/quoxon/roster.js +117 -17
- package/lib/quoxon/route.js +6 -5
- package/lib/quoxon/rows.js +954 -0
- package/lib/quoxon/rowsStore.js +80 -0
- package/lib/quoxon/screenContext.js +150 -0
- package/lib/quoxon/screenFrames.js +254 -0
- package/lib/quoxon/serverChip.js +42 -0
- package/lib/quoxon/session.js +182 -2
- package/lib/quoxon/sessionDead.js +17 -0
- package/lib/quoxon/signin.js +125 -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 +94 -0
- package/lib/quoxon/slash/cliLeaves.json +1023 -0
- package/lib/quoxon/slash/compact.js +1 -1
- 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/evidenceCmd.js +34 -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 +13 -8
- package/lib/quoxon/slash/listView.js +3 -1
- package/lib/quoxon/slash/modelCmd.js +261 -0
- package/lib/quoxon/slash/palette.js +22 -8
- package/lib/quoxon/slash/paletteController.js +117 -7
- package/lib/quoxon/slash/panels.js +21 -6
- package/lib/quoxon/slash/picker.js +20 -2
- package/lib/quoxon/slash/qpeCmd.js +35 -0
- package/lib/quoxon/slash/restart.js +95 -13
- package/lib/quoxon/slash/resume.js +18 -1
- package/lib/quoxon/slash/rowCmd.js +157 -0
- package/lib/quoxon/slash/rowWalk.js +175 -0
- package/lib/quoxon/slash/settings.js +16 -6
- 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/todoCmd.js +122 -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/mapping.js +2 -1
- package/lib/quoxon/stray.js +22 -0
- package/lib/quoxon/suggestCommand.js +90 -0
- package/lib/quoxon/term.js +46 -11
- package/lib/quoxon/textBuffer.js +176 -2
- package/lib/quoxon/theme.js +58 -25
- package/lib/quoxon/tips.js +433 -0
- package/lib/quoxon/toolCards.js +30 -0
- package/lib/quoxon/toolError.js +41 -0
- package/lib/quoxon/transcript.js +42 -4
- package/lib/quoxon/web/qface.js +18 -10
- package/lib/quoxon/welcome.js +1 -1
- package/lib/quoxon/whatsnew.js +136 -0
- package/lib/quoxon/whatsnew.jsonl +134 -0
- package/lib/quoxon/windowOrg.js +123 -0
- package/lib/server/devServers.js +137 -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/views/HyperionDeck.jsx +79 -0
- package/lib/tui/views/LucidDeck.jsx +209 -217
- package/package.json +5 -1
- package/vendor/dragonlab/SOURCE +4 -0
- package/vendor/dragonlab/design/cipher/v1/cipher-master.svg +46 -0
- package/vendor/dragonlab/design/cipher/v2/character.mjs +49 -0
- package/vendor/dragonlab/design/cipher/v2/review.mjs +33 -0
- package/vendor/dragonlab/design/cipher/v2/watch.mjs +56 -0
- package/vendor/dragonlab/design/drago/v1/character.mjs +19 -0
- package/vendor/dragonlab/design/drago/v1/drago-master.svg +56 -0
- package/vendor/dragonlab/design/drago/v2/character.mjs +87 -0
- package/vendor/dragonlab/design/drago/v4/character.mjs +67 -0
- package/vendor/dragonlab/design/drago/v4/profile.mjs +35 -0
- package/vendor/dragonlab/design/drago/v4/review.mjs +33 -0
- package/vendor/dragonlab/design/drago/v4/watch.mjs +56 -0
- package/vendor/dragonlab/design/hyperion/v1/hyperion-master.svg +56 -0
- package/vendor/dragonlab/design/hyperion/v2/character.mjs +79 -0
- package/vendor/dragonlab/design/hyperion/v2/review.mjs +33 -0
- package/vendor/dragonlab/design/hyperion/v2/watch.mjs +56 -0
- package/vendor/dragonlab/design/lucid/recovery/arrival.mjs +22 -0
- package/vendor/dragonlab/design/lucid/recovery/character.mjs +106 -0
- package/vendor/dragonlab/design/lucid/recovery/layout.mjs +50 -0
- package/vendor/dragonlab/design/lucid/recovery/lucid-master.svg +78 -0
- package/vendor/dragonlab/design/lucid/recovery/motion.mjs +42 -0
- package/vendor/dragonlab/design/lucid/recovery/render.mjs +121 -0
- package/vendor/dragonlab/design/lucid/recovery/review.mjs +68 -0
- package/vendor/dragonlab/design/lucid/recovery/verify.mjs +84 -0
- package/vendor/dragonlab/design/lucid/recovery/watch.mjs +56 -0
- package/vendor/dragonlab/design/seer/v1/seer-master.svg +53 -0
- package/vendor/dragonlab/design/seer/v2/character.mjs +88 -0
- package/vendor/dragonlab/design/seer/v3/character.mjs +33 -0
- package/vendor/dragonlab/design/seer/v4/character.mjs +66 -0
- package/vendor/dragonlab/design/seer/v4/review.mjs +33 -0
- package/vendor/dragonlab/design/seer/v4/watch.mjs +56 -0
- package/vendor/dragonlab/design/stage3/companion-review.mjs +28 -0
- package/vendor/dragonlab/design/stage3/sentinel-art.js +39 -0
- package/vendor/dragonlab/design/stage3/sentinel-braille.js +216 -0
- package/vendor/dragonlab/design/stage3/sentinel-character.js +257 -0
- package/vendor/dragonlab/design/stage3/sentinel-icon.js +103 -0
- package/vendor/dragonlab/design/stage3/sentinel-warden-eyes.js +95 -0
- package/vendor/dragonlab/design/stage3/svg-coverage.js +148 -0
- package/vendor/dragonlab/factory/svg-rig.mjs +63 -0
- package/vendor/dragonlab/integration/companions-v1/characters.mjs +88 -0
- package/vendor/dragonlab/integration/companions-v1/cipher.mjs +2 -0
- package/vendor/dragonlab/integration/companions-v1/companion.mjs +63 -0
- package/vendor/dragonlab/integration/companions-v1/drago.mjs +2 -0
- package/vendor/dragonlab/integration/companions-v1/hyperion.mjs +2 -0
- package/vendor/dragonlab/integration/companions-v1/lucid.mjs +2 -0
- package/vendor/dragonlab/integration/companions-v1/seer.mjs +2 -0
- package/vendor/dragonlab/integration/companions-v1/sentinel.mjs +2 -0
- package/vendor/dragonlab/integration/companions-v1/view.mjs +28 -0
- package/vendor/dragonlab/integration/hyperion-v3/activity.mjs +76 -0
- package/vendor/dragonlab/lib/power-effects.js +294 -0
- package/vendor/dragonlab/lib/power-registry.js +74 -0
- package/vendor/dragonlab/vendor/quox-dragon/qart.js +348 -0
- package/vendor/dragonlab/vendor/quox-dragon/qeyes.js +213 -0
- package/lib/core/websiteSession.js +0 -148
package/lib/commands/motion.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
export function registerMotionCommand(program) {
|
|
6
6
|
program
|
|
7
7
|
.command('motion')
|
|
8
|
-
.description('Play the Quox motion gallery: the Q intro, portal, particle, the Dragon\'s Eye, the status Q, ring and
|
|
9
|
-
.argument('[scenes...]', 'only these: orbit portal particle eye hello perpetual ring fx')
|
|
8
|
+
.description('Play the Quox motion gallery: the Q intro, portal, particle, the Dragon\'s Eye, the status Q, ring, reveals and the living dragon (no server needed)')
|
|
9
|
+
.argument('[scenes...]', 'only these: orbit portal particle eye hello perpetual ring fx dragon dragon-fire dragon-moods')
|
|
10
10
|
.option('--narrow', 'use the 40-column layout (the compact Q)')
|
|
11
11
|
.option('--slow', 'play three times slower')
|
|
12
12
|
.option('--mono', 'no colour (also honoured: NO_COLOR)')
|
package/lib/commands/nucleus.js
CHANGED
|
@@ -23,6 +23,36 @@ import { line as glyphLine, printEvent } from '../core/quoxglyph.js';
|
|
|
23
23
|
import { resolveEndpoint } from '../api/endpoints.js';
|
|
24
24
|
import { resolveOrgId } from './helpers.js';
|
|
25
25
|
|
|
26
|
+
// codebase_query's schema (collector agentTools.js): question (required),
|
|
27
|
+
// target, max_snippets. quox#836: the CLI used to send query/repo/limit,
|
|
28
|
+
// every call failed "Missing required parameter: question", and the failure
|
|
29
|
+
// printed as "0 hits".
|
|
30
|
+
export function buildNucleusInput(question, options = {}) {
|
|
31
|
+
const input = { question };
|
|
32
|
+
if (options.target) input.target = options.target;
|
|
33
|
+
const n = parseInt(options.limit, 10);
|
|
34
|
+
if (n > 0) input.max_snippets = n;
|
|
35
|
+
return input;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// The tool result shape varies by engine version, so normalise rather than
|
|
39
|
+
// assuming: an unexpected shape must still print SOMETHING true. An error
|
|
40
|
+
// body is an error, never an empty result.
|
|
41
|
+
export function readNucleusResult(data) {
|
|
42
|
+
if (data && data.success === false) return { error: data.error || data.message || 'tool call failed' };
|
|
43
|
+
// The collector's codebase_query returns agent-friendly text with
|
|
44
|
+
// file:line citations ({ success, output, resultCount }), not an array.
|
|
45
|
+
if (typeof data?.output === 'string') return { text: data.output, count: data.resultCount ?? null, result: data };
|
|
46
|
+
const result = data && (data.result || data.output || data);
|
|
47
|
+
if (result && result.success === false) return { error: result.error || result.message || 'tool call failed' };
|
|
48
|
+
if (typeof result?.output === 'string') return { text: result.output, count: result.resultCount ?? null, result };
|
|
49
|
+
const results = Array.isArray(result?.results) ? result.results
|
|
50
|
+
: Array.isArray(result?.snippets) ? result.snippets
|
|
51
|
+
: Array.isArray(result) ? result
|
|
52
|
+
: null;
|
|
53
|
+
return { results, result };
|
|
54
|
+
}
|
|
55
|
+
|
|
26
56
|
export function registerNucleusCommands(program, { client, auth }) {
|
|
27
57
|
const nucleus = program
|
|
28
58
|
.command('nucleus')
|
|
@@ -43,33 +73,34 @@ export function registerNucleusCommands(program, { client, auth }) {
|
|
|
43
73
|
const started = Date.now();
|
|
44
74
|
|
|
45
75
|
const ep = resolveEndpoint('v1.tools.execute');
|
|
46
|
-
const body = {
|
|
47
|
-
tool_name: 'codebase_query',
|
|
48
|
-
input: {
|
|
49
|
-
query: question,
|
|
50
|
-
...(options.target ? { repo: options.target } : {}),
|
|
51
|
-
...(options.limit ? { limit: parseInt(options.limit, 10) || 8 } : {}),
|
|
52
|
-
},
|
|
53
|
-
};
|
|
76
|
+
const body = { tool_name: 'codebase_query', input: buildNucleusInput(question, options) };
|
|
54
77
|
const orgId = resolveOrgId(auth, program);
|
|
55
78
|
if (orgId) body.org_id = orgId;
|
|
56
79
|
|
|
57
80
|
const data = await client.post(ep.path, { service: ep.service, body, timeout: 60000 });
|
|
58
81
|
const ms = Date.now() - started;
|
|
59
|
-
|
|
60
|
-
// The tool result shape varies by engine version, so normalise rather
|
|
61
|
-
// than assuming: an unexpected shape must still print SOMETHING true.
|
|
62
|
-
const result = data && (data.result || data.output || data);
|
|
63
|
-
const results = Array.isArray(result?.results) ? result.results
|
|
64
|
-
: Array.isArray(result?.snippets) ? result.snippets
|
|
65
|
-
: Array.isArray(result) ? result
|
|
66
|
-
: null;
|
|
82
|
+
const { error, results, result, text, count } = readNucleusResult(data);
|
|
67
83
|
|
|
68
84
|
if (program.opts().output === 'json') {
|
|
69
85
|
formatDetail(data, { format: 'json' });
|
|
70
86
|
return;
|
|
71
87
|
}
|
|
72
88
|
|
|
89
|
+
if (error) {
|
|
90
|
+
printEvent(glyphLine('repobrain', `query "${question}"`, { result: 'failed', ms }));
|
|
91
|
+
printWarning(`The query failed: ${error}`);
|
|
92
|
+
process.exitCode = 1;
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (typeof text === 'string') {
|
|
97
|
+
const hits = count === null ? 'answered' : `${count} hits`;
|
|
98
|
+
printEvent(glyphLine('repobrain', `query "${question}"`, { result: count === 0 ? '0 hits' : hits, ms }));
|
|
99
|
+
console.log('');
|
|
100
|
+
console.log(text.split('\n').map((l) => ` ${l}`).join('\n'));
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
73
104
|
if (!results || results.length === 0) {
|
|
74
105
|
printEvent(glyphLine('repobrain', `query "${question}"`, { result: '0 hits', ms }));
|
|
75
106
|
printWarning('Nothing matched. Try naming a concrete symbol, filename or behaviour rather than a general description.');
|
|
@@ -85,7 +116,7 @@ export function registerNucleusCommands(program, { client, auth }) {
|
|
|
85
116
|
const line = r.line || r.start_line || null;
|
|
86
117
|
console.log('');
|
|
87
118
|
console.log(` ${loc}${line ? `:${line}` : ''}`);
|
|
88
|
-
const snippet = r.snippet || r.content || r.text || '';
|
|
119
|
+
const snippet = r.snippet || r.code || r.content || r.text || '';
|
|
89
120
|
for (const l of String(snippet).split('\n').slice(0, 20)) console.log(` ${l}`);
|
|
90
121
|
}
|
|
91
122
|
});
|
|
@@ -12,9 +12,10 @@
|
|
|
12
12
|
* live loop gate: budget, risk, interval).
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
import { formatOutput, formatDetail, printSuccess } from '../core/output.js';
|
|
15
|
+
import { formatOutput, formatDetail, printSuccess, printWarning } from '../core/output.js';
|
|
16
16
|
import { parseJSON } from './helpers.js';
|
|
17
17
|
import { resolveEndpoint } from '../api/endpoints.js';
|
|
18
|
+
import { QuoxUserError } from '../core/errors.js';
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* Format a timestamp as a short relative-time string ("5m ago").
|
|
@@ -75,6 +76,13 @@ export function registerObjectiveCommands(program, ctx) {
|
|
|
75
76
|
.option('--loop-backend <backend>', 'claude|codex, loop mode only (default claude)')
|
|
76
77
|
.option('--capability-scope <tools>', 'comma-separated tool names the loop may call (repeatable); empty scope escalates every tool', collectScope)
|
|
77
78
|
.option('--system-prompt <text>', 'per-objective system prompt, carried verbatim to the run')
|
|
79
|
+
.option('--observe-every <n>', 'loop mode: emit a status line every N turns while it runs (watch with `quox loop watch <id>`)')
|
|
80
|
+
.option('--observe-milestones', 'loop mode: lift MILESTONE: lines from the loop output into headline updates')
|
|
81
|
+
.option('--until <text>', 'loop mode: the done criterion in plain words. The loop runs turn after turn until the model ends a turn with "DONE: <evidence>" (or --max-iterations / --max-duration-ms stops it)')
|
|
82
|
+
.option('--every-seconds <n>', 'loop mode: the runner waits N seconds (30-3600) between turns; the model is never asked to sleep')
|
|
83
|
+
.option('--workspace <name>', 'loop mode: name the durable workspace dir, so a follow-up loop can work in the same files (default: one per loop)')
|
|
84
|
+
.option('--done-file <path>', 'loop mode: DONE only counts once this file exists in the loop workspace; the runner checks it itself (repeatable)', (v, prev = []) => prev.concat(v))
|
|
85
|
+
.option('--done-command <cmd>', 'loop mode: DONE only counts once this command exits 0 in the loop workspace; must be one the loop scope lets it run (repeatable)', (v, prev = []) => prev.concat(v))
|
|
78
86
|
.action(async (goal, options) => {
|
|
79
87
|
auth.requireAuth();
|
|
80
88
|
const body = { title: goal };
|
|
@@ -98,6 +106,28 @@ export function registerObjectiveCommands(program, ctx) {
|
|
|
98
106
|
if (scope.length > 0) body.capability_scope = scope;
|
|
99
107
|
}
|
|
100
108
|
if (options.systemPrompt) body.system_prompt = options.systemPrompt;
|
|
109
|
+
if (options.until) body.until = options.until;
|
|
110
|
+
if (options.everySeconds !== undefined) {
|
|
111
|
+
const n = Number(options.everySeconds);
|
|
112
|
+
if (!Number.isInteger(n) || n < 30 || n > 3600) throw new QuoxUserError('--every-seconds needs a whole number of seconds between 30 and 3600.');
|
|
113
|
+
body.every_seconds = n;
|
|
114
|
+
}
|
|
115
|
+
if (options.workspace) body.workspace = options.workspace;
|
|
116
|
+
const doneChecks = [
|
|
117
|
+
...(options.doneFile || []).map((path) => ({ kind: 'file_exists', path })),
|
|
118
|
+
...(options.doneCommand || []).map((command) => ({ kind: 'command_ok', command })),
|
|
119
|
+
];
|
|
120
|
+
if (doneChecks.length) body.done_check = doneChecks;
|
|
121
|
+
if (options.observeEvery !== undefined || options.observeMilestones) {
|
|
122
|
+
const observe = {};
|
|
123
|
+
if (options.observeEvery !== undefined) {
|
|
124
|
+
const n = Number(options.observeEvery);
|
|
125
|
+
if (!Number.isInteger(n) || n < 1) throw new QuoxUserError('--observe-every needs a whole number of turns (1 or more).');
|
|
126
|
+
observe.every_turns = n;
|
|
127
|
+
}
|
|
128
|
+
if (options.observeMilestones) observe.milestones = true;
|
|
129
|
+
body.observe = observe;
|
|
130
|
+
}
|
|
101
131
|
|
|
102
132
|
const data = await client.post(resolveEndpoint('objectives.create').path, { service: resolveEndpoint('objectives.create').service, body });
|
|
103
133
|
printSuccess(`Objective created: ${data.id}`);
|
|
@@ -155,6 +185,17 @@ export function registerObjectiveCommands(program, ctx) {
|
|
|
155
185
|
printSuccess(`Objective ${id}: ${data.status}${data.message ? ` — ${data.message}` : ''}`);
|
|
156
186
|
});
|
|
157
187
|
|
|
188
|
+
objective
|
|
189
|
+
.command('retry')
|
|
190
|
+
.description('Retry a failed or partially completed objective: failed and skipped steps are reset and the plan comes back for approval')
|
|
191
|
+
.argument('<id>', 'objective ID')
|
|
192
|
+
.action(async (id) => {
|
|
193
|
+
auth.requireAuth();
|
|
194
|
+
const ep = resolveEndpoint('objectives.retry', { id });
|
|
195
|
+
const data = await client.post(ep.path, { service: ep.service });
|
|
196
|
+
printSuccess(`Objective ${id}: ${data.steps_reset ?? 0} step(s) reset, plan is back for approval. Run \`quox objective approve ${id}\` to run them again.`);
|
|
197
|
+
});
|
|
198
|
+
|
|
158
199
|
objective
|
|
159
200
|
.command('checkpoints')
|
|
160
201
|
.description('List pending HITL checkpoints across the org (approval queue)')
|
|
@@ -191,6 +232,12 @@ export function registerObjectiveCommands(program, ctx) {
|
|
|
191
232
|
if (options.notes) body.notes = options.notes;
|
|
192
233
|
const params = { id: objectiveId, checkpointId };
|
|
193
234
|
const data = await client.post(resolveEndpoint('objectives.checkpoint-approve', params).path, { service: resolveEndpoint('objectives.checkpoint-approve', params).service, body });
|
|
235
|
+
// LOOPQ-HALT: "approved" is not "running". When the server says the loop did not start, say so in words.
|
|
236
|
+
if (data.started === false) {
|
|
237
|
+
printWarning(`Checkpoint ${checkpointId}: ${data.status}, but the objective did NOT start (objective ${data.objective_status || 'pending'}).`);
|
|
238
|
+
if (data.hint) printWarning(data.hint);
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
194
241
|
printSuccess(`Checkpoint ${checkpointId}: ${data.status}${data.objective_status ? ` (objective ${data.objective_status})` : ''}`);
|
|
195
242
|
});
|
|
196
243
|
|
|
@@ -209,6 +256,17 @@ export function registerObjectiveCommands(program, ctx) {
|
|
|
209
256
|
printSuccess(`Checkpoint ${checkpointId}: ${data.status}${data.objective_status ? ` (objective ${data.objective_status})` : ''}`);
|
|
210
257
|
});
|
|
211
258
|
|
|
259
|
+
objective
|
|
260
|
+
.command('cancel')
|
|
261
|
+
.description('Cancel an objective (pending ones included, e.g. proof leftovers that never started); its open tasks are cancelled too. For a RUNNING loop prefer `halt`, which also kills the live session.')
|
|
262
|
+
.argument('<objectiveId>', 'objective ID')
|
|
263
|
+
.action(async (objectiveId) => {
|
|
264
|
+
auth.requireAuth();
|
|
265
|
+
const ep = resolveEndpoint('objectives.cancel', { id: objectiveId });
|
|
266
|
+
const data = await client.delete(ep.path, { service: ep.service });
|
|
267
|
+
printSuccess(`Objective ${objectiveId}: ${data?.status || 'cancelled'}`);
|
|
268
|
+
});
|
|
269
|
+
|
|
212
270
|
objective
|
|
213
271
|
.command('halt')
|
|
214
272
|
.description('Halt a running QLoop loop ON DEMAND (unconditional human stop; no pending gate needed). Fires the same signed-kill as a gate deny.')
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `quox offload` : run a heavy command on a pool worker VM and behave like running it locally.
|
|
3
|
+
*
|
|
4
|
+
* quox offload [--dir <path>] [--fresh] [--keep] [--cores N --memory-gb N --disk-gb N] -- <command...>
|
|
5
|
+
* quox offload status
|
|
6
|
+
* quox offload release
|
|
7
|
+
*
|
|
8
|
+
* Engine: lib/core/offload.js. The worker is leased through the human pool REST API
|
|
9
|
+
* (same as `quox vm pool lease`) with a dedicated key at ~/.config/quox/offload_ed25519.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
import { printInfo } from '../core/output.js';
|
|
14
|
+
import { makePoolRest } from '../core/vm.js';
|
|
15
|
+
import { OffloadError, realDeps, runOffload, releaseWorker, workerStatus, gitToplevel, WORKER_NAME_RE } from '../core/offload.js';
|
|
16
|
+
|
|
17
|
+
export function registerOffloadCommands(program, ctx, { deps: injected } = {}) {
|
|
18
|
+
const { client, auth } = ctx;
|
|
19
|
+
const json = () => program.opts().output === 'json';
|
|
20
|
+
const base = () => injected || realDeps({ rest: makePoolRest({ client }) });
|
|
21
|
+
// --worker <name> / QUOX_OFFLOAD_WORKER: your own worker (state, lease, size), not the box's shared one.
|
|
22
|
+
const mk = (options = {}) => {
|
|
23
|
+
const d = base();
|
|
24
|
+
const name = options.worker ?? d.env?.QUOX_OFFLOAD_WORKER;
|
|
25
|
+
if (name !== undefined && name !== '' && !WORKER_NAME_RE.test(String(name))) {
|
|
26
|
+
throw new OffloadError(`worker name must be lowercase letters, digits and dashes (up to 32), got ${JSON.stringify(name)}`);
|
|
27
|
+
}
|
|
28
|
+
return name ? Object.assign(Object.create(Object.getPrototypeOf(d)), d, { worker: String(name) }) : d;
|
|
29
|
+
};
|
|
30
|
+
const WORKER_HELP = 'use your own named worker (its own lease and size) instead of the shared one; or set QUOX_OFFLOAD_WORKER';
|
|
31
|
+
|
|
32
|
+
const off = program
|
|
33
|
+
.command('offload')
|
|
34
|
+
.description('Run a heavy command on a pool worker VM (synced dir, cached npm ci, live output, same exit code)')
|
|
35
|
+
.argument('[command...]', 'command to run remotely (put it after --)')
|
|
36
|
+
.option('--dir <path>', 'directory to sync (default: git toplevel of the current directory)')
|
|
37
|
+
.option('--fresh', 'release the current worker, lease a new one and reinstall dependencies')
|
|
38
|
+
.option('--keep', 'leave the worker leased for reuse (the default; kept for compatibility)')
|
|
39
|
+
.option('--cores <n>', 'vCPU cores for a newly leased worker')
|
|
40
|
+
.option('--memory-gb <n>', 'memory in GB for a newly leased worker')
|
|
41
|
+
.option('--disk-gb <n>', 'disk in GB for a newly leased worker')
|
|
42
|
+
.option('--worker <name>', WORKER_HELP)
|
|
43
|
+
.option('--docker', 'also give the worker Docker (user hyp in the docker group) and build the quox-sandbox images from the synced repo when they are missing or changed')
|
|
44
|
+
.allowExcessArguments(true)
|
|
45
|
+
.action(async (command, options) => {
|
|
46
|
+
auth.requireAuth();
|
|
47
|
+
const cwd = process.cwd();
|
|
48
|
+
const dir = path.resolve(options.dir || gitToplevel(cwd));
|
|
49
|
+
try {
|
|
50
|
+
const code = await runOffload(mk(options), {
|
|
51
|
+
dir, cwd, command, fresh: !!options.fresh, docker: !!options.docker,
|
|
52
|
+
cores: options.cores, memoryGb: options.memoryGb, diskGb: options.diskGb,
|
|
53
|
+
});
|
|
54
|
+
process.exitCode = code;
|
|
55
|
+
} catch (e) {
|
|
56
|
+
if (!(e instanceof OffloadError)) throw e;
|
|
57
|
+
process.stderr.write(`offload: ${e.message}\n`);
|
|
58
|
+
process.exitCode = 1;
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
off.command('status')
|
|
63
|
+
.description('Show your offload worker: vmid, ip, lease expiry, synced dirs')
|
|
64
|
+
.option('--worker <name>', WORKER_HELP)
|
|
65
|
+
.action(async (options) => {
|
|
66
|
+
auth.requireAuth();
|
|
67
|
+
const s = await workerStatus(mk(options));
|
|
68
|
+
if (json()) { console.log(JSON.stringify(s, null, 2)); return; }
|
|
69
|
+
if (!s.worker) { printInfo('no offload worker leased (it is leased on the next `quox offload -- <command>`)'); return; }
|
|
70
|
+
const w = s.worker;
|
|
71
|
+
console.log(`worker ${w.vmid} ${w.ip || '?'} ${w.state} lessee ${w.lessee} lease expires ${w.lease_expires_at || '?'}`);
|
|
72
|
+
for (const d of s.dirs) console.log(` synced ${d.local} -> ${d.remote} ${d.synced_at || ''}`);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
off.command('release')
|
|
76
|
+
.description('Release (destroy) your offload worker via the pool')
|
|
77
|
+
.option('--worker <name>', WORKER_HELP)
|
|
78
|
+
.action(async (options) => {
|
|
79
|
+
auth.requireAuth();
|
|
80
|
+
try {
|
|
81
|
+
const vmid = await releaseWorker(mk(options));
|
|
82
|
+
if (json()) console.log(JSON.stringify({ released: vmid }));
|
|
83
|
+
else printInfo(vmid ? `released worker ${vmid}` : 'no offload worker to release');
|
|
84
|
+
} catch (e) {
|
|
85
|
+
process.stderr.write(`offload: release failed: ${e.message}\n`);
|
|
86
|
+
process.exitCode = 1;
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
package/lib/commands/onboard.js
CHANGED
|
@@ -64,7 +64,8 @@ export function inferTargetType(value) {
|
|
|
64
64
|
/** curl install command for a host that is not yet a fleet-enrolled dev server. */
|
|
65
65
|
export function buildOnboardInstallCommand(collectorBase, host) {
|
|
66
66
|
const base = String(collectorBase || '').replace(/\/+$/, '');
|
|
67
|
-
|
|
67
|
+
// REL-423: fail loud, never `curl | sudo bash` (that pipe reports success when the download fails).
|
|
68
|
+
return `( f=$(mktemp) && trap 'rm -f "$f"' EXIT && curl -fsSL ${base}/install -o "$f" && sudo bash "$f" --host-id ${host} )`;
|
|
68
69
|
}
|
|
69
70
|
|
|
70
71
|
// ── the wizard ──────────────────────────────────────────────────────────────
|
package/lib/commands/org.js
CHANGED
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { QuoxError } from '../core/errors.js';
|
|
6
|
-
import { formatOutput, formatDetail, printSuccess } from '../core/output.js';
|
|
6
|
+
import { formatOutput, formatDetail, printSuccess, printWarning } from '../core/output.js';
|
|
7
|
+
import { otherProfileUsers, listProcs } from '../core/profileUsers.js';
|
|
7
8
|
import { resolveOrgId } from './helpers.js';
|
|
8
9
|
import { resolveEndpoint } from '../api/endpoints.js';
|
|
10
|
+
import { numberedOrgLines, pickOrgByInput, sharedSwitchHint } from '../quoxon/orgSwitch.js';
|
|
9
11
|
|
|
10
12
|
export function registerOrgCommands(program, ctx) {
|
|
11
13
|
const { client, auth, config } = ctx;
|
|
@@ -89,9 +91,26 @@ export function registerOrgCommands(program, ctx) {
|
|
|
89
91
|
org
|
|
90
92
|
.command('switch')
|
|
91
93
|
.description('Switch active organization context')
|
|
92
|
-
.argument('
|
|
93
|
-
.action(async (
|
|
94
|
+
.argument('[orgId]', 'organization ID, slug, or the number from the list (omit to pick from a numbered list)')
|
|
95
|
+
.action(async (orgIdArg) => {
|
|
94
96
|
auth.requireAuth();
|
|
97
|
+
let orgId = orgIdArg;
|
|
98
|
+
if (!orgId || /^\d+$/.test(orgId)) {
|
|
99
|
+
const l = await client.get(resolveEndpoint('orgs.list').path, { service: resolveEndpoint('orgs.list').service });
|
|
100
|
+
const orgs = Array.isArray(l) ? l : (l?.organizations || l?.orgs || l?.data || []);
|
|
101
|
+
if (!orgs.length) throw new QuoxError('No organisations returned for this login.', 1);
|
|
102
|
+
if (!orgId) {
|
|
103
|
+
const curId = (() => { try { return auth.getOrgId(); } catch { return null; } })();
|
|
104
|
+
for (const line of numberedOrgLines(orgs, curId)) console.log(line);
|
|
105
|
+
if (!process.stdin.isTTY) throw new QuoxError('Pass a number, slug or ID: quox org switch <number>.', 1);
|
|
106
|
+
const rl = (await import('node:readline/promises')).createInterface({ input: process.stdin, output: process.stdout });
|
|
107
|
+
try { orgId = await rl.question('Switch to which? (number, slug, or Enter to cancel) '); } finally { rl.close(); }
|
|
108
|
+
if (!orgId.trim()) { console.log('Not switched.'); return; }
|
|
109
|
+
}
|
|
110
|
+
const pick = pickOrgByInput(orgId, orgs);
|
|
111
|
+
if (pick.org) orgId = pick.org.id;
|
|
112
|
+
else if (/^\d+$/.test(orgId)) throw new QuoxError(`No org numbered ${orgId}. Run \`quox org switch\` to see the list.`, 1);
|
|
113
|
+
}
|
|
95
114
|
// The server matches memberships by org ID only. Accept a slug (or exact name) by
|
|
96
115
|
// resolving it against the caller's org list first; a 26-char ULID passes through.
|
|
97
116
|
let targetId = orgId;
|
|
@@ -120,6 +139,14 @@ export function registerOrgCommands(program, ctx) {
|
|
|
120
139
|
config.setAuth(authData);
|
|
121
140
|
|
|
122
141
|
printSuccess(`Switched to ${data.org?.name || orgId}`);
|
|
142
|
+
// #1034: this changed the SHARED profile. Name the other live sessions that will follow it.
|
|
143
|
+
try {
|
|
144
|
+
const name = config.getActiveProfileName?.();
|
|
145
|
+
const others = name ? otherProfileUsers({ profile: name, defaultProfile: config._data?.activeProfile, procs: listProcs(), selfPids: [process.pid, process.ppid] }) : [];
|
|
146
|
+
if (others.length) {
|
|
147
|
+
printWarning(sharedSwitchHint({ name, pids: others.map(p => p.pid) }));
|
|
148
|
+
}
|
|
149
|
+
} catch { /* best effort: never fail the switch over the warning */ }
|
|
123
150
|
});
|
|
124
151
|
|
|
125
152
|
// Members subcommands
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* quox peek <id>
|
|
3
|
+
*
|
|
4
|
+
* Look up an id without knowing what it is: an AEE envelope, inbox (approval) item, objective, workflow
|
|
5
|
+
* run, WARD receipt or agent. The id's shape picks what to ask; every lookup is an existing read
|
|
6
|
+
* endpoint; a miss names each kind tried and what it answered. The TUI's /peek prints the same card.
|
|
7
|
+
*/
|
|
8
|
+
import { createPeekFetchers, peekId, peekLines } from '../core/peek.js';
|
|
9
|
+
import { resolveOrgId } from './helpers.js';
|
|
10
|
+
|
|
11
|
+
export function registerPeekCommand(program, ctx) {
|
|
12
|
+
const { client, auth } = ctx;
|
|
13
|
+
program
|
|
14
|
+
.command('peek')
|
|
15
|
+
.description('Look up an envelope, inbox item, objective, run, WARD receipt or agent by id (read only)')
|
|
16
|
+
.argument('<id>', 'the id, e.g. a ULID, a WARD entry UUID or an agent name')
|
|
17
|
+
.action(async (id) => {
|
|
18
|
+
auth.requireAuth();
|
|
19
|
+
const orgId = resolveOrgId(auth, program);
|
|
20
|
+
const r = await peekId(id, createPeekFetchers({ client, orgId: () => orgId }));
|
|
21
|
+
if (program.opts().output === 'json') {
|
|
22
|
+
console.log(JSON.stringify({ id: r.id, shape: r.shape, kind: r.hit?.kind || null, data: r.hit?.data || null, also: r.also, tried: r.tried }, null, 2));
|
|
23
|
+
} else {
|
|
24
|
+
for (const l of peekLines(r)) console.log(l.text);
|
|
25
|
+
}
|
|
26
|
+
if (!r.hit) process.exitCode = 5; // not found (the inbox verbs use 5 for not_found too)
|
|
27
|
+
});
|
|
28
|
+
}
|
package/lib/commands/plan.js
CHANGED
|
@@ -137,6 +137,23 @@ function renderRoadmapsList(roadmaps) {
|
|
|
137
137
|
return lines;
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
+
function renderSearchResults(data) {
|
|
141
|
+
const results = data.results || [];
|
|
142
|
+
if (results.length === 0) return [chalk.dim(` No streams match "${data.q}".`)];
|
|
143
|
+
const lines = [''];
|
|
144
|
+
for (const r of results) {
|
|
145
|
+
const g = statusGlyph(r.status);
|
|
146
|
+
const where = [...new Set((r.matches || []).map((m) => m.where))].join(', ');
|
|
147
|
+
const first = (r.matches || []).find((m) => m.snippet) || {};
|
|
148
|
+
lines.push(
|
|
149
|
+
` ${g.color(g.glyph)} ${pad(truncate(r.id, ID_WIDTH), ID_WIDTH)} ${pad(truncate(r.name, NAME_WIDTH), NAME_WIDTH)} `
|
|
150
|
+
+ `${pad(r.status, 15)} ${pad(where, 18)} ${chalk.dim(truncate(first.snippet || '', 60))}`
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
lines.push('', chalk.dim(` ${results.length} stream${results.length === 1 ? '' : 's'} matched "${data.q}"`));
|
|
154
|
+
return lines;
|
|
155
|
+
}
|
|
156
|
+
|
|
140
157
|
function streamLine(s, { indent = 0, showReasons = false } = {}) {
|
|
141
158
|
const prefix = indent > 0 ? ' '.repeat(indent) + '└ ' : ' ';
|
|
142
159
|
const g = statusGlyph(s.status);
|
|
@@ -546,6 +563,27 @@ export function registerPlanCommands(program, ctx) {
|
|
|
546
563
|
printSuccess(`Created roadmap ${created.id || options.id} for org ${orgId}`);
|
|
547
564
|
});
|
|
548
565
|
|
|
566
|
+
// ── search ───────────────────────────────────────────────────────────
|
|
567
|
+
|
|
568
|
+
plan
|
|
569
|
+
.command('search <text...>')
|
|
570
|
+
.description('Search streams by text (id, name, notes, plan, phase titles)')
|
|
571
|
+
.option('--roadmap <id>', 'limit to one roadmap')
|
|
572
|
+
.option('--status <status>', `limit to one status (${VALID_STATUSES.join(', ')})`)
|
|
573
|
+
.action(async (textParts, options) => {
|
|
574
|
+
auth.requireAuth();
|
|
575
|
+
if (options.status && !VALID_STATUSES.includes(options.status)) {
|
|
576
|
+
throw new Error(`invalid --status "${options.status}" (expected ${VALID_STATUSES.join(', ')})`);
|
|
577
|
+
}
|
|
578
|
+
const query = { q: textParts.join(' ') };
|
|
579
|
+
if (options.roadmap) query.roadmap = options.roadmap;
|
|
580
|
+
if (options.status) query.status = options.status;
|
|
581
|
+
const ep = resolveEndpoint('quoxplan.search');
|
|
582
|
+
const data = await client.get(ep.path, { service: ep.service, query });
|
|
583
|
+
if (isJsonOutput(program)) return printJson(data);
|
|
584
|
+
console.log(renderSearchResults(data).join('\n'));
|
|
585
|
+
});
|
|
586
|
+
|
|
549
587
|
// ── list ─────────────────────────────────────────────────────────────
|
|
550
588
|
|
|
551
589
|
plan
|
package/lib/commands/plugin.js
CHANGED
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
* Plugin commands: org-scoped plugin install registry (PD-1..PD-8)
|
|
3
3
|
*
|
|
4
4
|
* quox plugin list|get|install|update|uninstall|mine
|
|
5
|
+
* quox plugin enable <id> (PLUGIN-IMG #1012: prebuilt private image, licence first)
|
|
5
6
|
* quox plugin data list|get|set|delete
|
|
6
7
|
* quox plugin secrets list|set|reveal|delete
|
|
7
8
|
* quox plugin assign list|add|remove
|
|
8
9
|
* quox plugin trusted-keys list|add|remove
|
|
10
|
+
* quox plugin revocations list|add|remove
|
|
9
11
|
*
|
|
10
12
|
* Backend: services/auth/routes/plugins.js, mounted org-scoped at
|
|
11
13
|
* `/api/orgs/:orgId/...` (server.js). Install/update/uninstall and all
|
|
@@ -18,6 +20,9 @@ import { readFileSync } from 'node:fs';
|
|
|
18
20
|
import { formatOutput, formatDetail, printSuccess, printWarning, printInfo } from '../core/output.js';
|
|
19
21
|
import { resolveOrgId, parseJSON } from './helpers.js';
|
|
20
22
|
import { resolveEndpoint } from '../api/endpoints.js';
|
|
23
|
+
import { enablePlugin, entitlementFrom } from '../server/pluginEnable.js';
|
|
24
|
+
import { resolveInstall, readEnvKeys } from '../server/install.js';
|
|
25
|
+
import { createSys } from '../server/sys.js';
|
|
21
26
|
|
|
22
27
|
/** Read + JSON.parse a file, wrapping errors with the file path for context. */
|
|
23
28
|
function readJsonFile(filePath, label) {
|
|
@@ -113,6 +118,56 @@ export function registerPluginCommands(program, ctx) {
|
|
|
113
118
|
}, { title: `Licence: ${pluginId}` });
|
|
114
119
|
});
|
|
115
120
|
|
|
121
|
+
// ── plugin enable (PLUGIN-IMG #1012) ────────────────────────────────────────
|
|
122
|
+
// Starts a licensed plugin from its prebuilt private image on this
|
|
123
|
+
// self-hosted install. Licence first: unlicensed means nothing runs.
|
|
124
|
+
|
|
125
|
+
plugin
|
|
126
|
+
.command('enable')
|
|
127
|
+
.description('Start a licensed plugin from its prebuilt image on this self-hosted install (QuoxPlan for now). Unlicensed: refused, nothing pulled.')
|
|
128
|
+
.argument('<pluginId>', 'plugin id, e.g. quoxplan')
|
|
129
|
+
.option('--dir <path>', 'the install directory (default: the one Getting started recorded)')
|
|
130
|
+
.action(async (pluginId, opts) => {
|
|
131
|
+
auth.requireAuth();
|
|
132
|
+
const deps = ctx.serverDeps || {};
|
|
133
|
+
const env = deps.env || process.env;
|
|
134
|
+
const sys = deps.sys || createSys();
|
|
135
|
+
const checkEntitlement = async (id) => {
|
|
136
|
+
const ep = resolveEndpoint('setup.licensing.entitlements.list');
|
|
137
|
+
const data = await client.get(ep.path, { service: ep.service });
|
|
138
|
+
return entitlementFrom(data, id);
|
|
139
|
+
};
|
|
140
|
+
// Licence before anything that touches the box: an unlicensed enable must not even look for the install.
|
|
141
|
+
let ent;
|
|
142
|
+
try { ent = await checkEntitlement(pluginId); } catch (err) { ent = err; }
|
|
143
|
+
const resolveFirst = !(ent instanceof Error) && ent && ent.entitled;
|
|
144
|
+
let install = null;
|
|
145
|
+
if (resolveFirst) {
|
|
146
|
+
const i = await resolveInstall({ dir: opts.dir, env, sys, journey: deps.journey });
|
|
147
|
+
if (i.error) { const e = new Error(i.error); e.exitCode = 2; throw e; }
|
|
148
|
+
install = i;
|
|
149
|
+
}
|
|
150
|
+
const tag = install ? (env.QUOX_IMAGE_TAG || readEnvKeys(install.repoDir, ['QUOX_IMAGE_TAG']).QUOX_IMAGE_TAG || '') : '';
|
|
151
|
+
const result = await enablePlugin({
|
|
152
|
+
pluginId,
|
|
153
|
+
checkEntitlement: async () => { if (ent instanceof Error) throw ent; return ent; },
|
|
154
|
+
install: install || { repoDir: '' },
|
|
155
|
+
sys,
|
|
156
|
+
tag,
|
|
157
|
+
...(deps.getPullCredential ? { getPullCredential: deps.getPullCredential } : {}),
|
|
158
|
+
...(deps.sleep ? { sleep: deps.sleep } : {}),
|
|
159
|
+
log: (l) => printInfo(l),
|
|
160
|
+
});
|
|
161
|
+
if (program.opts().output === 'json') {
|
|
162
|
+
console.log(JSON.stringify({ plugin: pluginId, ok: result.ok, stage: result.stage, message: result.message }, null, 2));
|
|
163
|
+
} else if (result.ok) {
|
|
164
|
+
printSuccess(result.message);
|
|
165
|
+
} else {
|
|
166
|
+
printWarning(result.message);
|
|
167
|
+
}
|
|
168
|
+
if (!result.ok) process.exitCode = result.stage === 'licence' ? 3 : 1;
|
|
169
|
+
});
|
|
170
|
+
|
|
116
171
|
// ── plugin list ─────────────────────────────────────────────────────────────
|
|
117
172
|
|
|
118
173
|
plugin
|
|
@@ -536,4 +591,59 @@ export function registerPluginCommands(program, ctx) {
|
|
|
536
591
|
await client.delete(ep.path, reqOpts);
|
|
537
592
|
printSuccess('Trusted key removed.');
|
|
538
593
|
});
|
|
594
|
+
|
|
595
|
+
// ── plugin revocations (SDK-TEAM W5) ────────────────────────────────────────
|
|
596
|
+
|
|
597
|
+
const revocations = plugin
|
|
598
|
+
.command('revocations')
|
|
599
|
+
.description('Revoke a plugin signer key or one bundle digest for this org (admin only). A revoked plugin cannot be installed and stops loading on the next page load.');
|
|
600
|
+
|
|
601
|
+
revocations
|
|
602
|
+
.command('list')
|
|
603
|
+
.description('List revocations')
|
|
604
|
+
.action(async () => {
|
|
605
|
+
auth.requireAuth();
|
|
606
|
+
const orgId = resolveOrgId(auth, program);
|
|
607
|
+
const ep = resolveEndpoint('plugins.revocations.list', { orgId });
|
|
608
|
+
const result = await client.get(ep.path, { service: ep.service });
|
|
609
|
+
const rows = result.revocations || result || [];
|
|
610
|
+
formatOutput({
|
|
611
|
+
columns: ['id', 'kind', 'value', 'reason', 'revoked_by', 'revoked_at'],
|
|
612
|
+
headers: ['ID', 'Kind', 'Value', 'Reason', 'Revoked By', 'Revoked'],
|
|
613
|
+
rows,
|
|
614
|
+
}, { format: program.opts().output, emptyMessage: 'No revocations.' });
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
revocations
|
|
618
|
+
.command('add')
|
|
619
|
+
.description('Revoke a signer key or a bundle digest')
|
|
620
|
+
.option('--signer-key <hex>', 'raw Ed25519 public key (64 hex), as in signature.json public_key_hex')
|
|
621
|
+
.option('--bundle-digest <hex>', 'sha256 of plugin.esm.js (64 hex), as shown by quox plugin list')
|
|
622
|
+
.option('--reason <text>', 'why (kept in the audit trail)')
|
|
623
|
+
.action(async (options) => {
|
|
624
|
+
auth.requireAuth();
|
|
625
|
+
if (!!options.signerKey === !!options.bundleDigest) {
|
|
626
|
+
throw new Error('Specify exactly one of --signer-key or --bundle-digest.');
|
|
627
|
+
}
|
|
628
|
+
const orgId = resolveOrgId(auth, program);
|
|
629
|
+
const body = options.signerKey
|
|
630
|
+
? { kind: 'signer_key', value: options.signerKey, reason: options.reason }
|
|
631
|
+
: { kind: 'bundle_digest', value: options.bundleDigest, reason: options.reason };
|
|
632
|
+
const ep = resolveEndpoint('plugins.revocations.create', { orgId });
|
|
633
|
+
const result = await client.post(ep.path, { service: ep.service, body });
|
|
634
|
+
printSuccess('Revoked.');
|
|
635
|
+
formatDetail(result.revocation || result, { format: program.opts().output });
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
revocations
|
|
639
|
+
.command('remove')
|
|
640
|
+
.description('Lift a revocation')
|
|
641
|
+
.argument('<revocationId>', 'revocation ID')
|
|
642
|
+
.action(async (revocationId) => {
|
|
643
|
+
auth.requireAuth();
|
|
644
|
+
const orgId = resolveOrgId(auth, program);
|
|
645
|
+
const ep = resolveEndpoint('plugins.revocations.delete', { orgId, revocationId });
|
|
646
|
+
await client.delete(ep.path, { service: ep.service });
|
|
647
|
+
printSuccess('Revocation lifted.');
|
|
648
|
+
});
|
|
539
649
|
}
|