quoxcli 0.0.0-stage → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +35 -0
- package/README.md +144 -2
- package/bin/quox.js +265 -0
- package/bin/quoxon.js +8 -0
- package/lib/api/endpoints/admin.js +151 -0
- package/lib/api/endpoints/aee.js +38 -0
- package/lib/api/endpoints/agent-attach.js +126 -0
- package/lib/api/endpoints/agent-schedules.js +26 -0
- package/lib/api/endpoints/agents.js +63 -0
- package/lib/api/endpoints/assistants.js +62 -0
- package/lib/api/endpoints/audit.js +14 -0
- package/lib/api/endpoints/auth.js +50 -0
- package/lib/api/endpoints/awareness.js +34 -0
- package/lib/api/endpoints/away.js +15 -0
- package/lib/api/endpoints/backup-schedules.js +20 -0
- package/lib/api/endpoints/backups.js +86 -0
- package/lib/api/endpoints/brain.js +140 -0
- package/lib/api/endpoints/budgets.js +62 -0
- package/lib/api/endpoints/calendarq.js +71 -0
- package/lib/api/endpoints/catalog.js +14 -0
- package/lib/api/endpoints/chat.js +61 -0
- package/lib/api/endpoints/consent.js +26 -0
- package/lib/api/endpoints/contactsq.js +68 -0
- package/lib/api/endpoints/conversations.js +46 -0
- package/lib/api/endpoints/custom-roles.js +92 -0
- package/lib/api/endpoints/divisions.js +56 -0
- package/lib/api/endpoints/domains.js +38 -0
- package/lib/api/endpoints/engagement.js +231 -0
- package/lib/api/endpoints/engine.js +11 -0
- package/lib/api/endpoints/entity.js +50 -0
- package/lib/api/endpoints/executions.js +45 -0
- package/lib/api/endpoints/fetchAllowlist.js +27 -0
- package/lib/api/endpoints/file.js +20 -0
- package/lib/api/endpoints/files.js +40 -0
- package/lib/api/endpoints/github.js +21 -0
- package/lib/api/endpoints/governance.js +43 -0
- package/lib/api/endpoints/hat.js +66 -0
- package/lib/api/endpoints/inbox.js +52 -0
- package/lib/api/endpoints/inboxq.js +120 -0
- package/lib/api/endpoints/index.js +242 -0
- package/lib/api/endpoints/invites.js +19 -0
- package/lib/api/endpoints/llm-policy.js +43 -0
- package/lib/api/endpoints/lucid.js +89 -0
- package/lib/api/endpoints/members.js +32 -0
- package/lib/api/endpoints/memory.js +94 -0
- package/lib/api/endpoints/mfa.js +32 -0
- package/lib/api/endpoints/mind.js +13 -0
- package/lib/api/endpoints/mon.js +184 -0
- package/lib/api/endpoints/notesq.js +43 -0
- package/lib/api/endpoints/objectives.js +68 -0
- package/lib/api/endpoints/orgs.js +38 -0
- package/lib/api/endpoints/plugins.js +152 -0
- package/lib/api/endpoints/powers.js +75 -0
- package/lib/api/endpoints/presence.js +33 -0
- package/lib/api/endpoints/prompts.js +69 -0
- package/lib/api/endpoints/qlarity.js +122 -0
- package/lib/api/endpoints/quoxbox.js +55 -0
- package/lib/api/endpoints/quoxchat.js +54 -0
- package/lib/api/endpoints/quoxflow.js +32 -0
- package/lib/api/endpoints/quoxplan.js +121 -0
- package/lib/api/endpoints/quoxseo.js +114 -0
- package/lib/api/endpoints/reach.js +47 -0
- package/lib/api/endpoints/router.js +17 -0
- package/lib/api/endpoints/runs.js +38 -0
- package/lib/api/endpoints/safety.js +53 -0
- package/lib/api/endpoints/scim.js +46 -0
- package/lib/api/endpoints/scopes.js +14 -0
- package/lib/api/endpoints/security.js +69 -0
- package/lib/api/endpoints/setup.js +90 -0
- package/lib/api/endpoints/skills.js +200 -0
- package/lib/api/endpoints/sso.js +67 -0
- package/lib/api/endpoints/stepup.js +20 -0
- package/lib/api/endpoints/tags.js +32 -0
- package/lib/api/endpoints/teams.js +56 -0
- package/lib/api/endpoints/telephony.js +46 -0
- package/lib/api/endpoints/tg.js +56 -0
- package/lib/api/endpoints/tools.js +50 -0
- package/lib/api/endpoints/traces.js +157 -0
- package/lib/api/endpoints/triggers.js +96 -0
- package/lib/api/endpoints/user-library.js +41 -0
- package/lib/api/endpoints/users.js +20 -0
- package/lib/api/endpoints/v1.js +585 -0
- package/lib/api/endpoints/vault.js +192 -0
- package/lib/api/endpoints/voice.js +22 -0
- package/lib/api/endpoints/volt.js +84 -0
- package/lib/api/endpoints/ward.js +47 -0
- package/lib/api/endpoints/webhooks.js +46 -0
- package/lib/api/endpoints/workflows.js +169 -0
- package/lib/api/endpoints/x.js +32 -0
- package/lib/api/endpoints.js +15 -0
- package/lib/commands/actions.js +61 -0
- package/lib/commands/admin.js +375 -0
- package/lib/commands/aee.js +99 -0
- package/lib/commands/agent.js +337 -0
- package/lib/commands/agentAttach.js +1528 -0
- package/lib/commands/approvals.js +119 -0
- package/lib/commands/aside.js +24 -0
- package/lib/commands/ask.js +144 -0
- package/lib/commands/assistant.js +169 -0
- package/lib/commands/auth.js +464 -0
- package/lib/commands/awareness.js +88 -0
- package/lib/commands/backup.js +377 -0
- package/lib/commands/brain.js +1085 -0
- package/lib/commands/budget.js +241 -0
- package/lib/commands/build.js +170 -0
- package/lib/commands/calendar.js +216 -0
- package/lib/commands/capabilities.js +34 -0
- package/lib/commands/chat.js +295 -0
- package/lib/commands/claude.js +380 -0
- package/lib/commands/config-cmd.js +106 -0
- package/lib/commands/consent.js +84 -0
- package/lib/commands/contacts.js +1016 -0
- package/lib/commands/contactsSelftest.js +132 -0
- package/lib/commands/conversation.js +105 -0
- package/lib/commands/dashboard.js +43 -0
- package/lib/commands/department.js +96 -0
- package/lib/commands/dev.js +620 -0
- package/lib/commands/devResident.js +326 -0
- package/lib/commands/devSupervisor.js +1062 -0
- package/lib/commands/discord.js +132 -0
- package/lib/commands/doctor.js +181 -0
- package/lib/commands/domain.js +114 -0
- package/lib/commands/done.js +347 -0
- package/lib/commands/engagement.js +597 -0
- package/lib/commands/entity.js +119 -0
- package/lib/commands/facebook.js +212 -0
- package/lib/commands/fetchAllowlist.js +71 -0
- package/lib/commands/file.js +165 -0
- package/lib/commands/fleet.js +1189 -0
- package/lib/commands/governance.js +647 -0
- package/lib/commands/gripe.js +355 -0
- package/lib/commands/hat.js +374 -0
- package/lib/commands/helpers.js +96 -0
- package/lib/commands/hyperion.js +58 -0
- package/lib/commands/inbox.js +173 -0
- package/lib/commands/instagram.js +264 -0
- package/lib/commands/integration.js +100 -0
- package/lib/commands/inventory.js +115 -0
- package/lib/commands/invites.js +45 -0
- package/lib/commands/licence.js +139 -0
- package/lib/commands/linkedin.js +178 -0
- package/lib/commands/llm-policy.js +117 -0
- package/lib/commands/llm.js +45 -0
- package/lib/commands/lucid.js +597 -0
- package/lib/commands/mail.js +531 -0
- package/lib/commands/memory.js +361 -0
- package/lib/commands/mind.js +71 -0
- package/lib/commands/mon.js +581 -0
- package/lib/commands/monitoring.js +86 -0
- package/lib/commands/motion.js +22 -0
- package/lib/commands/notes.js +1246 -0
- package/lib/commands/notesBatch.js +160 -0
- package/lib/commands/notesBridges.js +56 -0
- package/lib/commands/notesLinks.js +60 -0
- package/lib/commands/notification.js +57 -0
- package/lib/commands/nucleus.js +123 -0
- package/lib/commands/objective.js +240 -0
- package/lib/commands/offload.js +89 -0
- package/lib/commands/onboard.js +329 -0
- package/lib/commands/open.js +56 -0
- package/lib/commands/org.js +276 -0
- package/lib/commands/peek.js +28 -0
- package/lib/commands/plan.js +944 -0
- package/lib/commands/plugin-doctor.js +1091 -0
- package/lib/commands/plugin.js +649 -0
- package/lib/commands/policy.js +78 -0
- package/lib/commands/powers.js +296 -0
- package/lib/commands/presence.js +89 -0
- package/lib/commands/prompt.js +350 -0
- package/lib/commands/provider.js +159 -0
- package/lib/commands/qlarity.js +706 -0
- package/lib/commands/quoxbox.js +270 -0
- package/lib/commands/quoxchat.js +275 -0
- package/lib/commands/quoxseo.js +378 -0
- package/lib/commands/reach.js +159 -0
- package/lib/commands/role.js +286 -0
- package/lib/commands/router.js +77 -0
- package/lib/commands/rows.js +358 -0
- package/lib/commands/run.js +187 -0
- package/lib/commands/safety.js +107 -0
- package/lib/commands/scim.js +88 -0
- package/lib/commands/scope.js +58 -0
- package/lib/commands/security.js +157 -0
- package/lib/commands/server.js +292 -0
- package/lib/commands/service.js +89 -0
- package/lib/commands/settings.js +99 -0
- package/lib/commands/setup.js +569 -0
- package/lib/commands/skillManifest.js +113 -0
- package/lib/commands/skillRightsFormat.js +38 -0
- package/lib/commands/skills.js +687 -0
- package/lib/commands/slot.js +1451 -0
- package/lib/commands/sso.js +229 -0
- package/lib/commands/status.js +137 -0
- package/lib/commands/tag.js +91 -0
- package/lib/commands/team.js +142 -0
- package/lib/commands/tg.js +240 -0
- package/lib/commands/tiktok.js +218 -0
- package/lib/commands/tips.js +23 -0
- package/lib/commands/tool.js +304 -0
- package/lib/commands/trace.js +530 -0
- package/lib/commands/trigger.js +223 -0
- package/lib/commands/update.js +46 -0
- package/lib/commands/vault.js +1447 -0
- package/lib/commands/vm.js +237 -0
- package/lib/commands/voice.js +213 -0
- package/lib/commands/volt.js +570 -0
- package/lib/commands/walkthrough.js +32 -0
- package/lib/commands/watch.js +167 -0
- package/lib/commands/webhook.js +137 -0
- package/lib/commands/welcome.js +14 -0
- package/lib/commands/workflow.js +660 -0
- package/lib/commands/x.js +448 -0
- package/lib/core/actingAs.js +136 -0
- package/lib/core/activeSummary.js +186 -0
- package/lib/core/aee.js +53 -0
- package/lib/core/agentAlias.js +163 -0
- package/lib/core/approvalContext.js +61 -0
- package/lib/core/aside.js +54 -0
- package/lib/core/askDecision.js +60 -0
- package/lib/core/auth.js +501 -0
- package/lib/core/banner.js +143 -0
- package/lib/core/brainPrime.js +90 -0
- package/lib/core/callerSource.js +129 -0
- package/lib/core/claudeLs.js +94 -0
- package/lib/core/cliBuild.js +62 -0
- package/lib/core/client.js +693 -0
- package/lib/core/commandRegistrars.js +121 -0
- package/lib/core/completions.js +163 -0
- package/lib/core/config.js +669 -0
- package/lib/core/confirm.js +37 -0
- package/lib/core/customHats.js +168 -0
- package/lib/core/deeplinks.js +76 -0
- package/lib/core/doneEngineFetch.js +227 -0
- package/lib/core/errors.js +441 -0
- package/lib/core/global-flags.js +190 -0
- package/lib/core/governedSession.js +402 -0
- package/lib/core/hyperion.js +102 -0
- package/lib/core/inboxResolution.js +65 -0
- package/lib/core/lazyCommands.js +122 -0
- package/lib/core/liveSessionsReport.js +112 -0
- package/lib/core/offload.js +504 -0
- package/lib/core/org-override.js +52 -0
- package/lib/core/orgResolve.js +70 -0
- package/lib/core/output.js +239 -0
- package/lib/core/peek.js +126 -0
- package/lib/core/prodEnv.js +7 -0
- package/lib/core/profileUsers.js +51 -0
- package/lib/core/promptCancel.js +18 -0
- package/lib/core/quoxglyph.js +158 -0
- package/lib/core/repoPath.js +11 -0
- package/lib/core/residentAlarm.js +282 -0
- package/lib/core/residentAuth.js +243 -0
- package/lib/core/residentPump.js +229 -0
- package/lib/core/residentSeed.js +106 -0
- package/lib/core/rootOptions.js +39 -0
- package/lib/core/router.js +168 -0
- package/lib/core/selfUpdate.js +188 -0
- package/lib/core/sessionHeartbeat.js +192 -0
- package/lib/core/sessionsOverview.js +224 -0
- package/lib/core/slotKeeper.js +527 -0
- package/lib/core/slotWake.js +120 -0
- package/lib/core/supervisorEngine.js +933 -0
- package/lib/core/systemdInstaller.js +256 -0
- package/lib/core/version.js +87 -0
- package/lib/core/vm.js +361 -0
- package/lib/core/vmTui.js +86 -0
- package/lib/core/walkthrough.js +35 -0
- package/lib/hyperion/deck.js +29 -0
- package/lib/lucid/LucidCard.jsx +68 -0
- package/lib/lucid/LucidIntro.jsx +92 -0
- package/lib/lucid/blind.js +71 -0
- package/lib/lucid/cards.js +86 -0
- package/lib/lucid/deck.js +32 -0
- package/lib/lucid/fmt.js +139 -0
- package/lib/lucid/markdown.js +81 -0
- package/lib/lucid/motion.js +56 -0
- package/lib/lucid/sitrep.js +173 -0
- package/lib/plugins/loader.js +93 -0
- package/lib/quoxon/activity.js +116 -0
- package/lib/quoxon/aocl.js +117 -0
- package/lib/quoxon/api.js +952 -0
- package/lib/quoxon/app.js +4032 -0
- package/lib/quoxon/approvalFacts.js +94 -0
- package/lib/quoxon/approvalsView.js +325 -0
- package/lib/quoxon/asideView.js +40 -0
- package/lib/quoxon/ask.js +121 -0
- package/lib/quoxon/away.js +52 -0
- package/lib/quoxon/bang.js +224 -0
- package/lib/quoxon/bulkRisk.js +17 -0
- package/lib/quoxon/capabilities.js +82 -0
- package/lib/quoxon/cells.js +53 -0
- package/lib/quoxon/commandShort.js +112 -0
- package/lib/quoxon/commands.js +479 -0
- package/lib/quoxon/connect.js +654 -0
- package/lib/quoxon/connectCard.js +45 -0
- package/lib/quoxon/consent.js +86 -0
- package/lib/quoxon/context.js +68 -0
- package/lib/quoxon/copy.js +34 -0
- package/lib/quoxon/countdownLine.js +11 -0
- package/lib/quoxon/demo.autoplay.js +29 -0
- package/lib/quoxon/demo.fixtures.js +24 -0
- package/lib/quoxon/demo.js +76 -0
- package/lib/quoxon/devObserver.js +20 -0
- package/lib/quoxon/dividerAocl.js +191 -0
- package/lib/quoxon/dividerRule.js +57 -0
- package/lib/quoxon/dragonModes.js +150 -0
- package/lib/quoxon/dragonView.js +41 -0
- package/lib/quoxon/earlyInput.js +40 -0
- package/lib/quoxon/echo.js +15 -0
- package/lib/quoxon/egg.js +36 -0
- package/lib/quoxon/events.js +677 -0
- package/lib/quoxon/feedback.js +50 -0
- package/lib/quoxon/gallery.js +237 -0
- package/lib/quoxon/handoffOffer.js +78 -0
- package/lib/quoxon/hatSwitch.js +37 -0
- package/lib/quoxon/headless.js +161 -0
- package/lib/quoxon/hostUrls.js +41 -0
- package/lib/quoxon/indicator.js +197 -0
- package/lib/quoxon/intent.js +52 -0
- package/lib/quoxon/keys.js +164 -0
- package/lib/quoxon/launcher.js +103 -0
- package/lib/quoxon/main.js +176 -0
- package/lib/quoxon/markdown.js +341 -0
- package/lib/quoxon/markdownSettle.js +19 -0
- package/lib/quoxon/matrixDomains.json +46 -0
- package/lib/quoxon/mentions.js +90 -0
- package/lib/quoxon/mind.js +103 -0
- package/lib/quoxon/mode.js +46 -0
- package/lib/quoxon/model.js +311 -0
- package/lib/quoxon/modelPrefs.js +345 -0
- package/lib/quoxon/motion/clock.js +70 -0
- package/lib/quoxon/motion/color.js +35 -0
- package/lib/quoxon/motion/frame.js +14 -0
- package/lib/quoxon/motion/level.js +91 -0
- package/lib/quoxon/motion/reveal.js +54 -0
- package/lib/quoxon/motion/ring.js +79 -0
- package/lib/quoxon/mouse.js +211 -0
- package/lib/quoxon/noai.js +57 -0
- package/lib/quoxon/objects/agent.js +61 -0
- package/lib/quoxon/objects/away.js +72 -0
- package/lib/quoxon/objects/crystal.js +100 -0
- package/lib/quoxon/objects/fetch.js +182 -0
- package/lib/quoxon/objects/fleet.js +149 -0
- package/lib/quoxon/objects/health.js +186 -0
- package/lib/quoxon/objects/index.js +106 -0
- package/lib/quoxon/objects/ladder.js +71 -0
- package/lib/quoxon/objects/memory.js +44 -0
- package/lib/quoxon/objects/mirror.js +137 -0
- package/lib/quoxon/objects/model.js +118 -0
- package/lib/quoxon/objects/peek.js +17 -0
- package/lib/quoxon/objects/proof.js +110 -0
- package/lib/quoxon/objects/prove.js +130 -0
- package/lib/quoxon/objects/replay.js +125 -0
- package/lib/quoxon/objects/sitrep.js +58 -0
- package/lib/quoxon/objects/skill.js +105 -0
- package/lib/quoxon/objects/view.js +87 -0
- package/lib/quoxon/objects/workflow.js +119 -0
- package/lib/quoxon/observers.js +42 -0
- package/lib/quoxon/onboarding/copy.js +263 -0
- package/lib/quoxon/onboarding/credential.js +108 -0
- package/lib/quoxon/onboarding/detect.js +22 -0
- package/lib/quoxon/onboarding/dockerOffer.js +45 -0
- package/lib/quoxon/onboarding/failureCause.js +33 -0
- package/lib/quoxon/onboarding/finish.js +134 -0
- package/lib/quoxon/onboarding/index.js +94 -0
- package/lib/quoxon/onboarding/installRunner.js +284 -0
- package/lib/quoxon/onboarding/intent.js +53 -0
- package/lib/quoxon/onboarding/journey.js +73 -0
- package/lib/quoxon/onboarding/preflight.js +156 -0
- package/lib/quoxon/onboarding/probe.js +65 -0
- package/lib/quoxon/onboarding/runner.js +58 -0
- package/lib/quoxon/onboarding/view.js +682 -0
- package/lib/quoxon/orgLabel.js +10 -0
- package/lib/quoxon/orgSwitch.js +33 -0
- package/lib/quoxon/ownBroadcast.js +22 -0
- package/lib/quoxon/palette.js +43 -0
- package/lib/quoxon/print.js +98 -0
- package/lib/quoxon/profileSwitch.js +53 -0
- package/lib/quoxon/promptHistory.js +41 -0
- package/lib/quoxon/providers.js +48 -0
- package/lib/quoxon/qart.js +348 -0
- package/lib/quoxon/qdragon.js +410 -0
- package/lib/quoxon/qdragonFly.js +61 -0
- package/lib/quoxon/qdragonScenes.js +282 -0
- package/lib/quoxon/qeyes.js +213 -0
- package/lib/quoxon/qglyph.js +143 -0
- package/lib/quoxon/qhello.js +58 -0
- package/lib/quoxon/qmotion.js +132 -0
- package/lib/quoxon/render.js +1167 -0
- package/lib/quoxon/resend.js +72 -0
- package/lib/quoxon/roster.js +307 -0
- package/lib/quoxon/route.js +39 -0
- package/lib/quoxon/rows.js +711 -0
- package/lib/quoxon/rowsStore.js +80 -0
- package/lib/quoxon/rules.js +130 -0
- package/lib/quoxon/screenContext.js +150 -0
- package/lib/quoxon/screenFrames.js +254 -0
- package/lib/quoxon/session.js +238 -0
- package/lib/quoxon/sessionDead.js +17 -0
- package/lib/quoxon/signin.js +125 -0
- package/lib/quoxon/skills.js +30 -0
- package/lib/quoxon/slash/agents.js +112 -0
- package/lib/quoxon/slash/argSources.js +65 -0
- package/lib/quoxon/slash/args.js +65 -0
- package/lib/quoxon/slash/automate.js +89 -0
- package/lib/quoxon/slash/broadcast.js +140 -0
- package/lib/quoxon/slash/broadcastRun.js +108 -0
- package/lib/quoxon/slash/card.js +30 -0
- package/lib/quoxon/slash/challenge.js +114 -0
- package/lib/quoxon/slash/cliCommand.js +53 -0
- package/lib/quoxon/slash/cliLeaves.json +948 -0
- package/lib/quoxon/slash/compact.js +90 -0
- package/lib/quoxon/slash/confirm.js +30 -0
- package/lib/quoxon/slash/crystallize.js +69 -0
- package/lib/quoxon/slash/dashboard.js +136 -0
- package/lib/quoxon/slash/draft.js +54 -0
- package/lib/quoxon/slash/hatWalk.js +206 -0
- package/lib/quoxon/slash/inverses.js +77 -0
- package/lib/quoxon/slash/killer.js +24 -0
- package/lib/quoxon/slash/killerApi.js +16 -0
- package/lib/quoxon/slash/ledger.js +88 -0
- package/lib/quoxon/slash/listView.js +30 -0
- package/lib/quoxon/slash/modelCmd.js +261 -0
- package/lib/quoxon/slash/palette.js +118 -0
- package/lib/quoxon/slash/paletteController.js +169 -0
- package/lib/quoxon/slash/panels.js +116 -0
- package/lib/quoxon/slash/picker.js +56 -0
- package/lib/quoxon/slash/restart.js +202 -0
- package/lib/quoxon/slash/resume.js +59 -0
- package/lib/quoxon/slash/rowCmd.js +157 -0
- package/lib/quoxon/slash/rowWalk.js +175 -0
- package/lib/quoxon/slash/settings.js +60 -0
- package/lib/quoxon/slash/spawn.js +177 -0
- package/lib/quoxon/slash/stepUp.js +274 -0
- package/lib/quoxon/slash/stepUpCard.js +60 -0
- package/lib/quoxon/slash/stepUpCmds.js +78 -0
- package/lib/quoxon/slash/undoApi.js +38 -0
- package/lib/quoxon/slash/undoCmd.js +49 -0
- package/lib/quoxon/slash/undoWish.js +15 -0
- package/lib/quoxon/slash/watch.js +164 -0
- package/lib/quoxon/slash/wish.js +23 -0
- package/lib/quoxon/slash/wishCmd.js +32 -0
- package/lib/quoxon/slotChat.js +300 -0
- package/lib/quoxon/slotFormat.js +195 -0
- package/lib/quoxon/slotRun.js +131 -0
- package/lib/quoxon/sound/index.js +186 -0
- package/lib/quoxon/sound/mapping.js +120 -0
- package/lib/quoxon/sound/output.js +52 -0
- package/lib/quoxon/sound/synth.js +122 -0
- package/lib/quoxon/stray.js +22 -0
- package/lib/quoxon/suggestCommand.js +59 -0
- package/lib/quoxon/term.js +141 -0
- package/lib/quoxon/textBuffer.js +416 -0
- package/lib/quoxon/theme.js +286 -0
- package/lib/quoxon/tips.js +433 -0
- package/lib/quoxon/toolError.js +41 -0
- package/lib/quoxon/transcript.js +188 -0
- package/lib/quoxon/web/qface.js +89 -0
- package/lib/quoxon/welcome.js +52 -0
- package/lib/quoxon/whatsnew.js +136 -0
- package/lib/quoxon/whatsnew.jsonl +89 -0
- package/lib/quoxon/windowOrg.js +113 -0
- package/lib/server/diag.js +129 -0
- package/lib/server/doctor.js +71 -0
- package/lib/server/install.js +149 -0
- package/lib/server/pluginEnable.js +161 -0
- package/lib/server/skew.js +56 -0
- package/lib/server/snapshot.js +131 -0
- package/lib/server/status.js +128 -0
- package/lib/server/sys.js +65 -0
- package/lib/server/uninstall.js +63 -0
- package/lib/server/update.js +234 -0
- package/lib/toolOutputShape.js +315 -0
- package/lib/tui/app.jsx +289 -0
- package/lib/tui/components/Breadcrumb.jsx +42 -0
- package/lib/tui/components/ChatInput.jsx +68 -0
- package/lib/tui/components/Confirm.jsx +32 -0
- package/lib/tui/components/DataTable.jsx +270 -0
- package/lib/tui/components/DetailPanel.jsx +241 -0
- package/lib/tui/components/HelpOverlay.jsx +67 -0
- package/lib/tui/components/Layout.jsx +129 -0
- package/lib/tui/components/Palette.jsx +141 -0
- package/lib/tui/components/SearchInput.jsx +125 -0
- package/lib/tui/components/Sparkline.jsx +55 -0
- package/lib/tui/components/StatusBar.jsx +133 -0
- package/lib/tui/components/Toast.jsx +52 -0
- package/lib/tui/hooks/useApi.js +44 -0
- package/lib/tui/hooks/useHealth.js +90 -0
- package/lib/tui/hooks/usePolledApi.js +86 -0
- package/lib/tui/hooks/useTerminalSize.js +46 -0
- package/lib/tui/index.js +56 -0
- package/lib/tui/intro/Intro.jsx +332 -0
- package/lib/tui/jsx-loader.js +32 -0
- package/lib/tui/keys.js +87 -0
- package/lib/tui/registry.js +49 -0
- package/lib/tui/theme.js +103 -0
- package/lib/tui/views/AdminView.jsx +398 -0
- package/lib/tui/views/AgentView.jsx +204 -0
- package/lib/tui/views/BackupView.jsx +225 -0
- package/lib/tui/views/BrainView.jsx +223 -0
- package/lib/tui/views/ChatView.jsx +468 -0
- package/lib/tui/views/FilesView.jsx +218 -0
- package/lib/tui/views/FleetView.jsx +234 -0
- package/lib/tui/views/GovernanceView.jsx +453 -0
- package/lib/tui/views/HealthView.jsx +216 -0
- package/lib/tui/views/HyperionDeck.jsx +79 -0
- package/lib/tui/views/InboxView.jsx +228 -0
- package/lib/tui/views/LucidDeck.jsx +719 -0
- package/lib/tui/views/MainMenu.jsx +123 -0
- package/lib/tui/views/MemoryView.jsx +377 -0
- package/lib/tui/views/ObjectivesView.jsx +230 -0
- package/lib/tui/views/OrgView.jsx +229 -0
- package/lib/tui/views/ToolView.jsx +221 -0
- package/lib/tui/views/VaultView.jsx +422 -0
- package/lib/tui/views/WorkflowView.jsx +329 -0
- package/package.json +75 -4
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `quox lucid --sitrep`: a one-shot, width-aware ANSI snapshot of the LUCID
|
|
3
|
+
* situation, built to read well in a terminal and when pasted into a chat.
|
|
4
|
+
* Pure: renderSitrep(situation, opts) -> string. Colour is explicit (opts.color).
|
|
5
|
+
*/
|
|
6
|
+
import {
|
|
7
|
+
GLYPH, STATE_HEX, URGENCY, PALETTE, wrap, clip, padEnd, vlen, ageOf, meter,
|
|
8
|
+
clockLondon, firstMeasure, whenText, changedWords, blindSpots,
|
|
9
|
+
} from './fmt.js';
|
|
10
|
+
|
|
11
|
+
const R = '\x1b[0m';
|
|
12
|
+
|
|
13
|
+
export function makePainter(color) {
|
|
14
|
+
const rgb = (hex) => {
|
|
15
|
+
const n = parseInt(hex.slice(1), 16);
|
|
16
|
+
return `\x1b[38;2;${(n >> 16) & 255};${(n >> 8) & 255};${n & 255}m`;
|
|
17
|
+
};
|
|
18
|
+
const wrapSeq = (seq, s) => (color && s !== '' ? `${seq}${s}${R}` : s);
|
|
19
|
+
return {
|
|
20
|
+
color,
|
|
21
|
+
fg: (hex, s) => wrapSeq(rgb(hex), s),
|
|
22
|
+
bold: (s) => wrapSeq('\x1b[1m', s),
|
|
23
|
+
dim: (s) => wrapSeq(rgb(PALETTE.dim), s),
|
|
24
|
+
muted: (s) => wrapSeq(rgb(PALETTE.muted), s),
|
|
25
|
+
boldFg: (hex, s) => wrapSeq(`\x1b[1m${rgb(hex)}`, s),
|
|
26
|
+
pill: (hex, s) => (color ? `\x1b[48;2;${parseInt(hex.slice(1, 3), 16)};${parseInt(hex.slice(3, 5), 16)};${parseInt(hex.slice(5, 7), 16)}m\x1b[38;2;17;24;39m\x1b[1m[${s}]${R}` : `[${s}]`),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function tile(area, w, p, now) {
|
|
31
|
+
const inner = w - 4;
|
|
32
|
+
const hex = STATE_HEX[area.state] || STATE_HEX.unknown;
|
|
33
|
+
const glyph = GLYPH[area.state] || GLYPH.unknown;
|
|
34
|
+
const label = clip(area.label || area.area, inner - 3);
|
|
35
|
+
const topPlain = `─ ${glyph} ${label} `;
|
|
36
|
+
const top = p.fg(PALETTE.dim, '╭') + p.fg(PALETTE.dim, '─ ') + p.boldFg(hex, glyph) + ' ' + p.bold(label) + ' '
|
|
37
|
+
+ p.fg(PALETTE.dim, '─'.repeat(Math.max(0, w - 2 - [...topPlain].length)) + '╮');
|
|
38
|
+
let body = wrap(area.L0 || 'No signal yet.', inner);
|
|
39
|
+
if (body.length > 3) body = [...body.slice(0, 2), clip(body[2] + ' ' + body.slice(3).join(' '), inner)];
|
|
40
|
+
const rows = body.map((l) => p.fg(area.state === 'ok' ? PALETTE.muted : PALETTE.text, l));
|
|
41
|
+
const last = area.last;
|
|
42
|
+
if (last) {
|
|
43
|
+
const tail = `${last.outcome ? ` (${last.outcome})` : ''} ${ageOf(last.ts, now)} ago`;
|
|
44
|
+
rows.push(p.dim(`last: ${clip(last.L0, Math.max(6, inner - 6 - [...tail].length))}${tail}`));
|
|
45
|
+
} else rows.push(p.dim('nothing yet'));
|
|
46
|
+
const v = p.fg(PALETTE.dim, '│');
|
|
47
|
+
const mid = rows.map((r) => `${v} ${padEnd(r, inner)} ${v}`);
|
|
48
|
+
const bot = p.fg(PALETTE.dim, '╰' + '─'.repeat(w - 2) + '╯');
|
|
49
|
+
return [top, ...mid, bot];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function grid(tiles, width, p, now) {
|
|
53
|
+
const gap = 1;
|
|
54
|
+
const tw = Math.floor((width - gap) / 2);
|
|
55
|
+
const out = [];
|
|
56
|
+
for (let i = 0; i < tiles.length; i += 2) {
|
|
57
|
+
const a = tile(tiles[i], tw, p, now);
|
|
58
|
+
const b = tiles[i + 1] ? tile(tiles[i + 1], tw, p, now) : [];
|
|
59
|
+
const h = Math.max(a.length, b.length);
|
|
60
|
+
const fill = (t, idx, wd) => {
|
|
61
|
+
if (t[idx] !== undefined) return t[idx];
|
|
62
|
+
// pad short tile with an empty bordered row before its bottom edge
|
|
63
|
+
return ' '.repeat(wd);
|
|
64
|
+
};
|
|
65
|
+
// equalise heights by inserting blank rows before the bottom border
|
|
66
|
+
const eq = (t) => {
|
|
67
|
+
if (!t.length) return t;
|
|
68
|
+
const bottom = t[t.length - 1];
|
|
69
|
+
const row = `${p.fg(PALETTE.dim, '│')}${' '.repeat(tw - 2)}${p.fg(PALETTE.dim, '│')}`;
|
|
70
|
+
const body = t.slice(0, -1);
|
|
71
|
+
while (body.length < h - 1) body.push(row);
|
|
72
|
+
return [...body, bottom];
|
|
73
|
+
};
|
|
74
|
+
const ea = eq(a), eb = eq(b);
|
|
75
|
+
for (let k = 0; k < h; k++) out.push(`${fill(ea, k, tw)}${' '.repeat(gap)}${eb.length ? fill(eb, k, tw) : ''}`.trimEnd());
|
|
76
|
+
}
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function section(title, width, p, extra = '') {
|
|
81
|
+
const t = ` ${title}${extra ? ' ' + extra : ''} `;
|
|
82
|
+
return p.boldFg(PALETTE.accent, title) + (extra ? ' ' + p.dim(extra) : '') + ' ' + p.fg(PALETTE.dim, '─'.repeat(Math.max(2, width - vlen(t))));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function renderSitrep(data, opts = {}) {
|
|
86
|
+
const width = Math.max(60, Math.min(opts.width || 100, 140));
|
|
87
|
+
const now = opts.now ?? Date.now();
|
|
88
|
+
const p = makePainter(opts.color !== false);
|
|
89
|
+
const sit = (data && data.situation) || data || {};
|
|
90
|
+
const cs = sit.cannot_see || {};
|
|
91
|
+
const cov = cs.coverage || { live: 0, expected: 0 };
|
|
92
|
+
const lines = [];
|
|
93
|
+
|
|
94
|
+
const sep = p.dim('│');
|
|
95
|
+
const left = `${p.boldFg(PALETTE.brand, '◉ LUCID')} ${sep} ${p.bold('sitrep')} ${sep} ${clockLondon(now)} ${p.dim('·')} `
|
|
96
|
+
+ `${p.fg(cov.live < cov.expected ? STATE_HEX.attention : STATE_HEX.ok, `${cov.live}/${cov.expected}`)} sources`;
|
|
97
|
+
lines.push(left);
|
|
98
|
+
lines.push(p.fg(PALETTE.dim, '━'.repeat(width)));
|
|
99
|
+
|
|
100
|
+
lines.push('');
|
|
101
|
+
for (const l of wrap(sit.L0 || 'No briefing available.', width)) lines.push(p.fg(PALETTE.text, l));
|
|
102
|
+
lines.push('');
|
|
103
|
+
|
|
104
|
+
const areas = sit.areas || [];
|
|
105
|
+
if (areas.length) {
|
|
106
|
+
lines.push(...grid(areas, width, p, now));
|
|
107
|
+
lines.push('');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const needs = sit.needs_you || [];
|
|
111
|
+
lines.push(section('NEEDS YOU', width, p, needs.length ? `${needs.length}` : ''));
|
|
112
|
+
if (!needs.length) {
|
|
113
|
+
lines.push(p.fg(STATE_HEX.ok, ' Nothing needs you right now.') + (cs.silent && cs.silent.length ? p.dim(' (but see what I can\'t see)') : ''));
|
|
114
|
+
}
|
|
115
|
+
const iw = width - 5;
|
|
116
|
+
needs.forEach((it, i) => {
|
|
117
|
+
const u = URGENCY[it.urgency] || URGENCY.whenever;
|
|
118
|
+
const num = String(i + 1).padStart(2);
|
|
119
|
+
lines.push('');
|
|
120
|
+
lines.push(`${p.dim(num + '.')} ${p.pill(u.hex, u.label)} ${p.bold(clip(it.L0 || '', width - 8 - u.label.length))}`);
|
|
121
|
+
const a = it.L1 || {};
|
|
122
|
+
const field = (k, v) => {
|
|
123
|
+
if (!v) return;
|
|
124
|
+
const wl = wrap(v, iw - 6);
|
|
125
|
+
wl.forEach((l, j) => lines.push(` ${j === 0 ? p.dim(k.padEnd(5)) : ' '}${p.fg(PALETTE.muted, l)}`));
|
|
126
|
+
};
|
|
127
|
+
field('Who', a.who); field('What', a.what); field('Why', a.why); field('When', whenText(a.when, now));
|
|
128
|
+
const m = firstMeasure(it);
|
|
129
|
+
if (m) {
|
|
130
|
+
const say = m.say || m.label;
|
|
131
|
+
lines.push(` ${p.boldFg(PALETTE.brand, '→ do:')} ${p.fg(PALETTE.text, clip(say, iw - 8))}`);
|
|
132
|
+
const cmd = m.command || m.url;
|
|
133
|
+
if (cmd) lines.push(` ${p.fg(PALETTE.code, clip(cmd, iw - 5))}`);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
lines.push('');
|
|
137
|
+
|
|
138
|
+
const changed = sit.changed || [];
|
|
139
|
+
lines.push(section('SINCE YOU LOOKED', width, p, changed.length ? `${changed.length}` : ''));
|
|
140
|
+
if (!changed.length) lines.push(p.dim(' Nothing has changed.'));
|
|
141
|
+
for (const c of changed.slice(0, 8)) {
|
|
142
|
+
const o = changedWords(c);
|
|
143
|
+
const tail = `${o ? o + ' ' : ''}${ageOf(c.ts, now)} ago`;
|
|
144
|
+
lines.push(` ${p.dim('•')} ${clip(c.L0 || '', width - 6 - tail.length)} ${p.dim(tail)}`);
|
|
145
|
+
}
|
|
146
|
+
if (changed.length > 8) lines.push(p.dim(` … and ${changed.length - 8} more`));
|
|
147
|
+
lines.push('');
|
|
148
|
+
|
|
149
|
+
const da = sit.doesnt_add_up || [];
|
|
150
|
+
if (da.length) {
|
|
151
|
+
lines.push(section("DOESN'T ADD UP", width, p, `${da.length}`));
|
|
152
|
+
for (const x of da.slice(0, 5)) {
|
|
153
|
+
lines.push(` ${p.dim('•')} ${p.bold(clip(x.L0 || '', width - 6))}${x.urgent ? ' ' + p.pill(URGENCY.today.hex, 'TODAY') : ''}`);
|
|
154
|
+
for (const [k, v] of [['Claimed', x.claimed], ['Observed', x.observed]]) {
|
|
155
|
+
if (!v) continue;
|
|
156
|
+
wrap(v, width - 16).forEach((l, j) => lines.push(` ${j === 0 ? p.dim(k.padEnd(9)) : ' '.repeat(9)}${p.fg(PALETTE.muted, l)}`));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (da.length > 5) lines.push(p.dim(` … and ${da.length - 5} more (quox lucid blind)`));
|
|
160
|
+
lines.push('');
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
lines.push(section("WHAT I CAN'T SEE", width, p, `${meter(cov.live, cov.expected)} ${cov.live}/${cov.expected}`));
|
|
164
|
+
const spots = blindSpots(cs);
|
|
165
|
+
if (!spots.length && cov.live >= cov.expected) lines.push(p.dim(' Every expected source is speaking.'));
|
|
166
|
+
else if (!spots.length) lines.push(p.fg(STATE_HEX.attention, ` ${cov.expected - cov.live} expected source(s) are not reporting.`));
|
|
167
|
+
for (const s of spots) {
|
|
168
|
+
for (const [j, l] of wrap(s.text, width - 4).entries()) {
|
|
169
|
+
lines.push(` ${p.fg(s.k === 'failing' ? STATE_HEX.blind : STATE_HEX.attention, l)}`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return lines.join('\n') + '\n';
|
|
173
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin loader for QuoxCLI
|
|
3
|
+
*
|
|
4
|
+
* Discovers and loads plugins from:
|
|
5
|
+
* 1. ~/.quox/plugins/ (user plugins)
|
|
6
|
+
* 2. QUOX_PLUGIN_DIR env var (custom path)
|
|
7
|
+
*
|
|
8
|
+
* Plugin format: each plugin is a directory with an index.js that exports:
|
|
9
|
+
* { name, version, description, register(program, context) }
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { existsSync, readdirSync, statSync } from 'node:fs';
|
|
13
|
+
import { join } from 'node:path';
|
|
14
|
+
import { homedir } from 'node:os';
|
|
15
|
+
import { pathToFileURL } from 'node:url';
|
|
16
|
+
|
|
17
|
+
function getPluginDirs() {
|
|
18
|
+
const dirs = [join(homedir(), '.quox', 'plugins')];
|
|
19
|
+
if (process.env.QUOX_PLUGIN_DIR) {
|
|
20
|
+
dirs.push(process.env.QUOX_PLUGIN_DIR);
|
|
21
|
+
}
|
|
22
|
+
return dirs;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function discoverPlugins() {
|
|
26
|
+
const plugins = [];
|
|
27
|
+
|
|
28
|
+
for (const dir of getPluginDirs()) {
|
|
29
|
+
if (!existsSync(dir)) continue;
|
|
30
|
+
|
|
31
|
+
const entries = readdirSync(dir);
|
|
32
|
+
for (const entry of entries) {
|
|
33
|
+
const pluginPath = join(dir, entry);
|
|
34
|
+
if (!statSync(pluginPath).isDirectory()) continue;
|
|
35
|
+
|
|
36
|
+
const indexPath = join(pluginPath, 'index.js');
|
|
37
|
+
if (!existsSync(indexPath)) continue;
|
|
38
|
+
|
|
39
|
+
plugins.push({
|
|
40
|
+
name: entry,
|
|
41
|
+
path: pluginPath,
|
|
42
|
+
indexPath,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return plugins;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export async function loadPlugin(pluginInfo) {
|
|
51
|
+
try {
|
|
52
|
+
const moduleUrl = pathToFileURL(pluginInfo.indexPath).href;
|
|
53
|
+
const mod = await import(moduleUrl);
|
|
54
|
+
|
|
55
|
+
if (typeof mod.register !== 'function') {
|
|
56
|
+
throw new Error(`Plugin "${pluginInfo.name}" does not export a register() function`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
name: mod.name || pluginInfo.name,
|
|
61
|
+
version: mod.version || '0.0.0',
|
|
62
|
+
description: mod.description || '',
|
|
63
|
+
register: mod.register,
|
|
64
|
+
};
|
|
65
|
+
} catch (err) {
|
|
66
|
+
return {
|
|
67
|
+
name: pluginInfo.name,
|
|
68
|
+
error: err.message,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export async function loadAllPlugins(program, context) {
|
|
74
|
+
const discovered = await discoverPlugins();
|
|
75
|
+
const loaded = [];
|
|
76
|
+
const errors = [];
|
|
77
|
+
|
|
78
|
+
for (const pluginInfo of discovered) {
|
|
79
|
+
const plugin = await loadPlugin(pluginInfo);
|
|
80
|
+
if (plugin.error) {
|
|
81
|
+
errors.push({ name: plugin.name, error: plugin.error });
|
|
82
|
+
} else {
|
|
83
|
+
try {
|
|
84
|
+
plugin.register(program, context);
|
|
85
|
+
loaded.push({ name: plugin.name, version: plugin.version, description: plugin.description });
|
|
86
|
+
} catch (err) {
|
|
87
|
+
errors.push({ name: plugin.name, error: err.message });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return { loaded, errors };
|
|
93
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What is actually happening right now, as one honest word (CLI-QUOX indicator).
|
|
3
|
+
* Pure: the reducer feeds every real event through nextActivity and keeps the result on the turn.
|
|
4
|
+
* Rules: a word exists only because an event said so; between events the last true word stays (never
|
|
5
|
+
* invented, never rotated); unknown tools fall back to "Working" plus the tool name as detail.
|
|
6
|
+
* Words are capitalised present participles; the indicator appends the ellipsis.
|
|
7
|
+
*
|
|
8
|
+
* State: { word, detail, tone: 'work' | 'wait', flash: ms | null, since: ms }
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const clipD = (s, n = 40) => { const t = String(s ?? '').replace(/\s+/g, ' ').trim(); return t.length > n ? t.slice(0, n - 1) + '…' : t; };
|
|
12
|
+
|
|
13
|
+
// Ordered: first match wins, so specific families come before generic ones. [regex, word, detail?]
|
|
14
|
+
// Tool names are the real registry names (memory_search, bastion_ssh, quoxplan_set_status, ...).
|
|
15
|
+
const TOOL_TABLE = [
|
|
16
|
+
[/^(memory_(save|update)|brain_save|brain_garden_apply)/, 'Remembering'],
|
|
17
|
+
[/^memory_forget/, 'Forgetting'],
|
|
18
|
+
[/^(memory_|brain_|search_wisdom)/, 'Recalling'],
|
|
19
|
+
[/^(fleet_|bastion_).*(exec|ssh|run|restart|command)|^(bastion_ssh|fleet_exec)/, 'Running', 'host'],
|
|
20
|
+
[/^(fleet_|bastion_)/, 'Looking up'],
|
|
21
|
+
[/^(email_send|contacts_send)/, 'Sending'],
|
|
22
|
+
[/^contacts_dial/, 'Dialling'],
|
|
23
|
+
[/^(email_draft|inbox_propose|email_reply)/, 'Drafting'],
|
|
24
|
+
[/^(email_|inbox_)/, 'Checking mail'],
|
|
25
|
+
[/^(qlarity_|browser_(screenshot|lighthouse|pdf|find_element|list_tabs|monitor))/, 'Inspecting'],
|
|
26
|
+
[/^(browser_|http_|fetch_|web_)/, 'Fetching'],
|
|
27
|
+
[/^(seo_|quoxseo)/, 'Analysing'],
|
|
28
|
+
[/^(delegate|agent_handoff|agent_delegate|ask_agent|agent_call)|handoff/, 'Delegating', 'target'],
|
|
29
|
+
[/^(quoxflow_|workflow_)/, 'Orchestrating'],
|
|
30
|
+
[/^(quoxplan_|plan_)/, 'Planning'],
|
|
31
|
+
[/^(ward_|volt_|receipt|verify)/, 'Verifying'],
|
|
32
|
+
[/^approval/, 'Checking approvals'],
|
|
33
|
+
[/^calendar_/, 'Scheduling'],
|
|
34
|
+
[/^(search_|query_)|_search$|_find$/, 'Searching'],
|
|
35
|
+
[/(^|_)(write|edit|create)_(file|doc)|^file_(write|save)|^plan_doc/, 'Writing'],
|
|
36
|
+
[/(^|_)read(_|$)|^file_(read|get|open)/, 'Reading'],
|
|
37
|
+
[/(^|_)(list|get|status)$|^contacts_/, 'Looking up'],
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
/** QUOXON-FW3: "Delegating <Agent> · <task gist>" instead of an anonymous delegate_to_agent. */
|
|
41
|
+
function delegateTarget(ev) {
|
|
42
|
+
const id = ev.agent_id || (String(ev.summary || '').match(/\bagent_id=(\S+)/) || [])[1] || '';
|
|
43
|
+
const name = ev.agent_name || id;
|
|
44
|
+
return { ...ev, target: [name, ev.task_gist].filter(Boolean).join(' \u00b7 ') };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** { word, detail } for a tool call. Unknown tools are "Working" with the tool name, never a guess. */
|
|
48
|
+
export function toolWord(tool, ev = {}) {
|
|
49
|
+
const name = String(tool || '').toLowerCase();
|
|
50
|
+
for (const [re, word, d] of TOOL_TABLE) {
|
|
51
|
+
if (re.test(name)) return { word, detail: d ? (clipD(ev[d] ?? ev.target ?? ev.host) || null) : null };
|
|
52
|
+
}
|
|
53
|
+
return { word: 'Working', detail: name || null };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const mk = (word, detail = null, now = 0, tone = 'work', flash = null, tool = null) => ({ word, detail: detail ? clipD(detail) : null, tone, flash, since: now, ...(tool ? { tool: clipD(tool, 40) } : {}) });
|
|
57
|
+
export const initialActivity = (now = 0) => mk('Sending', null, now); // the request was dispatched: true from turn.begin
|
|
58
|
+
|
|
59
|
+
/** Trace lines from the governance chain. Labels as the server sends them. */
|
|
60
|
+
function traceWord(ev) {
|
|
61
|
+
const label = String(ev.label || '').toLowerCase();
|
|
62
|
+
if (ev.protocol === 'aee' && /envelope opened/.test(label)) return ['Recording', 'envelope'];
|
|
63
|
+
if (ev.protocol === 'aocl') {
|
|
64
|
+
if (/\bl1\b|identity/.test(label)) return ['Verifying', 'L1 identity'];
|
|
65
|
+
if (/\bl3\b|policy/.test(label)) return ['Governing', 'L3 policy'];
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
if (ev.protocol === 'ward' && /witness/.test(label)) return ['Witnessing', null];
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Next activity for a stream event. ctx = { hasText } (has any answer text arrived yet).
|
|
74
|
+
* Returns prev unchanged for events that say nothing new.
|
|
75
|
+
*/
|
|
76
|
+
export function nextActivity(prev, ev, now = 0, ctx = {}) {
|
|
77
|
+
const p = prev || initialActivity(now);
|
|
78
|
+
switch (ev?.type) {
|
|
79
|
+
case 'thinking': {
|
|
80
|
+
const stage = String(ev.stage || ''), msg = String(ev.message || '').replace(/[.…\s]+$/u, '');
|
|
81
|
+
if (stage === 'routing') return mk('Routing', (msg.match(/\bto\s+(.+)$/i) || [])[1] || null, now);
|
|
82
|
+
if (stage === 'routing_detail') return mk('Routing', msg || p.detail, now);
|
|
83
|
+
if (stage === 'processing') return mk('Reading', null, now);
|
|
84
|
+
if (stage === 'api_call') {
|
|
85
|
+
if (ctx.hasText) return p;
|
|
86
|
+
return mk('Thinking', (msg.match(/Calling (.+?) API/i) || [])[1] || null, now);
|
|
87
|
+
}
|
|
88
|
+
if (stage.includes('tool') && msg) { const t = toolWord(msg); return mk(t.word, t.detail, now); }
|
|
89
|
+
return p;
|
|
90
|
+
}
|
|
91
|
+
case 'trace': { const t = traceWord(ev); return t ? mk(t[0], t[1], now) : p; }
|
|
92
|
+
case 'tool.started': { const t = toolWord(ev.tool, ev.tool === 'delegate_to_agent' ? delegateTarget(ev) : ev); return mk(t.word, t.detail, now, 'work', null, ev.tool || null); }
|
|
93
|
+
case 'delegation.progress': { // QUOXON 2026-10-17: a specialist's real tool call, forwarded by the server
|
|
94
|
+
if (!ev.tool) return p;
|
|
95
|
+
const who = ev.agent_name || ev.agent_id || 'specialist';
|
|
96
|
+
return mk('Delegating', `${who} \u00b7 ${ev.tool}${ev.detail ? ` (${ev.detail})` : ''}`, now, 'work', null, ev.tool);
|
|
97
|
+
}
|
|
98
|
+
case 'tool.finished': return ev.status === 'failed' ? { ...p, flash: now } : p; // keep the word, flash the Q only
|
|
99
|
+
case 'approval.requested': return mk('Waiting', 'for your approval', now, 'wait');
|
|
100
|
+
case 'approval.resolved': return mk('Resuming', null, now);
|
|
101
|
+
case 'steer.accepted': return mk('Adjusting', null, now);
|
|
102
|
+
case 'text.delta': case 'chunk': return p.word === 'Writing' && p.tone === 'work' ? p : mk('Writing', null, now);
|
|
103
|
+
case 'retry': case 'reconnecting': return mk('Reconnecting', null, now);
|
|
104
|
+
case 'resumed': return mk('Resuming', 'reattached', now);
|
|
105
|
+
case 'done': return mk('Confirming', 'waiting for the server', now);
|
|
106
|
+
case 'error': return { ...p, flash: now };
|
|
107
|
+
default: return p;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Client-side actions that are also true events (the human pressed Esc). */
|
|
112
|
+
export function actionActivity(prev, action, now = 0) {
|
|
113
|
+
if (action?.type === 'turn.begin') return initialActivity(action.now ?? now);
|
|
114
|
+
if (action?.type === 'interrupt.requested') return mk('Stopping', null, action.now ?? now);
|
|
115
|
+
return prev;
|
|
116
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QUOXON-AOCL: one compact AOCL line per turn, and the full per-layer table on demand (/aocl).
|
|
3
|
+
*
|
|
4
|
+
* The server sends ONE `aocl.summary` per streamed turn ({ layers:[{id,outcome,ms,reason}],
|
|
5
|
+
* total, accounted, passed, bypassed, rejected, rejected_at, ms, verdict? }) and an
|
|
6
|
+
* `aocl.verdict` when L8 flags text that was already on screen. Older servers send only
|
|
7
|
+
* per-layer `trace` rows (protocol aocl, label "L1 identity complete"); those are folded
|
|
8
|
+
* into the same line so nothing is lost, and the line says how many layers were reported.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export const LAYER_NAMES = {
|
|
12
|
+
L0: 'ingress', L1: 'identity', L2: 'router', L3: 'policy', L4: 'planner', L5: 'context',
|
|
13
|
+
L6: 'shape', L7: 'delegate', L8: 'verify', L9: 'assemble', L10: 'audit'
|
|
14
|
+
};
|
|
15
|
+
const ORDER = Object.keys(LAYER_NAMES);
|
|
16
|
+
const OUTCOME_WORD = { complete: 'passed', bypass: 'bypassed', reject: 'rejected', not_run: 'not run' };
|
|
17
|
+
const OUTCOME_GLYPH = { complete: '✔', bypass: '○', reject: '✖', not_run: '?' };
|
|
18
|
+
|
|
19
|
+
/** A per-layer AOCL trace row (folded into the one-line summary instead of a row per layer). */
|
|
20
|
+
export const isLayerTrace = (ev) => ev?.protocol === 'aocl' && /^L(?:10|[0-9])\b/.test(String(ev.label || ''));
|
|
21
|
+
|
|
22
|
+
const fmtMs = (ms) => {
|
|
23
|
+
const n = Number(ms);
|
|
24
|
+
if (!Number.isFinite(n)) return '';
|
|
25
|
+
return n < 10 ? `${Math.round(n * 10) / 10} ms` : n < 1000 ? `${Math.round(n)} ms` : `${(n / 1000).toFixed(1)} s`;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/** Normalise a server summary (tolerant of missing fields). */
|
|
29
|
+
export function normaliseSummary(ev) {
|
|
30
|
+
const layers = Array.isArray(ev?.layers) ? ev.layers.filter(l => l && l.id).map(l => ({ id: String(l.id), outcome: String(l.outcome || 'not_run'), ms: Number(l.ms) || 0, ...(l.reason ? { reason: String(l.reason) } : {}) })) : [];
|
|
31
|
+
const count = (o) => layers.filter(l => l.outcome === o).length;
|
|
32
|
+
const rejected = layers.filter(l => l.outcome === 'reject');
|
|
33
|
+
return {
|
|
34
|
+
layers,
|
|
35
|
+
total: Number(ev?.total) || 11,
|
|
36
|
+
accounted: Number.isFinite(Number(ev?.accounted)) ? Number(ev.accounted) : layers.filter(l => l.outcome !== 'not_run').length,
|
|
37
|
+
passed: Number.isFinite(Number(ev?.passed)) ? Number(ev.passed) : count('complete'),
|
|
38
|
+
bypassed: Number.isFinite(Number(ev?.bypassed)) ? Number(ev.bypassed) : count('bypass'),
|
|
39
|
+
rejected: Number.isFinite(Number(ev?.rejected)) ? Number(ev.rejected) : rejected.length,
|
|
40
|
+
rejectedAt: ev?.rejected_at || (rejected[0] && rejected[0].id) || null,
|
|
41
|
+
ms: Number.isFinite(Number(ev?.ms)) ? Number(ev.ms) : null,
|
|
42
|
+
verdict: ev?.verdict || null,
|
|
43
|
+
legacy: Boolean(ev?.legacy)
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Build a summary from legacy per-layer trace rows (a server without aocl.summary). */
|
|
48
|
+
export function summaryFromTraces(traces) {
|
|
49
|
+
const layers = [];
|
|
50
|
+
for (const t of traces || []) {
|
|
51
|
+
const m = String(t.label || '').match(/^(L(?:10|[0-9]))\b.*?\b(complete|bypass|reject)\b/);
|
|
52
|
+
if (!m || layers.some(l => l.id === m[1])) continue;
|
|
53
|
+
const ms = String(t.detail || '').match(/(\d+(?:\.\d+)?)\s*ms/);
|
|
54
|
+
layers.push({ id: m[1], outcome: m[2], ms: ms ? Number(ms[1]) : 0 });
|
|
55
|
+
}
|
|
56
|
+
layers.sort((a, b) => ORDER.indexOf(a.id) - ORDER.indexOf(b.id));
|
|
57
|
+
const ms = layers.reduce((n, l) => n + l.ms, 0);
|
|
58
|
+
return normaliseSummary({ layers, total: 11, accounted: layers.length, ms, legacy: true });
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* The one line: "AOCL 11/11 ✔ · 9 passed · 2 bypassed · 34 ms" (the caller draws the ▤ icon).
|
|
63
|
+
* -> { segs: [{ t, tone }] } where tone is 'ok' | 'fail' | 'warn' | 'text'.
|
|
64
|
+
*/
|
|
65
|
+
export function aoclLineSegs(sum) {
|
|
66
|
+
const s = sum || normaliseSummary({});
|
|
67
|
+
const segs = [{ t: `${s.accounted}/${s.total} `, tone: 'text' }];
|
|
68
|
+
if (s.rejected > 0) {
|
|
69
|
+
const rl = s.layers.find(l => l.id === s.rejectedAt);
|
|
70
|
+
segs.push({ t: '✖', tone: 'fail' }, { t: ` ${[s.rejectedAt || 'a layer', LAYER_NAMES[s.rejectedAt]].filter(Boolean).join(' ')} rejected${rl && rl.reason ? `: ${rl.reason}` : ''}`, tone: 'fail' });
|
|
71
|
+
} else if (s.accounted < s.total) {
|
|
72
|
+
segs.push({ t: '⚠', tone: 'warn' }, { t: ` only ${s.accounted} of ${s.total} reported`, tone: 'warn' });
|
|
73
|
+
} else {
|
|
74
|
+
segs.push({ t: '✔', tone: 'ok' });
|
|
75
|
+
}
|
|
76
|
+
segs.push({ t: ` · ${s.passed} passed`, tone: 'text' });
|
|
77
|
+
if (s.bypassed) segs.push({ t: ` · ${s.bypassed} bypassed`, tone: 'text' });
|
|
78
|
+
if (s.verdict && s.verdict.verdict === 'warned') segs.push({ t: ` · ${s.verdict.layer || 'L8'} warned`, tone: 'warn' });
|
|
79
|
+
if (s.toolsOffered != null) segs.push({ t: ` · ${s.toolsOffered} tool${s.toolsOffered === 1 ? '' : 's'}`, tone: 'text' });
|
|
80
|
+
if (s.ms != null) segs.push({ t: ` · ${fmtMs(s.ms)}`, tone: 'text' });
|
|
81
|
+
if (s.legacy) segs.push({ t: ' · server sent no summary', tone: 'warn' });
|
|
82
|
+
return { segs };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export const aoclLineText = (sum) => 'AOCL ' + aoclLineSegs(sum).segs.map(x => x.t).join('');
|
|
86
|
+
|
|
87
|
+
/** The /aocl table: [text, tone] rows, one per layer, for the last turn. */
|
|
88
|
+
export function aoclTableLines(sum) {
|
|
89
|
+
if (!sum) return [['No AOCL record yet. Send a message, then /aocl shows every layer of that turn.', 'warn']];
|
|
90
|
+
const out = [[`▤ AOCL last turn │ ${aoclLineText(sum).slice(5)}`, sum.rejected ? 'error' : 'accent']];
|
|
91
|
+
const byId = Object.fromEntries(sum.layers.map(l => [l.id, l]));
|
|
92
|
+
for (const id of ORDER) {
|
|
93
|
+
const l = byId[id] || { id, outcome: 'not_run', ms: 0 };
|
|
94
|
+
const word = OUTCOME_WORD[l.outcome] || l.outcome;
|
|
95
|
+
const line = `${OUTCOME_GLYPH[l.outcome] || '·'} ${id.padEnd(4)}${LAYER_NAMES[id].padEnd(10)}${word.padEnd(10)}${fmtMs(l.ms).padStart(8)}${l.reason ? ` ${l.reason}` : ''}`;
|
|
96
|
+
out.push([line, l.outcome === 'reject' ? 'error' : l.outcome === 'not_run' ? 'warn' : l.outcome === 'complete' ? 'ok' : 'accent']);
|
|
97
|
+
}
|
|
98
|
+
if (sum.toolsOffered != null) { // the VOLT "tools offered" list, on demand instead of opening every turn
|
|
99
|
+
out.push([`tools offered to the model: ${sum.toolsOffered}${sum.toolsTotal != null ? ` of ${sum.toolsTotal}` : ''}`, 'accent']);
|
|
100
|
+
let row = ' ';
|
|
101
|
+
for (const t of String(sum.toolsList || '').split(/,\s*/).filter(Boolean)) {
|
|
102
|
+
if (row.length + t.length + 2 > 76 && row.trim()) { out.push([row.replace(/,?\s*$/, ''), 'text']); row = ' '; }
|
|
103
|
+
row += t + ', ';
|
|
104
|
+
}
|
|
105
|
+
if (row.trim()) out.push([row.replace(/,?\s*$/, ''), 'text']);
|
|
106
|
+
}
|
|
107
|
+
if (sum.verdict) out.push([`${sum.verdict.layer || 'L8'} ${sum.verdict.verdict}: ${sum.verdict.reason || ''}${sum.verdict.delivered ? ' (the text was already shown)' : ''}`, sum.verdict.verdict === 'blocked' ? 'error' : 'warn']);
|
|
108
|
+
if (sum.legacy) out.push(['This server sent per-layer traces only, no aocl.summary: layers it did not report are shown as not run.', 'warn']);
|
|
109
|
+
return out;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** The note shown when L8 flags an answer that is already on screen. */
|
|
113
|
+
export function verdictNote(v) {
|
|
114
|
+
const reason = v?.reason ? `: ${v.reason}` : '';
|
|
115
|
+
if (v?.verdict === 'blocked') return { text: `✖ AOCL ${v.layer || 'L8'} blocked this answer after it was shown${reason}. Do not act on it.`, tone: 'error' };
|
|
116
|
+
return { text: `⚠ AOCL ${v?.layer || 'L8'} flagged this answer${reason}.`, tone: 'warn' };
|
|
117
|
+
}
|