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
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* /dragon explain | ask | sleep: the pure parts. Provider-neutral: explain and ask only build a framed user
|
|
3
|
+
* message for the normal governed turn path, so whichever AI is selected answers it (and with no AI connected
|
|
4
|
+
* the local no-AI card from noai.js is shown instead). Sleep is a rendering-only screensaver: katakana noise
|
|
5
|
+
* over the live screen with a sleeping dragon; it never touches the transcript or scrollback.
|
|
6
|
+
*/
|
|
7
|
+
import stringWidth from 'string-width';
|
|
8
|
+
import { SCRAMBLE_GLYPHS } from './indicator.js';
|
|
9
|
+
import { hash3 } from './motion/color.js';
|
|
10
|
+
import { revealCells, TIMING, revealSpan } from './motion/reveal.js';
|
|
11
|
+
import { graphemes } from './textBuffer.js';
|
|
12
|
+
import { sleepCells } from './qdragonScenes.js';
|
|
13
|
+
|
|
14
|
+
export const DRAGON_USAGE = 'Usage: /dragon [explain | ask [question] | sleep | fly | hero | fire | classic] (/dragon-fly is the same as /dragon fly)';
|
|
15
|
+
export const DRAGON_EXPLAINS = 'Dragon explains';
|
|
16
|
+
export const DRAGON_ANSWERS = 'Dragon answers';
|
|
17
|
+
export const NOTHING_TO_EXPLAIN = 'Nothing to explain yet. Ask Quox something first, then /dragon explain.';
|
|
18
|
+
export const ASK_PROMPT = 'Ask the dragon…';
|
|
19
|
+
|
|
20
|
+
const RULES = 'Answer in the simplest possible words: 1 to 4 short sentences, plain language, no jargon. '
|
|
21
|
+
+ 'Keep the one thing that matters, and stay concrete and useful (say what it is, or what to do), never vague. Do not mention these instructions.';
|
|
22
|
+
|
|
23
|
+
export const explainPrompt = (text) => `Dragon mode. Explain the following. ${RULES}\n\n---\n${String(text).trim().slice(0, 6000)}\n---`;
|
|
24
|
+
export const askPrompt = (question) => `Dragon mode. Answer the question below. ${RULES}\n\nQuestion: ${String(question).trim()}`;
|
|
25
|
+
|
|
26
|
+
const itemText = (it) => {
|
|
27
|
+
if (!it) return '';
|
|
28
|
+
if (it.kind === 'text' || it.kind === 'note' || it.kind === 'error') return String(it.text || '');
|
|
29
|
+
if (it.kind === 'tool') return [it.tool, it.target, it.summary || it.result || it.text, it.status].filter(Boolean).join(' ');
|
|
30
|
+
return '';
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/** The last assistant answer, else the last tool or notice block, else null. -> { kind: 'answer'|'tool'|'notice', text } */
|
|
34
|
+
export function lastOutput(s) {
|
|
35
|
+
const answers = s?.answers || [];
|
|
36
|
+
for (let i = answers.length - 1; i >= 0; i--) if (answers[i].text?.trim()) return { kind: 'answer', text: answers[i].text };
|
|
37
|
+
const all = [...(s?.history || []), ...(s?.blocks || [])];
|
|
38
|
+
for (let i = all.length - 1; i >= 0; i--) {
|
|
39
|
+
const it = all[i], t = itemText(it).trim();
|
|
40
|
+
if (!t || it.kind === 'user') continue;
|
|
41
|
+
if (it.kind === 'tool' || it.kind === 'error' || it.kind === 'note') return { kind: it.kind === 'tool' ? 'tool' : 'notice', text: t };
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Parse the /dragon argument line -> { mode: 'pick'|'fire'|'idle'|'hero'|'explain'|'ask'|'sleep'|'fly', question? } | null (usage). */
|
|
47
|
+
export function parseDragonArg(restArg) {
|
|
48
|
+
const t = String(restArg || '').trim();
|
|
49
|
+
if (!t) return { mode: 'pick' };
|
|
50
|
+
const [w, ...rest] = t.split(/\s+/);
|
|
51
|
+
switch (w.toLowerCase()) {
|
|
52
|
+
case 'fire': return rest.length ? null : { mode: 'fire' };
|
|
53
|
+
case 'classic': return rest.length ? null : { mode: 'idle' };
|
|
54
|
+
case 'hero': return rest.length ? null : { mode: 'hero' };
|
|
55
|
+
// `/dragon explain <thing>` is a question about that thing (owner 2026-10-15: it used to print usage).
|
|
56
|
+
case 'explain': return rest.length ? { mode: 'ask', question: rest.join(' ').trim() } : { mode: 'explain' };
|
|
57
|
+
case 'companion': return { mode: 'companion', arg: rest.join(' ') };
|
|
58
|
+
case 'sleep': return rest.length ? null : { mode: 'sleep' };
|
|
59
|
+
case 'fly': return rest.length ? null : { mode: 'fly' };
|
|
60
|
+
case 'ask': return { mode: 'ask', question: rest.join(' ').trim() };
|
|
61
|
+
// Anything else is a question for the dragon, never a usage error.
|
|
62
|
+
default: return { mode: 'ask', question: t };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ---- sleep: katakana veil ---------------------------------------------------------------------------------
|
|
67
|
+
export const VEIL_IN_MS = 700; // text drops into katakana, left to right
|
|
68
|
+
export const VEIL_STEP_MS = 700; // the noise re-rolls this slowly (low frame rate; a shimmer, not a flicker)
|
|
69
|
+
export const WAKE_MS = Math.round(revealSpan(TIMING.row) * 1000); // the existing decode reveal, run forward
|
|
70
|
+
|
|
71
|
+
const isText = (ch) => /^[\p{L}\p{N}\p{P}\p{S}]+$/u.test(ch);
|
|
72
|
+
const kana = (i, k, salt) => SCRAMBLE_GLYPHS[Math.floor(hash3(i, k, salt) * SCRAMBLE_GLYPHS.length)];
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* One source line as veil cells at `ms` since sleep began (phase 'in' then 'asleep') or since wake began
|
|
76
|
+
* (phase 'wake'). Cells are { ch, kind: 'kana'|'plain'|'blank'|'glow', g }. Width of every column is preserved
|
|
77
|
+
* (a 2-wide char becomes two kana), so rows never change length. still: no re-rolling.
|
|
78
|
+
*/
|
|
79
|
+
export function veilRow(text, ms, { phase = 'asleep', still = false, salt = 1, row = 0 } = {}) {
|
|
80
|
+
if (phase === 'wake') return revealCells(text, ms / 1000, TIMING.row, { salt: salt + row }).map((c) => ({ ...c }));
|
|
81
|
+
const gs = graphemes(String(text ?? '')).map((g) => g.text);
|
|
82
|
+
const n = gs.length, bucket = still ? 0 : Math.floor(ms / VEIL_STEP_MS);
|
|
83
|
+
const edge = phase === 'in' && !still ? (ms / VEIL_IN_MS) * n : Infinity; // cells left of the edge are veiled
|
|
84
|
+
const out = [];
|
|
85
|
+
gs.forEach((ch, i) => {
|
|
86
|
+
const w = stringWidth(ch);
|
|
87
|
+
if (w === 0) return;
|
|
88
|
+
if (ch === ' ' || !isText(ch) || i > edge) { out.push({ ch, kind: 'plain', g: 0 }); return; }
|
|
89
|
+
for (let k = 0; k < w; k++) out.push({ ch: kana(i * 2 + k + row * 131, bucket, salt), kind: 'kana', g: hash3(i, bucket + 7, salt) });
|
|
90
|
+
});
|
|
91
|
+
return out;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export const veilText = (cells) => cells.map((c) => c.ch).join('');
|
|
95
|
+
export const isVeiled = (cells) => cells.some((c) => c.kind === 'kana');
|
|
96
|
+
|
|
97
|
+
/** The visible text the screen shows, as at most `rows` lines wrapped to `cols` (tail of the transcript). */
|
|
98
|
+
export function sourceLines(s, cols, rows) {
|
|
99
|
+
const all = [...(s?.history || []), ...(s?.blocks || [])];
|
|
100
|
+
const lines = [];
|
|
101
|
+
for (let i = all.length - 1; i >= 0 && lines.length < rows; i--) {
|
|
102
|
+
const it = all[i];
|
|
103
|
+
const t = it.kind === 'user' ? `> ${it.text || ''}` : itemText(it);
|
|
104
|
+
if (!t.trim()) continue;
|
|
105
|
+
const wrapped = [];
|
|
106
|
+
for (const raw of t.split('\n')) {
|
|
107
|
+
let r = raw;
|
|
108
|
+
if (!r) { wrapped.push(''); continue; }
|
|
109
|
+
while (stringWidth(r) > cols) { let cut = cols; while (cut > 1 && stringWidth(r.slice(0, cut)) > cols) cut--; wrapped.push(r.slice(0, cut)); r = r.slice(cut); }
|
|
110
|
+
wrapped.push(r);
|
|
111
|
+
}
|
|
112
|
+
lines.unshift(...wrapped);
|
|
113
|
+
}
|
|
114
|
+
return lines.slice(-rows);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// ---- the sleep screen -----------------------------------------------------------------------------------------
|
|
118
|
+
export const SLEEP_HINT = 'asleep · any key wakes · /back when you return';
|
|
119
|
+
const VEIL_RGB = [129, 140, 248], HINT_RGB = [186, 230, 253];
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* The whole sleep frame as rows of { ch, rgb } cells, `rows` tall and `cols` wide. ms = since sleep began, or
|
|
123
|
+
* since wake began when wake is true (text decodes back, the dragon is gone). Pure: no transcript access, the
|
|
124
|
+
* caller passes the source lines. still (reduced motion): a static veil and a still dragon. mono: no colour.
|
|
125
|
+
*/
|
|
126
|
+
export function composeSleep({ lines, cols, rows, ms = 0, wake = false, still = false, mono = false, theme = 'dark', size }) {
|
|
127
|
+
const phase = wake ? 'wake' : ms < VEIL_IN_MS && !still ? 'in' : 'asleep';
|
|
128
|
+
const col = (c) => (mono ? null : c);
|
|
129
|
+
const grid = Array.from({ length: rows }, () => Array.from({ length: cols }, () => ({ ch: ' ', rgb: null })));
|
|
130
|
+
const body = wake ? rows : rows - 1; // the last row holds the wake hint while asleep
|
|
131
|
+
const src = lines.slice(-body);
|
|
132
|
+
const top = body - src.length;
|
|
133
|
+
src.forEach((line, i) => {
|
|
134
|
+
veilRow(line, ms, { phase, still, row: i }).slice(0, cols).forEach((c, x) => {
|
|
135
|
+
grid[top + i][x] = { ch: c.ch, rgb: c.kind === 'kana' ? col(VEIL_RGB) : null, bold: c.kind === 'glow' && c.g > 0.5 };
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
if (!wake) {
|
|
139
|
+
const sz = size ?? (rows >= 32 && cols >= 64 ? undefined : 'mid');
|
|
140
|
+
const dcols = Math.min(cols, sz === 'mid' || cols < 64 ? 44 : 72);
|
|
141
|
+
const dc = sleepCells(ms, dcols, undefined, { theme, mono, still, size: sz });
|
|
142
|
+
const x0 = Math.max(0, Math.floor((cols - dcols) / 2)), y0 = Math.max(0, Math.floor((rows - 1 - dc.length) / 2));
|
|
143
|
+
dc.forEach((r, i) => {
|
|
144
|
+
if (y0 + i >= rows - 1) return;
|
|
145
|
+
r.forEach((c, x) => { if (x0 + x < cols) grid[y0 + i][x0 + x] = { ch: c.ch, rgb: mono ? null : c.rgb, bg: c.bg || undefined }; });
|
|
146
|
+
});
|
|
147
|
+
const hint = [...SLEEP_HINT], hx = Math.max(0, Math.floor((cols - hint.length) / 2));
|
|
148
|
+
hint.forEach((ch, i) => { if (hx + i < cols) grid[rows - 1][hx + i] = { ch, rgb: col(HINT_RGB) }; });
|
|
149
|
+
}
|
|
150
|
+
return grid;
|
|
151
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ONE moment engine for both dragon systems. A "moment" is a stream fact worth a dragon: an approval is waiting, a turn or the
|
|
3
|
+
* stream failed, a long turn finished, a turn finished. The classification (and its dedupe) lives here once; the table says what
|
|
4
|
+
* each moment calls: `mood` is the Q dragon's cinematic clip (qmotion playDragon), `companion` is whether an attached companion
|
|
5
|
+
* dragon shows itself. The controller (dragonCompanion.js) runs the engine on every stream fact and owns the routing: while a
|
|
6
|
+
* companion owns the moments the Q dragon stays quiet, so a moment is never two dragons.
|
|
7
|
+
*/
|
|
8
|
+
export const MOMENTS = Object.freeze({
|
|
9
|
+
approval: Object.freeze({ mood: 'waiting', companion: true }),
|
|
10
|
+
failure: Object.freeze({ mood: 'failure', companion: true }),
|
|
11
|
+
long: Object.freeze({ mood: 'success', companion: true }),
|
|
12
|
+
success: Object.freeze({ mood: 'success', companion: false }),
|
|
13
|
+
});
|
|
14
|
+
/** A turn at least this long counts as a "long task" when it finishes. */
|
|
15
|
+
export const LONG_TASK_MS = 30000;
|
|
16
|
+
|
|
17
|
+
export function createMomentEngine({ now = Date.now } = {}) {
|
|
18
|
+
const seen = new Set();
|
|
19
|
+
let turnStart = null;
|
|
20
|
+
const moment = (kind) => ({ kind, ...MOMENTS[kind] });
|
|
21
|
+
return {
|
|
22
|
+
turnStarted() { turnStart = now(); },
|
|
23
|
+
reset() { seen.clear(); turnStart = null; },
|
|
24
|
+
/** A reducer event (the companion's vocabulary) -> { kind, mood, companion } | null. */
|
|
25
|
+
observe(ev) {
|
|
26
|
+
if (!ev) return null;
|
|
27
|
+
if (ev.type === 'approval.requested') {
|
|
28
|
+
// The same approval arrives twice (the stream event, then the inbox poll) under different ids: one moment for it.
|
|
29
|
+
const keys = [ev.call_id, ev.inbox_item_id, ev.approval_id].filter(Boolean).map(String);
|
|
30
|
+
if (keys.some(k => seen.has(k))) return null;
|
|
31
|
+
keys.forEach(k => seen.add(k));
|
|
32
|
+
return moment('approval');
|
|
33
|
+
}
|
|
34
|
+
if (ev.type === 'error') return moment('failure');
|
|
35
|
+
if (ev.type === 'turn.finished') {
|
|
36
|
+
const started = turnStart; turnStart = null;
|
|
37
|
+
if (ev.status === 'failed' || ev.status === 'unconfirmed') return moment('failure');
|
|
38
|
+
if (ev.status !== 'completed') return null;
|
|
39
|
+
return moment(started != null && now() - started >= LONG_TASK_MS ? 'long' : 'success');
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ---- domain moments: a fact from the estate summons the matching dragon (companion mode `on` only) ------------------------
|
|
47
|
+
/** A dragon summoned by a domain moment cannot be summoned again for this long. */
|
|
48
|
+
export const SUMMON_COOLDOWN_MS = 60000;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* An objective or loop roster row -> { dragon, caption } when it has finished or failed, else null. The caption states only
|
|
52
|
+
* what the row says. The roster row carries no agent, so the dragon is Seer (the plan dragon); an agent field would pick its own.
|
|
53
|
+
*/
|
|
54
|
+
export function objectiveMoment(row) {
|
|
55
|
+
if (!row || (row.kind !== 'objective' && row.kind !== 'loop') || (row.state !== 'done' && row.state !== 'failed')) return null;
|
|
56
|
+
const noun = row.kind === 'loop' ? 'Loop' : 'Objective', name = row.name || row.id;
|
|
57
|
+
const caption = row.state === 'done' ? `${noun} finished: ${name}.` : `${noun} failed: ${name}${row.activity ? ` (${row.activity})` : ''}.`;
|
|
58
|
+
return { dragon: 'seer', caption };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Watches roster rows and reports each objective/loop that was seen unfinished and is now done or failed, once. The first
|
|
63
|
+
* observation is a baseline (rows already finished at startup never fire); a reported key is retired for good.
|
|
64
|
+
*/
|
|
65
|
+
export function createRosterWatch() {
|
|
66
|
+
const active = new Set(), retired = new Set();
|
|
67
|
+
let primed = false;
|
|
68
|
+
return {
|
|
69
|
+
observe(rows = []) {
|
|
70
|
+
const out = [];
|
|
71
|
+
for (const r of rows) {
|
|
72
|
+
if (!r || (r.kind !== 'objective' && r.kind !== 'loop') || retired.has(r.key)) continue;
|
|
73
|
+
if (r.state === 'done' || r.state === 'failed') {
|
|
74
|
+
if (active.delete(r.key) && primed) { const m = objectiveMoment(r); if (m) out.push(m); }
|
|
75
|
+
retired.add(r.key);
|
|
76
|
+
} else active.add(r.key);
|
|
77
|
+
}
|
|
78
|
+
primed = true;
|
|
79
|
+
return out;
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The reads behind the dragon jobs (lib/dragon/jobs.js). Each is the same call a `quox` verb already makes, read-only,
|
|
3
|
+
* bounded, retries off. The CLI client throws on a non-2xx, so a throw is the failure and a returned body is checked for the
|
|
4
|
+
* error shapes some routes use with a 200 (success:false). Nothing here turns an error into a count.
|
|
5
|
+
*/
|
|
6
|
+
import { resolveEndpoint } from '../api/endpoints.js';
|
|
7
|
+
import { healthOf } from './objects/fleet.js';
|
|
8
|
+
|
|
9
|
+
const TIMEOUT = 5000;
|
|
10
|
+
const STATE = { 1: 'up', 0: 'down', 2: 'pending', 3: 'maintenance' };
|
|
11
|
+
const kumaState = (m) => (m && typeof m.state === 'string' ? m.state : m && Object.hasOwn(STATE, m.status) ? STATE[m.status] : 'unknown'); // same mapping as `quox kuma`
|
|
12
|
+
const whyOf = (e) => (e?.status ? `HTTP ${e.status}` : /timed out/i.test(e?.message || '') ? 'timed out' : e?.message || 'failed');
|
|
13
|
+
|
|
14
|
+
export function createDragonReads({ client }) {
|
|
15
|
+
const get = (name, params, query) => { const ep = resolveEndpoint(name, params); return client.get(ep.path, { service: ep.service, query, retries: 0, timeout: TIMEOUT }); };
|
|
16
|
+
return {
|
|
17
|
+
/** WARD inclusion receipt of one envelope (POST /ward/verify-receipt, the route /proof uses). -> { ok, result } | { ok:false, error } */
|
|
18
|
+
async verifyReceipt(envelopeId) {
|
|
19
|
+
try {
|
|
20
|
+
const d = await client.post('/ward/verify-receipt', { service: 'collector', body: { source_id: envelopeId, source_kind: 'AEE' }, retries: 0, timeout: TIMEOUT });
|
|
21
|
+
return { ok: true, result: d?.result || d };
|
|
22
|
+
} catch (e) { return { ok: false, error: whyOf(e) }; }
|
|
23
|
+
},
|
|
24
|
+
/** `quox kuma` live read -> { up, down, total, avgPing, downNames, ageSeconds } */
|
|
25
|
+
async routes() {
|
|
26
|
+
const d = await get('mon.kuma.live.get');
|
|
27
|
+
if (d?.success === false) throw new Error(`kuma returned an error body: ${d.error || 'no detail'}`);
|
|
28
|
+
if (!Array.isArray(d?.monitors)) throw new Error('kuma answered with no monitors list');
|
|
29
|
+
const ms = d.monitors;
|
|
30
|
+
const up = ms.filter(m => kumaState(m) === 'up'), down = ms.filter(m => kumaState(m) === 'down');
|
|
31
|
+
const pings = up.filter(m => m.ping != null).map(m => Number(m.ping)).filter(Number.isFinite); // a null ping is no measurement, not 0 ms
|
|
32
|
+
return { up: up.length, down: down.length, total: ms.length, avgPing: pings.length ? pings.reduce((a, b) => a + b, 0) / pings.length : null, downNames: down.map(m => m.name || `monitor ${m.id}`), ageSeconds: Number.isFinite(d.ageSeconds) ? d.ageSeconds : null };
|
|
33
|
+
},
|
|
34
|
+
/** `quox plan focus` -> { id, done, total } of the first focus stream; null when nothing is in focus or there is no roadmap. */
|
|
35
|
+
async plan() {
|
|
36
|
+
const rms = (await get('quoxplan.roadmaps.list'))?.roadmaps;
|
|
37
|
+
if (!Array.isArray(rms)) throw new Error('quoxplan answered with no roadmaps list');
|
|
38
|
+
if (!rms.length) return null;
|
|
39
|
+
const streams = (await get('quoxplan.roadmap.streams.list', { roadmapId: rms[0].id }, { lens: 'focus' }))?.streams;
|
|
40
|
+
if (!Array.isArray(streams)) throw new Error('quoxplan answered with no streams list');
|
|
41
|
+
if (!streams.length) return null;
|
|
42
|
+
// The first few focus streams, in the server's order: the first one that has phases gives "x of y". A stream with none (a meta
|
|
43
|
+
// stream) or whose phases could not be read is only named, never given a made-up count.
|
|
44
|
+
const top = streams.slice(0, 3);
|
|
45
|
+
const details = await Promise.allSettled(top.map(t => get('quoxplan.stream.get', { id: t.id })));
|
|
46
|
+
const rows = top.map((t, i) => {
|
|
47
|
+
const phases = details[i].status === 'fulfilled' && Array.isArray(details[i].value?.phases) ? details[i].value.phases : null;
|
|
48
|
+
return phases ? { id: t.id, done: phases.filter(p => p.done_at || /^(done|complete)/i.test(String(p.status || ''))).length, total: phases.length } : { id: t.id, done: null, total: null };
|
|
49
|
+
});
|
|
50
|
+
return rows.find(r => r.total > 0) || rows[0];
|
|
51
|
+
},
|
|
52
|
+
/** `quox fleet hosts` rows bucketed by health. */
|
|
53
|
+
async fleet() {
|
|
54
|
+
const d = await get('v1.fleet.hosts.list');
|
|
55
|
+
const hosts = Array.isArray(d) ? d : d?.hosts;
|
|
56
|
+
if (!Array.isArray(hosts)) throw new Error('unexpected fleet response');
|
|
57
|
+
const c = { total: hosts.length, healthy: 0, degraded: 0, unhealthy: 0, offline: 0, unknown: 0 };
|
|
58
|
+
for (const h of hosts) c[healthOf(h)]++;
|
|
59
|
+
return c;
|
|
60
|
+
},
|
|
61
|
+
/** The org's open security findings (engagement store). */
|
|
62
|
+
async findings() {
|
|
63
|
+
const d = await get('engagement.findings.open', {});
|
|
64
|
+
if (!Array.isArray(d?.findings)) throw new Error('unexpected findings response');
|
|
65
|
+
return { open: d.findings.length, severe: d.findings.filter(f => /^(critical|high)$/i.test(String(f.severity || ''))).length };
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/** Ink views for /dragon explain|ask (the talking dragon) and /dragon sleep (the screensaver). Frames come from dragonModes.js. */
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { Box, Text } from 'ink';
|
|
4
|
+
import { cellNodes } from './qmotion.js';
|
|
5
|
+
import { composeSleep } from './dragonModes.js';
|
|
6
|
+
import { pickCells } from './qdragonScenes.js';
|
|
7
|
+
import { flyFrame, flyCols } from './qdragonFly.js';
|
|
8
|
+
import { mono, isLight, clip } from './theme.js';
|
|
9
|
+
import { useFrame } from './motion/frame.js';
|
|
10
|
+
|
|
11
|
+
const h = React.createElement;
|
|
12
|
+
|
|
13
|
+
/** The sleep screen: the whole live region while asleep (and for the decode on wake). Reads the clock itself. */
|
|
14
|
+
export function SleepScreen({ lines, cols, rows, startedAt, wakeAt = null, still = false }) {
|
|
15
|
+
useFrame();
|
|
16
|
+
const now = Date.now();
|
|
17
|
+
const wake = wakeAt != null;
|
|
18
|
+
const ms = wake ? now - wakeAt : now - startedAt;
|
|
19
|
+
const grid = composeSleep({ lines, cols, rows, ms, wake, still, mono: mono(), theme: isLight() ? 'light' : 'dark' });
|
|
20
|
+
return h(Box, { flexDirection: 'column' }, ...grid.map((r, k) => h(Text, { key: k, wrap: 'truncate' }, ...cellNodes(r, `s${k}-`))));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** The compact dragon beside an explain/ask answer: the mouth works while text streams, then it rests with idle eyes. */
|
|
24
|
+
export function DragonTalk({ cols, label, talking, since, still = false }) {
|
|
25
|
+
useFrame();
|
|
26
|
+
const dcols = Math.min(cols, 44);
|
|
27
|
+
const t = Date.now() - since;
|
|
28
|
+
const cells = pickCells(t, dcols, undefined, { theme: isLight() ? 'light' : 'dark', mono: mono(), still: still || !talking, talk: talking && !still, size: 'mid', mouthSide: 'right' });
|
|
29
|
+
return h(Box, { flexDirection: 'column', marginTop: 1 },
|
|
30
|
+
...cells.map((row, k) => h(Text, { key: k, wrap: 'truncate' }, ...cellNodes(row, `t${k}-`))),
|
|
31
|
+
h(Text, null, clip(label, Math.max(10, cols - 2))));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** /dragon-fly: one pass of the dragon in flight across the live region (qdragonFly.js). `still`: a single frame, no motion. */
|
|
35
|
+
export function FlyLive({ cols, rows, startedAt, still = false, chromeH = null }) {
|
|
36
|
+
useFrame();
|
|
37
|
+
const c = flyCols(cols);
|
|
38
|
+
const cells = flyFrame(Date.now() - startedAt, c, { still, mono: mono(), theme: isLight() ? 'light' : 'dark', termRows: rows, chromeH });
|
|
39
|
+
return h(Box, { flexDirection: 'column', marginTop: 1 },
|
|
40
|
+
...cells.map((row, k) => h(Text, { key: k, wrap: 'truncate' }, ...cellNodes(row, `f${k}-`))));
|
|
41
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keys typed before the app is ready (R3 audit D4). bin/quox.js calls this before it loads React, Ink or any
|
|
3
|
+
* command module, so the tty is raw (no cooked echo) and every key is kept for the composer. main() calls it
|
|
4
|
+
* again and gets the same capture. Tiny on purpose: it must not import anything heavy.
|
|
5
|
+
*
|
|
6
|
+
* A line typed while the tty was still cooked reaches us when raw mode turns on, with the kernel's ICRNL
|
|
7
|
+
* having turned its Enter into LF; that first read is mapped back to CR so the Enter submits as typed.
|
|
8
|
+
*/
|
|
9
|
+
import { PASTE_ON, PASTE_OFF } from './keys.js';
|
|
10
|
+
|
|
11
|
+
const COOKED_MS = 50; // the read that drains the cooked line buffer arrives right after raw mode turns on
|
|
12
|
+
let shared = null;
|
|
13
|
+
|
|
14
|
+
export function captureEarlyInput(stdin = process.stdin, stdout = process.stdout) {
|
|
15
|
+
const own = stdin === process.stdin;
|
|
16
|
+
if (own && shared) return shared;
|
|
17
|
+
if (!stdin?.isTTY) return null;
|
|
18
|
+
const chunks = [];
|
|
19
|
+
const t0 = Date.now();
|
|
20
|
+
const fn = (d) => {
|
|
21
|
+
const s = typeof d === 'string' ? d : d.toString('utf8');
|
|
22
|
+
chunks.push(Date.now() - t0 < COOKED_MS ? s.replace(/\n/g, '\r') : s);
|
|
23
|
+
};
|
|
24
|
+
try { stdin.setRawMode?.(true); stdin.resume?.(); } catch { /* not a tty after all */ }
|
|
25
|
+
stdin.on('data', fn);
|
|
26
|
+
if (stdout?.isTTY) stdout.write(PASTE_ON);
|
|
27
|
+
const cap = {
|
|
28
|
+
chunks,
|
|
29
|
+
detach: () => stdin.off('data', fn),
|
|
30
|
+
/** Nothing will take the terminal over (help, a flag error): give it back as it was. */
|
|
31
|
+
release: () => {
|
|
32
|
+
stdin.off('data', fn);
|
|
33
|
+
try { stdin.setRawMode?.(false); stdin.pause?.(); } catch { /* ignore */ }
|
|
34
|
+
if (stdout?.isTTY) stdout.write(PASTE_OFF);
|
|
35
|
+
if (own) shared = null;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
if (own) shared = cap;
|
|
39
|
+
return cap;
|
|
40
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Echo of a command the human typed, shown in the scrollback like a prompt line (wrapped in full, secrets masked).
|
|
2
|
+
// Owner 2026-10-15: "why truncated": the echo wraps like any prompt; only a runaway paste is capped.
|
|
3
|
+
import { redactSecrets } from './slotChat.js';
|
|
4
|
+
import { clip } from './theme.js';
|
|
5
|
+
|
|
6
|
+
const PIN_CMD = /^\/(authenticate|authorise|authorize)(\s|$)/i;
|
|
7
|
+
|
|
8
|
+
/** -> { shown, full }: `shown` is the whole command on one logical line (the view wraps it; capped at ECHO_CAP), `full` is the masked text the transcript records. */
|
|
9
|
+
export const ECHO_CAP = 2000;
|
|
10
|
+
export function echoLine(text, { cols = 100 } = {}) {
|
|
11
|
+
let t = String(text ?? '').trim();
|
|
12
|
+
if (PIN_CMD.test(t)) t = t.split(/\s+/)[0]; // a stray argument may be a PIN: never shown
|
|
13
|
+
const full = redactSecrets(t).text;
|
|
14
|
+
return { shown: clip(full.replace(/\s*\n\s*/g, ' '), ECHO_CAP), full };
|
|
15
|
+
}
|
package/lib/quoxon/egg.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The
|
|
2
|
+
* The launch Easter egg (CLI-QUOX). On launch the v8 dragon greets you (googly eyes open, blink, smile), rarely:
|
|
3
3
|
* 1 in EGG_ODDS launches, never twice in a row, never in --print, under reduced motion or off a TTY.
|
|
4
|
-
* /
|
|
4
|
+
* /dragon plays it on demand, and the cinematic motion level always may.
|
|
5
5
|
*
|
|
6
6
|
* pickLaunchEgg is pure; launchEgg adds the one bit of persistence (did the last launch show the eye?) in
|
|
7
7
|
* ~/.config/quox/motion.json. QUOX_EGG=eye forces it (demos, captures); QUOX_EGG=off disables it.
|