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,10 @@
|
|
|
1
|
+
/** The org as the status line shows it: its name, or a short "org …H398" until the name arrives. Never a raw ULID. */
|
|
2
|
+
const ULID = /^[0-9A-HJKMNP-TV-Z]{26}$/i;
|
|
3
|
+
export const isOrgId = (s) => ULID.test(String(s || '').trim());
|
|
4
|
+
export function orgLabel(name, id = null) {
|
|
5
|
+
const n = name == null ? '' : String(name).trim();
|
|
6
|
+
if (n && !isOrgId(n)) return n;
|
|
7
|
+
const raw = isOrgId(n) ? n : (id ? String(id).trim() : '');
|
|
8
|
+
if (!raw) return null;
|
|
9
|
+
return isOrgId(raw) ? `org …${raw.slice(-4)}` : raw; // only a real ULID is masked
|
|
10
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** /org helpers (pure). Org list rows, fuzzy match, and the lines the command prints. QUOXON-FW3. */
|
|
2
|
+
const norm = (s) => String(s ?? '').toLowerCase().replace(/[^a-z0-9]+/g, ' ').trim();
|
|
3
|
+
|
|
4
|
+
export const orgRows = (list) => (Array.isArray(list) ? list : []).map((o) => ({ id: o.id, name: o.name || o.slug || o.id, slug: o.slug || null, role: o.role || null }));
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Resolve a typed name or id against the user's orgs. Exact id, exact slug/name, then every word of the
|
|
8
|
+
* query found in the name or slug (so "hot tubs hampshire" finds "Hot Tubs Hampshire Ltd"). Never guesses between ties.
|
|
9
|
+
* -> { org } | { ambiguous: [orgs] } | { none: true }
|
|
10
|
+
*/
|
|
11
|
+
export function matchOrg(query, list) {
|
|
12
|
+
const rows = orgRows(list);
|
|
13
|
+
const q = norm(query);
|
|
14
|
+
if (!q) return { none: true };
|
|
15
|
+
// An exact slug wins outright, so a slug never ties with another org's look-alike name (#1141).
|
|
16
|
+
const bySlug = rows.filter((o) => o.slug && o.slug === String(query).trim());
|
|
17
|
+
if (bySlug.length === 1) return { org: bySlug[0] };
|
|
18
|
+
const exact = rows.filter((o) => String(o.id).toLowerCase() === String(query).trim().toLowerCase() || norm(o.slug) === q || norm(o.name) === q);
|
|
19
|
+
if (exact.length === 1) return { org: exact[0] };
|
|
20
|
+
if (exact.length > 1) return { ambiguous: exact };
|
|
21
|
+
const words = q.split(' ');
|
|
22
|
+
const fuzzy = rows.filter((o) => { const hay = `${norm(o.name)} ${norm(o.slug)}`; return words.every((w) => hay.includes(w)); });
|
|
23
|
+
if (fuzzy.length === 1) return { org: fuzzy[0] };
|
|
24
|
+
if (fuzzy.length > 1) return { ambiguous: fuzzy };
|
|
25
|
+
return { none: true };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** One line per org; the current one is marked. */
|
|
29
|
+
export function orgLines(list, currentId) {
|
|
30
|
+
const rows = orgRows(list);
|
|
31
|
+
const w = Math.min(36, Math.max(4, ...rows.map((o) => [...o.name].length)));
|
|
32
|
+
return rows.map((o) => `${o.id === currentId ? '* ' : ' '}${o.name.padEnd(w)} ${o.slug || o.id}${o.role ? ` (${o.role})` : ''}`);
|
|
33
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Your own broadcast is not news to you: the fan-out reaches every held slot in the org, including this window's, and
|
|
3
|
+
* the "BROADCAST sent" card already told the sender. Match by the sender's identity, never by text.
|
|
4
|
+
*/
|
|
5
|
+
import { parseBroadcastText } from './slash/broadcast.js';
|
|
6
|
+
|
|
7
|
+
const norm = (s) => String(s || '').toLowerCase().replace(/\s*\(.*?\)\s*/g, ' ').replace(/\s+/g, ' ').trim();
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @param {object} m the slot message
|
|
11
|
+
* @param {object} me { label: this window's sender label, display: the signed-in display name, userId }
|
|
12
|
+
*/
|
|
13
|
+
export function isOwnBroadcast(m, me = {}) {
|
|
14
|
+
const bc = parseBroadcastText(m?.text);
|
|
15
|
+
if (!bc) return false;
|
|
16
|
+
const uid = me.userId ? String(me.userId) : null;
|
|
17
|
+
if (uid && [m.user_id, m.from_user_id, m.author_user_id, m.author_id].some((x) => x != null && String(x) === uid)) return true;
|
|
18
|
+
const sender = norm(bc.sender), from = norm(m.from);
|
|
19
|
+
const mine = [me.label, me.display].map(norm).filter(Boolean);
|
|
20
|
+
if (!mine.length) return false;
|
|
21
|
+
return mine.some((x) => x === sender || x === from) || (me.label && m.from === me.label) || false;
|
|
22
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The semantic palette (QUOXON-FW11). One role per MEANING, so a reader can see where prose stops and a thing
|
|
3
|
+
* they can type starts:
|
|
4
|
+
*
|
|
5
|
+
* prose default text. White on dark, ink on light. Never grey.
|
|
6
|
+
* command anything the user can type: /slash commands, `quox ...`, !bang, flags and args INCLUDED. The whole
|
|
7
|
+
* command is ONE span in ONE colour (never split into differently coloured parts).
|
|
8
|
+
* value ids, names, numbers, paths, URLs (theme role `id`; theme's `value` stays the near-white card text).
|
|
9
|
+
* ok / warn / error state. Carried by a glyph or label ("⚠"), never by tinting the sentence, so commands and
|
|
10
|
+
* values inside keep their own colours.
|
|
11
|
+
* brand Quox purple: chrome only (logo, status-bar labels, headers). Never a command inside prose.
|
|
12
|
+
* quiet secondary text and rules: a tinted, readable shade (never a mid-grey).
|
|
13
|
+
*
|
|
14
|
+
* Both tables: [truecolor hex, ansi256 index]. DARK >= 4.5:1 on #000, LIGHT >= 4.5:1 on #fff (tests).
|
|
15
|
+
*/
|
|
16
|
+
export const SEMANTIC_DARK = {
|
|
17
|
+
prose: ['#f1f5f9', 255], command: ['#2dd4bf', 80], value: ['#93c5fd', 117],
|
|
18
|
+
ok: ['#4ade80', 78], warn: ['#f59e0b', 214], error: ['#f87171', 210],
|
|
19
|
+
brand: ['#a855f7', 135], quiet: ['#bcc8e8', 189], rule: ['#7c8fe0', 105]
|
|
20
|
+
};
|
|
21
|
+
export const SEMANTIC_LIGHT = {
|
|
22
|
+
prose: ['#0f172a', 234], command: ['#0f766e', 30], value: ['#1d4ed8', 26],
|
|
23
|
+
ok: ['#15803d', 28], warn: ['#b45309', 130], error: ['#b91c1c', 124],
|
|
24
|
+
brand: ['#7e22ce', 91], quiet: ['#3b4f87', 60], rule: ['#7280c8', 104]
|
|
25
|
+
};
|
|
26
|
+
export const SEMANTIC_ROLES = Object.keys(SEMANTIC_DARK);
|
|
27
|
+
|
|
28
|
+
/** Is this hex a mid-grey? Low saturation in the middle of the lightness range (white and ink are allowed). */
|
|
29
|
+
export function isGrey(hex) {
|
|
30
|
+
const [r, g, b] = [1, 3, 5].map(i => parseInt(hex.slice(i, i + 2), 16) / 255);
|
|
31
|
+
const max = Math.max(r, g, b), min = Math.min(r, g, b), l = (max + min) / 2, d = max - min;
|
|
32
|
+
const s = d === 0 ? 0 : d / (1 - Math.abs(2 * l - 1));
|
|
33
|
+
return s < 0.25 && l > 0.2 && l < 0.85;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// ---- inline markup used by every notice producer --------------------------------------------------
|
|
37
|
+
// ⟦text⟧ = a command (one span, markers dropped on screen). ⟪text⟫ = a value. Helpers build them. (Not backticks:
|
|
38
|
+
// plain backticks already appear literally in notices.)
|
|
39
|
+
export const cmd = (s) => `⟦${s}⟧`;
|
|
40
|
+
export const val = (s) => `⟪${s}⟫`;
|
|
41
|
+
export const MARK = /⟦([^⟧\n]+)⟧|⟪([^⟫\n]+)⟫/g;
|
|
42
|
+
/** The on-screen characters of marked-up text (markers dropped). Use for width and wrapping. */
|
|
43
|
+
export const stripMarks = (s) => String(s ?? '').replace(MARK, (_, a, b) => a ?? b);
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Headless mode: `quox --print "<prompt>"` sends one turn and exits.
|
|
3
|
+
* (-p is --profile across quox, so print has no short flag.)
|
|
4
|
+
* Exit codes: 0 completed, 2 held for approval, 3 interrupted, 4 auth, 5 unconfirmed
|
|
5
|
+
* (stream closed without turn.finished), 1 other.
|
|
6
|
+
*/
|
|
7
|
+
import { textGate } from './events.js';
|
|
8
|
+
import { streamFields, fallbackNote } from './model.js';
|
|
9
|
+
import { connectOfferFor } from './connect.js';
|
|
10
|
+
import { isConsentError, consentPrintMessage } from './consent.js';
|
|
11
|
+
|
|
12
|
+
export const EXIT = { ok: 0, error: 1, approval: 2, interrupted: 3, auth: 4, unconfirmed: 5 };
|
|
13
|
+
|
|
14
|
+
export async function readStdin(stream = process.stdin) {
|
|
15
|
+
if (stream.isTTY) return '';
|
|
16
|
+
let s = '';
|
|
17
|
+
stream.setEncoding?.('utf8');
|
|
18
|
+
for await (const chunk of stream) s += chunk;
|
|
19
|
+
return s;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Resolve the prompt: arg wins; absent or "-" reads stdin. */
|
|
23
|
+
export async function resolvePrompt(arg, stdin) {
|
|
24
|
+
if (arg && arg !== '-') return arg;
|
|
25
|
+
return (await readStdin(stdin)).replace(/\n+$/, '');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const isAuth = (e) => e?.status === 401 || /valid jwt|service key|unauthor|not authenticated/i.test(e?.message || '');
|
|
29
|
+
const newTurnId = () => `QXN_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
30
|
+
|
|
31
|
+
/** Runs one turn. out/err are write(string) sinks. Returns the exit code. */
|
|
32
|
+
export async function runPrint({ api, prompt, agent = 'quox', output = 'text', conversation = null, turnId = newTurnId(), timeoutS = 0, color = false, stopGraceMs = 8000, context = undefined, choice = null, promptProfile = undefined, profile = null, out, err }) {
|
|
33
|
+
if (!prompt || !prompt.trim()) { err('quox: empty prompt (pass --print "<prompt>" or pipe it on stdin)\n'); return EXIT.error; }
|
|
34
|
+
const ctrl = new AbortController();
|
|
35
|
+
let abandoned = false, graceTimer = null;
|
|
36
|
+
// A timeout asks the SERVER to stop; only if it cannot (or does not answer in the grace) do we abandon the
|
|
37
|
+
// local stream, and then we say "abandoned", never "interrupted": the server may still finish the turn.
|
|
38
|
+
const requestStop = async () => {
|
|
39
|
+
let r = { ok: false };
|
|
40
|
+
try { if (api.interrupt) r = await api.interrupt(convo, turnId); } catch { r = { ok: false }; }
|
|
41
|
+
if (r?.ok) graceTimer = setTimeout(() => { abandoned = true; ctrl.abort(); }, stopGraceMs);
|
|
42
|
+
else { abandoned = true; ctrl.abort(); }
|
|
43
|
+
};
|
|
44
|
+
const timer = timeoutS > 0 ? setTimeout(requestStop, timeoutS * 1000) : null;
|
|
45
|
+
const t0 = Date.now();
|
|
46
|
+
const sum = { tools: 0, approvals: 0, receipts: [] };
|
|
47
|
+
let convo = conversation, doneSession = null, status = null, text = '', sawApproval = false, errorMsg = null, authFail = false;
|
|
48
|
+
const seen = new Set();
|
|
49
|
+
let offer = null, handoff = null;
|
|
50
|
+
let gate = null;
|
|
51
|
+
try {
|
|
52
|
+
for await (const ev of api.stream({ turnId, message: prompt, agent: agent || 'quox', conversationId: conversation, context, ...streamFields(choice), ...(promptProfile ? { promptProfile } : {}), ...(timeoutS > 0 ? { turnBudgetMs: timeoutS * 1000 } : {}) }, ctrl.signal)) {
|
|
53
|
+
if (output === 'json') out(JSON.stringify(ev) + '\n');
|
|
54
|
+
const fb = fallbackNote(choice, ev);
|
|
55
|
+
if (fb) err(`quox: ${fb}\n`);
|
|
56
|
+
if (!offer) offer = connectOfferFor(ev);
|
|
57
|
+
if (ev.conversation_id) convo = ev.conversation_id;
|
|
58
|
+
if (ev.session_id) doneSession = ev.session_id; // the server's real id: v1 events only echo the request
|
|
59
|
+
if (ev.type === 'chunk' || ev.type === 'text.delta' || ev.type === 'turn.started') { const g = textGate(gate, ev); gate = g.st; if (g.append) text += ev.content; }
|
|
60
|
+
else if (ev.type === 'done' && !text && ev.full_response) text = ev.full_response;
|
|
61
|
+
else if (ev.type === 'tool.started' && !seen.has(ev.call_id)) { seen.add(ev.call_id); sum.tools++; }
|
|
62
|
+
else if (ev.type === 'tool.finished') { if (!seen.has(ev.call_id)) { seen.add(ev.call_id); sum.tools++; } if (ev.receipt?.ward_seq != null) sum.receipts.push(ev.receipt.ward_seq); }
|
|
63
|
+
else if (ev.type === 'approval.requested') { sawApproval = true; sum.approvals++; }
|
|
64
|
+
else if (ev.type === 'approval.resolved') sawApproval = false;
|
|
65
|
+
else if (ev.type === 'turn.handoff_suggested' && ev.handoff_suggested?.agent) handoff = ev.handoff_suggested; // QUOXON handoff offer
|
|
66
|
+
else if (ev.type === 'turn.finished') status = ev.status || 'completed';
|
|
67
|
+
else if (ev.type === 'error') errorMsg = isConsentError(ev) ? consentPrintMessage(ev, profile) : (ev.error || 'stream error');
|
|
68
|
+
}
|
|
69
|
+
} catch (e) {
|
|
70
|
+
if (ctrl.signal.aborted) { status = 'abandoned'; errorMsg = `timed out after ${timeoutS}s; the server was not confirmed stopped`; }
|
|
71
|
+
else { authFail = isAuth(e); errorMsg = e?.message || String(e); }
|
|
72
|
+
} finally { if (timer) clearTimeout(timer); clearTimeout(graceTimer); }
|
|
73
|
+
if (ctrl.signal.aborted && !status) { status = 'abandoned'; errorMsg = errorMsg || `timed out after ${timeoutS}s; the server was not confirmed stopped`; }
|
|
74
|
+
if (doneSession) convo = doneSession;
|
|
75
|
+
const serverStopped = abandoned && status === 'abandoned' ? false : status === 'interrupted' ? true : null;
|
|
76
|
+
|
|
77
|
+
let code;
|
|
78
|
+
if (authFail) code = EXIT.auth;
|
|
79
|
+
else if (sawApproval && status !== 'interrupted' && status !== 'abandoned') { status = status === 'completed' || !status ? 'held_for_approval' : status; code = EXIT.approval; }
|
|
80
|
+
else if (status === 'completed' && !errorMsg) code = EXIT.ok;
|
|
81
|
+
else if (status === 'interrupted' || status === 'abandoned') code = EXIT.interrupted;
|
|
82
|
+
else if (sawApproval) { status = status || 'held_for_approval'; code = EXIT.approval; }
|
|
83
|
+
else if (!status && !errorMsg) { status = 'unconfirmed'; code = EXIT.unconfirmed; }
|
|
84
|
+
else code = EXIT.error;
|
|
85
|
+
if (!status) status = authFail ? 'auth' : 'failed';
|
|
86
|
+
|
|
87
|
+
if (output === 'json') {
|
|
88
|
+
out(JSON.stringify({ type: 'summary', status, turn_id: turnId, conversation_id: convo, duration_ms: Date.now() - t0, server_stopped: serverStopped, ...sum, ...(handoff ? { handoff_suggested: handoff } : {}) }) + '\n');
|
|
89
|
+
} else if (text) out(text.endsWith('\n') ? text : text + '\n');
|
|
90
|
+
if (authFail) err(`Not signed in for chat. Run: quox login -p <profile>\n`);
|
|
91
|
+
else if (code === EXIT.approval) err('Held for approval: approve it in the dashboard or with `quox` /approvals.\n');
|
|
92
|
+
else if (code === EXIT.unconfirmed) err('quox: Ended without confirmation from the server\n');
|
|
93
|
+
else if (errorMsg) err(`quox: ${errorMsg}\n`);
|
|
94
|
+
if (offer && code !== EXIT.ok) err(`${offer}\n`);
|
|
95
|
+
// QUOXON handoff offer: no y/N here, so name the exact one-turn command (same question, same conversation).
|
|
96
|
+
if (handoff && output !== 'json' && code === EXIT.ok) err(`quox: ${handoff.reason ? `${String(handoff.reason).replace(/\s+$/, '')} ` : ''}${handoff.name || handoff.agent} can answer it: quox --print --agent ${handoff.agent}${convo ? ` --conversation ${convo}` : ''} ${JSON.stringify(prompt)}\n`);
|
|
97
|
+
return code;
|
|
98
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// PROFILE-SWITCH (owner 2026-10-16): switch this window between logged-in profiles with one y, never automatically.
|
|
2
|
+
import { askText } from './ask.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The App's api, swappable in place: every reader (and every controller built at mount) goes through this proxy,
|
|
6
|
+
* so a profile switch replaces ref.current.live and the whole window follows. Methods are bound to the live api.
|
|
7
|
+
*/
|
|
8
|
+
export function liveApi(ref) {
|
|
9
|
+
return new Proxy({}, {
|
|
10
|
+
get(_, k) {
|
|
11
|
+
const a = ref.current?.live;
|
|
12
|
+
if (a == null) return undefined;
|
|
13
|
+
const v = a[k];
|
|
14
|
+
return typeof v === 'function' ? v.bind(a) : v;
|
|
15
|
+
},
|
|
16
|
+
has(_, k) { const a = ref.current?.live; return a != null && k in Object(a); },
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** The ask card offering to switch an agent-login window to a human login. */
|
|
21
|
+
export const switchAskLine = (profile, human) => askText('Switch?', {
|
|
22
|
+
title: `This window is an agent login (${profile}).`,
|
|
23
|
+
action: `switch this window to your login '${human}' (same conversation, attach, slot and groups)`,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
/** The ask card for a /slot name that does not exist (the near misses are said on the line above). */
|
|
27
|
+
export const slotCreateAskLine = (nm) => askText('Create it?', { title: `No slot ${nm}.`, action: `create and hold slot ${nm}` });
|
|
28
|
+
|
|
29
|
+
/** A local run request (the shared run card): sign a profile in with the real `quox login`, terminal handed over. */
|
|
30
|
+
export function loginRunRequest(name, why, now = Date.now()) {
|
|
31
|
+
return { id: null, cmd: `quox login -p ${name}`, why, who: 'Quox', runnable: true, refuse: null, danger: null, expiresAt: now + 120000 };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** A safe profile name to put on a command line (letters, digits, . _ -). */
|
|
35
|
+
export const okProfileName = (n) => /^[A-Za-z0-9._-]{1,64}$/.test(String(n || ''));
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* /profile chooser rows (PROFILE-CHOOSER): signed-in profiles first (this window's marked), then profiles on this
|
|
39
|
+
* machine that are not signed in, then the current login's orgs (the window's org marked). Each row carries `pick`:
|
|
40
|
+
* { profile } switches this window in place, { login } offers `quox login -p`, { org } goes through /org switch
|
|
41
|
+
* (window-scoped since #1034, confirmed first). Nothing here writes the shared default profile.
|
|
42
|
+
*/
|
|
43
|
+
export function profileChooserRows({ current, humanProfiles = [], loginCandidates = [], orgs = [], orgId = null }) {
|
|
44
|
+
const names = [...new Set([current, ...humanProfiles].filter(okProfileName))];
|
|
45
|
+
const later = loginCandidates.filter(n => okProfileName(n) && !names.includes(n));
|
|
46
|
+
const orgList = (Array.isArray(orgs) ? orgs : []).map(o => ({ id: o.id, name: o.name || o.slug || o.id, slug: o.slug || null, role: o.role || null }));
|
|
47
|
+
const w = Math.min(28, Math.max(8, ...[...names, ...later].map(n => n.length + 8), ...orgList.map(o => [...o.name].length + 4)));
|
|
48
|
+
const rows = [];
|
|
49
|
+
for (const n of names) rows.push({ key: `${n === current ? '* ' : ' '}${`profile ${n}`.padEnd(w)}`, text: n === current ? 'this window' : 'signed in: switch this window to it', pick: { profile: n } });
|
|
50
|
+
for (const n of later) rows.push({ key: ` ${`profile ${n}`.padEnd(w)}`, text: 'not signed in: offers quox login', pick: { login: n } });
|
|
51
|
+
for (const o of orgList) rows.push({ key: `${o.id === orgId ? '* ' : ' '}${`org ${o.name}`.padEnd(w)}`, text: `${o.slug || o.id}${o.role ? ` (${o.role})` : ''}${o.id === orgId ? ' this window' : ''}`, pick: { org: o } });
|
|
52
|
+
return rows;
|
|
53
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QUOXON-HISTORY: what the user typed, kept across quox runs so Up recalls it (most recent first), like a shell.
|
|
3
|
+
* Local only (~/.quox/history.jsonl, mode 0600), capped. The caller never offers it anything that looks like a key:
|
|
4
|
+
* keys, PINs and /connect secrets are refused before they reach history.
|
|
5
|
+
*/
|
|
6
|
+
import { readFileSync, appendFileSync, writeFileSync, mkdirSync, statSync } from 'node:fs';
|
|
7
|
+
import { homedir } from 'node:os';
|
|
8
|
+
import { join, dirname } from 'node:path';
|
|
9
|
+
|
|
10
|
+
export const HISTORY_CAP = 500;
|
|
11
|
+
export const defaultHistoryPath = (home = homedir()) => join(home, '.quox', 'history.jsonl');
|
|
12
|
+
|
|
13
|
+
/** -> { load(): string[] oldest first, add(text) } on the given file. Every failure is quiet: history is a convenience. */
|
|
14
|
+
export function fileHistory(path = defaultHistoryPath(), { cap = HISTORY_CAP } = {}) {
|
|
15
|
+
const load = () => {
|
|
16
|
+
try {
|
|
17
|
+
const out = [];
|
|
18
|
+
for (const ln of readFileSync(path, 'utf8').split('\n')) {
|
|
19
|
+
if (!ln) continue;
|
|
20
|
+
try { const t = JSON.parse(ln)?.t; if (typeof t === 'string' && t) out.push(t); } catch { /* a torn line */ }
|
|
21
|
+
}
|
|
22
|
+
return out.slice(-cap);
|
|
23
|
+
} catch { return []; }
|
|
24
|
+
};
|
|
25
|
+
const add = (text) => {
|
|
26
|
+
try {
|
|
27
|
+
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
28
|
+
appendFileSync(path, JSON.stringify({ t: text }) + '\n', { mode: 0o600 });
|
|
29
|
+
if (statSync(path).size > cap * 400) { const keep = load(); writeFileSync(path, keep.map(t => JSON.stringify({ t })).join('\n') + '\n', { mode: 0o600 }); }
|
|
30
|
+
} catch { /* read-only home: this run still has it in memory */ }
|
|
31
|
+
};
|
|
32
|
+
return { load, add };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Push onto the in-memory list, skipping an exact repeat of the last entry (shell ignoredups). -> true when added. */
|
|
36
|
+
export function pushHistory(list, text) {
|
|
37
|
+
if (typeof text !== 'string' || !text.trim()) return false;
|
|
38
|
+
if (list.length && list[list.length - 1] === text) return false;
|
|
39
|
+
list.push(text);
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider availability, one source of truth for /model, /connect, /doctor and /capabilities (R3 audit D5:
|
|
3
|
+
* the Claude subscription used to tell five different stories).
|
|
4
|
+
*
|
|
5
|
+
* The SERVER decides: GET /api/v1/capabilities reports `provider.<id>` from real signals (org vault keys,
|
|
6
|
+
* instance keys, the server's Claude sign-in). The org vault list only adds detail (which credential, a
|
|
7
|
+
* stored-but-not-default key). A provider the server does not report (Ollama) falls back to the vault; when
|
|
8
|
+
* neither answers the state is unknown, never "not connected".
|
|
9
|
+
*
|
|
10
|
+
* Pure: `caps` is { ok, capabilities } from api.capabilities(), `vault` is { ok, rows } from api.connections().
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export const SUBSCRIPTION_NAME = 'Claude (subscription, dev only)';
|
|
14
|
+
const DISPLAY = { 'provider.claude_subscription': SUBSCRIPTION_NAME };
|
|
15
|
+
|
|
16
|
+
/** The name every surface shows for a capability (the server's own name, except where Quox has a fixed one). */
|
|
17
|
+
export const capabilityName = (c) => DISPLAY[c?.id] || c?.name || c?.id;
|
|
18
|
+
|
|
19
|
+
/** The server could not read this provider's status (not "not available"): shown as ? unknown on every surface. */
|
|
20
|
+
export const statusUnreadable = (c) => c?.availability === 'unavailable' && /^Could not read .* status/i.test(c.reason || '');
|
|
21
|
+
|
|
22
|
+
export const vaultPick = (rows, type) => {
|
|
23
|
+
const of = rows.filter(r => r.integration_type === type);
|
|
24
|
+
return { def: of.find(r => r.is_default === 1 || r.is_default === true) || null, any: of[0] || null };
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* -> { state, row?, reason?, setup?, source } for one provider.
|
|
29
|
+
* state: 'connected' (the server can use it) | 'stored' (a key exists but is not the org default) |
|
|
30
|
+
* 'missing' (needs setup) | 'unavailable' (not on this server) | 'unknown' (nothing answered).
|
|
31
|
+
* p: { cap: 'openai' | 'claude_subscription' | ..., vault?: integration type }
|
|
32
|
+
*/
|
|
33
|
+
export function providerState(p, caps, vault) {
|
|
34
|
+
const rows = vault?.ok && Array.isArray(vault.rows) ? vault.rows : null;
|
|
35
|
+
const v = rows && p.vault ? vaultPick(rows, p.vault) : { def: null, any: null };
|
|
36
|
+
const c = caps?.ok && Array.isArray(caps.capabilities) ? caps.capabilities.find(x => x?.id === `provider.${p.cap}`) : null;
|
|
37
|
+
if (c && statusUnreadable(c)) return { state: 'unknown', reason: c.reason, source: 'server' };
|
|
38
|
+
if (c) {
|
|
39
|
+
const base = { reason: c.reason || null, setup: c.setup || null, source: 'server' };
|
|
40
|
+
if (c.availability === 'installed') return { ...base, state: 'connected', row: v.def || null };
|
|
41
|
+
if (c.availability === 'requires_setup') return v.any && !v.def ? { ...base, state: 'stored', row: v.any } : { ...base, state: 'missing' };
|
|
42
|
+
return { ...base, state: 'unavailable' };
|
|
43
|
+
}
|
|
44
|
+
if (!rows || !p.vault) return { state: 'unknown', source: 'none' };
|
|
45
|
+
if (v.def) return { state: 'connected', row: v.def, source: 'vault' };
|
|
46
|
+
if (v.any) return { state: 'stored', row: v.any, source: 'vault' };
|
|
47
|
+
return { state: 'missing', source: 'vault' };
|
|
48
|
+
}
|