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,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ONE-BRAIN CX4 (attach-time prime) and CX3 (handoff-to-note) helpers.
|
|
3
|
+
*
|
|
4
|
+
* Both are best effort by design: neither may ever fail an attach or a detach.
|
|
5
|
+
* Endpoints reused: brain.context.pack (`quox brain context`) and
|
|
6
|
+
* brain.capture.create (`quox brain add` / `decide`).
|
|
7
|
+
*/
|
|
8
|
+
import { execFileSync } from 'node:child_process';
|
|
9
|
+
import { resolveEndpoint } from '../api/endpoints.js';
|
|
10
|
+
|
|
11
|
+
export const PRIME_TIMEOUT_MS = 5000;
|
|
12
|
+
export const PRIME_TOKEN_BUDGET = 1200;
|
|
13
|
+
export const PRIME_SNIPPET_CHARS = 300;
|
|
14
|
+
|
|
15
|
+
function gitOut(args) {
|
|
16
|
+
try { return execFileSync('git', args, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim(); } catch { return ''; }
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Does this attach kit's resolved tool list carry the brain_context tool? */
|
|
20
|
+
export function kitHasBrainContext(kit) {
|
|
21
|
+
return Array.isArray(kit?.tools) && kit.tools.includes('brain_context');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Query text from the working context: repo, branch, advisory stream, last 3 commit subjects. */
|
|
25
|
+
export function buildPrimeQuery({ git = gitOut, env = process.env } = {}) {
|
|
26
|
+
const top = git(['rev-parse', '--show-toplevel']);
|
|
27
|
+
const repo = top ? top.split('/').pop() : '';
|
|
28
|
+
const branch = git(['rev-parse', '--abbrev-ref', 'HEAD']);
|
|
29
|
+
const subjects = git(['log', '-3', '--pretty=%s']).split('\n').map((s) => s.trim()).filter(Boolean);
|
|
30
|
+
const parts = [];
|
|
31
|
+
if (repo) parts.push(`repo ${repo}`);
|
|
32
|
+
if (branch && branch !== 'HEAD') parts.push(`branch ${branch}`);
|
|
33
|
+
if (env.QUOX_STREAM) parts.push(`stream ${env.QUOX_STREAM} (advisory)`);
|
|
34
|
+
if (subjects.length) parts.push(`recent work: ${subjects.join('; ')}`);
|
|
35
|
+
return parts.join(', ');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function withTimeout(promise, ms) {
|
|
39
|
+
let timer;
|
|
40
|
+
const t = new Promise((_, reject) => { timer = setTimeout(() => reject(new Error(`timed out after ${ms / 1000}s`)), ms); });
|
|
41
|
+
return Promise.race([promise, t]).finally(() => clearTimeout(timer));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Returns the "## Brain primer" markdown section. Never throws. */
|
|
45
|
+
export async function buildBrainPrimer(client, { query, timeoutMs = PRIME_TIMEOUT_MS } = {}) {
|
|
46
|
+
const head = '## Brain primer';
|
|
47
|
+
try {
|
|
48
|
+
const q = query ?? buildPrimeQuery();
|
|
49
|
+
if (!q) return `${head}\n\nNo primer: the brain returned nothing relevant\n`;
|
|
50
|
+
const ep = resolveEndpoint('brain.context.pack');
|
|
51
|
+
const data = await withTimeout(
|
|
52
|
+
Promise.resolve().then(() => client.post(ep.path, { service: ep.service, body: { query: q, tokenBudget: PRIME_TOKEN_BUDGET } })),
|
|
53
|
+
timeoutMs,
|
|
54
|
+
);
|
|
55
|
+
const passages = Array.isArray(data?.passages) ? data.passages : [];
|
|
56
|
+
const insufficient = data?.insufficient === true || data?.relevance?.insufficient === true || passages.length === 0;
|
|
57
|
+
if (insufficient) return `${head}\n\nNo primer: the brain returned nothing relevant\n`;
|
|
58
|
+
const lines = passages.map((p) => {
|
|
59
|
+
const c = p.citation || {};
|
|
60
|
+
const text = String(p.text || '').replace(/\s+/g, ' ').trim().slice(0, PRIME_SNIPPET_CHARS);
|
|
61
|
+
return `- ${c.title || 'Untitled'} (${p.noteId || c.noteId || '?'}): ${text}`;
|
|
62
|
+
});
|
|
63
|
+
return `${head}\n\nQuery (stream is advisory): ${q}\n\n${lines.join('\n')}\n`;
|
|
64
|
+
} catch (err) {
|
|
65
|
+
return `${head}\n\nNo primer: brain unreachable (${err?.message || 'unknown error'})\n`;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Save a handoff to the knowledge brain as a private note. Returns { ok, noteId?, error? }; never throws. */
|
|
70
|
+
export async function saveHandoffNote(client, { agentId, content, prov = {}, sessionName, now = new Date() }) {
|
|
71
|
+
try {
|
|
72
|
+
const ep = resolveEndpoint('brain.capture.create');
|
|
73
|
+
const iso = now.toISOString();
|
|
74
|
+
const provLines = [
|
|
75
|
+
`Agent: ${agentId}`,
|
|
76
|
+
prov.repo ? `Repo: ${prov.repo}` : null,
|
|
77
|
+
prov.commit ? `Commit: ${prov.commit}` : null,
|
|
78
|
+
sessionName ? `Session: ${sessionName}` : null,
|
|
79
|
+
`At: ${iso}`,
|
|
80
|
+
].filter(Boolean);
|
|
81
|
+
const text = `${content}\n\n## Provenance\n\n${provLines.map((l) => `- ${l}`).join('\n')}\n`;
|
|
82
|
+
const data = await client.post(ep.path, {
|
|
83
|
+
service: ep.service,
|
|
84
|
+
body: { title: `Handoff: ${agentId} ${iso}`, text, tags: ['handoff', agentId], scope: 'user' },
|
|
85
|
+
});
|
|
86
|
+
return { ok: true, noteId: data?.noteId };
|
|
87
|
+
} catch (err) {
|
|
88
|
+
return { ok: false, error: err?.message || 'unknown error' };
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HITL-CONTEXT (AQ-9A phase 6): work out WHICH session is calling when
|
|
3
|
+
* $QUOX_SESSION is unset, so an approval card says "BRAIN2-AUDIT (CLI)"
|
|
4
|
+
* instead of a bare user id. Display-only: the server never authorizes on it.
|
|
5
|
+
*
|
|
6
|
+
* Precedence:
|
|
7
|
+
* 1. QUOX_SESSION
|
|
8
|
+
* 2. QUOX_STREAM (advisory)
|
|
9
|
+
* 3. the agent attached by this Claude process tree
|
|
10
|
+
* (~/.quox/attach/sessions/claude-<pid>/<agent>/)
|
|
11
|
+
* 4. the slot held by this process tree (held-slots.json sessionKey claude-<pid>)
|
|
12
|
+
* 5. last resort: "<parent process> in ~/<cwd>"
|
|
13
|
+
*
|
|
14
|
+
* Never reads token contents and never emits secrets: only directory names,
|
|
15
|
+
* the kit's display_name, the slot's session label and the cwd.
|
|
16
|
+
*/
|
|
17
|
+
import { readFileSync, readdirSync, existsSync } from 'node:fs';
|
|
18
|
+
import { homedir } from 'node:os';
|
|
19
|
+
import { join, basename } from 'node:path';
|
|
20
|
+
|
|
21
|
+
/** Tools the collector always holds for a human when an agent proposes them. */
|
|
22
|
+
export const APPROVAL_GATED_TOOLS = new Set([
|
|
23
|
+
'loop_halt', 'slot_assign', 'bob_dispatch_build', 'email_send', 'send_notification',
|
|
24
|
+
'remote_ssh', 'ssh_exec', 'db_query', 'alerts_manage', 'backup_run',
|
|
25
|
+
'keeper_backup_create', 'deploy_template',
|
|
26
|
+
'system_admin', 'proxmox_vm_action', 'calendar_event_create',
|
|
27
|
+
]);
|
|
28
|
+
|
|
29
|
+
export const MISSING_REASON_WARNING =
|
|
30
|
+
'approval requests without --reason show \'none given\' to the human; pass --reason "why"';
|
|
31
|
+
|
|
32
|
+
/** One-line stderr warning when a gated tool is run without --reason, else null. */
|
|
33
|
+
export function missingReasonWarning(toolName, reason) {
|
|
34
|
+
if (!APPROVAL_GATED_TOOLS.has(String(toolName || ''))) return null;
|
|
35
|
+
if (typeof reason === 'string' && reason.trim()) return null;
|
|
36
|
+
return `warning: ${MISSING_REASON_WARNING}`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function cleanLabel(v, n = 48) {
|
|
40
|
+
const s = String(v == null ? '' : v).replace(/[^\w .:@+\-/~]/g, '').trim().slice(0, n);
|
|
41
|
+
return s || null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const defaultDeps = {
|
|
45
|
+
readName: (pid) => { try { return readFileSync(`/proc/${pid}/comm`, 'utf-8').trim(); } catch { return null; } },
|
|
46
|
+
readPpid: (pid) => {
|
|
47
|
+
try {
|
|
48
|
+
const s = readFileSync(`/proc/${pid}/stat`, 'utf-8');
|
|
49
|
+
const rest = s.slice(s.lastIndexOf(')') + 2).trim().split(/\s+/);
|
|
50
|
+
const p = parseInt(rest[1], 10);
|
|
51
|
+
return Number.isFinite(p) ? p : null;
|
|
52
|
+
} catch { return null; }
|
|
53
|
+
},
|
|
54
|
+
attachSessionsRoot: () => join(homedir(), '.quox', 'attach', 'sessions'),
|
|
55
|
+
heldSlotsPath: () => join(homedir(), '.quox', 'held-slots.json'),
|
|
56
|
+
readdir: (d) => { try { return readdirSync(d, { withFileTypes: true }); } catch { return []; } },
|
|
57
|
+
readJson: (p) => { try { return existsSync(p) ? JSON.parse(readFileSync(p, 'utf-8')) : null; } catch { return null; } },
|
|
58
|
+
exists: existsSync,
|
|
59
|
+
cwd: () => { try { return process.cwd(); } catch { return ''; } },
|
|
60
|
+
home: () => homedir(),
|
|
61
|
+
pid: () => process.pid,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
function findClaudeAncestor(deps, startPid) {
|
|
65
|
+
let pid = startPid;
|
|
66
|
+
for (let hop = 0; hop < 24; hop += 1) {
|
|
67
|
+
if (deps.readName(pid) === 'claude') return pid;
|
|
68
|
+
const pp = deps.readPpid(pid);
|
|
69
|
+
if (!pp || pp === pid || pid === 1) break;
|
|
70
|
+
pid = pp;
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function attachedAgentLabel(deps, claudePid) {
|
|
76
|
+
const dir = join(deps.attachSessionsRoot(), `claude-${claudePid}`);
|
|
77
|
+
const agents = deps.readdir(dir).filter((e) => e.isDirectory() && deps.exists(join(dir, e.name, 'token')));
|
|
78
|
+
if (agents.length === 0) return null;
|
|
79
|
+
const name = agents[0].name;
|
|
80
|
+
const kit = deps.readJson(join(dir, name, 'kit.json'));
|
|
81
|
+
return cleanLabel(kit && kit.display_name) || cleanLabel(name);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function heldSlotLabel(deps, claudePid) {
|
|
85
|
+
const all = deps.readJson(deps.heldSlotsPath());
|
|
86
|
+
if (!all || typeof all !== 'object') return null;
|
|
87
|
+
for (const [slot, e] of Object.entries(all)) {
|
|
88
|
+
if (e && e.sessionKey === `claude-${claudePid}`) return cleanLabel(e.session) || cleanLabel(slot);
|
|
89
|
+
}
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function cwdLabel(deps) {
|
|
94
|
+
const cwd = deps.cwd();
|
|
95
|
+
if (!cwd) return null;
|
|
96
|
+
const home = deps.home();
|
|
97
|
+
if (home && cwd === home) return '~';
|
|
98
|
+
if (home && cwd.startsWith(`${home}/`)) return `~/${cwd.slice(home.length + 1)}`;
|
|
99
|
+
return basename(cwd) || null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** @returns {{ label: string|null, via: string }} */
|
|
103
|
+
export function detectCallerSource(env = process.env, overrides = {}) {
|
|
104
|
+
const deps = { ...defaultDeps, ...overrides };
|
|
105
|
+
const fromSession = cleanLabel(env.QUOX_SESSION);
|
|
106
|
+
if (fromSession) return { label: fromSession, via: 'QUOX_SESSION' };
|
|
107
|
+
const fromStream = cleanLabel(env.QUOX_STREAM);
|
|
108
|
+
if (fromStream) return { label: fromStream, via: 'QUOX_STREAM' };
|
|
109
|
+
|
|
110
|
+
let claudePid = null;
|
|
111
|
+
try { claudePid = findClaudeAncestor(deps, deps.pid()); } catch { claudePid = null; }
|
|
112
|
+
if (claudePid) {
|
|
113
|
+
const agent = attachedAgentLabel(deps, claudePid);
|
|
114
|
+
if (agent) return { label: agent, via: 'attached_agent' };
|
|
115
|
+
const slot = heldSlotLabel(deps, claudePid);
|
|
116
|
+
if (slot) return { label: slot, via: 'held_slot' };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
let parent = null;
|
|
120
|
+
try {
|
|
121
|
+
const pp = deps.readPpid(deps.pid());
|
|
122
|
+
parent = pp ? deps.readName(pp) : null;
|
|
123
|
+
} catch { parent = null; }
|
|
124
|
+
const who = claudePid ? 'claude' : cleanLabel(parent, 24);
|
|
125
|
+
const where = cwdLabel(deps);
|
|
126
|
+
if (who && where) return { label: cleanLabel(`${who} in ${where}`), via: 'process' };
|
|
127
|
+
if (who) return { label: who, via: 'process' };
|
|
128
|
+
return { label: null, via: 'none' };
|
|
129
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `quox claude ls`: one row per quox-* tmux session. Pure parse/build/render
|
|
3
|
+
* functions take injected tmux output, held-slots JSON and a clock so they
|
|
4
|
+
* unit-test without tmux. SLOT comes from ~/.quox/held-slots.json (holder
|
|
5
|
+
* session name), AGENT from the attach kit of the claude pid that slot entry
|
|
6
|
+
* records (~/.quox/attach/sessions/claude-<pid>/<agent>/). Both are '-' when
|
|
7
|
+
* not derivable (a session that holds no slot has no recorded pid).
|
|
8
|
+
*/
|
|
9
|
+
import { spawnSync as realSpawnSync } from 'node:child_process';
|
|
10
|
+
import { PREFIX, programOf } from './governedSession.js';
|
|
11
|
+
import { slotsBySession, readAttachSafe, readHeldSlotsSafe } from './liveSessionsReport.js';
|
|
12
|
+
import { line } from './quoxglyph.js';
|
|
13
|
+
|
|
14
|
+
export const LS_FORMAT = '#{session_name}\t#{session_created}\t#{session_attached}\t#{session_activity}\t#{session_windows}';
|
|
15
|
+
|
|
16
|
+
export function formatAge(sec) {
|
|
17
|
+
const s = Math.max(0, Math.floor(sec));
|
|
18
|
+
if (s < 60) return `${s}s`;
|
|
19
|
+
if (s < 3600) return `${Math.floor(s / 60)}m`;
|
|
20
|
+
if (s < 86400) return `${Math.floor(s / 3600)}h`;
|
|
21
|
+
return `${Math.floor(s / 86400)}d`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const toDate = (v) => new Date(Number(v) * 1000);
|
|
25
|
+
|
|
26
|
+
export function parseQuoxSessions(out) {
|
|
27
|
+
return String(out || '').split('\n').map((l) => l.split('\t'))
|
|
28
|
+
.filter((c) => c.length >= 5 && c[0].startsWith(PREFIX) && c[0].length > PREFIX.length)
|
|
29
|
+
.map((c) => ({
|
|
30
|
+
name: c[0].slice(PREFIX.length),
|
|
31
|
+
created: toDate(c[1]),
|
|
32
|
+
clients: Number(c[2]) || 0,
|
|
33
|
+
activity: toDate(c[3]),
|
|
34
|
+
windows: Number(c[4]) || 0,
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function buildRows({ tmuxOut, held, now = new Date(), attachLookup = readAttachSafe }) {
|
|
39
|
+
const bySession = slotsBySession(held);
|
|
40
|
+
return parseQuoxSessions(tmuxOut)
|
|
41
|
+
.sort((a, b) => b.activity - a.activity)
|
|
42
|
+
.map((s) => {
|
|
43
|
+
// The slot ledger records the bare session name (what --resume NAME used).
|
|
44
|
+
const hit = bySession[s.name] || bySession[s.name.replace(/^(codex-|gemini-|tui-)/, '')] || null;
|
|
45
|
+
const att = hit ? attachLookup(hit.pid) : null;
|
|
46
|
+
const age = (d) => formatAge((now - d) / 1000);
|
|
47
|
+
return {
|
|
48
|
+
name: s.name,
|
|
49
|
+
state: s.clients > 0 ? 'attached' : 'detached',
|
|
50
|
+
clients: s.clients,
|
|
51
|
+
created: s.created.toISOString(),
|
|
52
|
+
created_age: age(s.created),
|
|
53
|
+
last_active: s.activity.toISOString(),
|
|
54
|
+
active_age: age(s.activity),
|
|
55
|
+
slot: hit ? hit.slot : null,
|
|
56
|
+
agent: att ? att.agent : null,
|
|
57
|
+
backend: programOf(s.name),
|
|
58
|
+
};
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const clip = (v, n) => {
|
|
63
|
+
const a = [...String(v)];
|
|
64
|
+
return a.length > n ? a.slice(0, n - 1).join('') + '…' : String(v);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export function renderTable(rows, { color = false } = {}) {
|
|
68
|
+
const W = { NAME: 20, STATE: 9, CLIENTS: 8, CREATED: 8, 'LAST ACTIVE': 12, SLOT: 8, AGENT: 8, BACKEND: 7 };
|
|
69
|
+
const cols = Object.keys(W);
|
|
70
|
+
const cell = (v, k, last) => (last ? clip(v, W[k]) : clip(v, W[k] - 1).padEnd(W[k]));
|
|
71
|
+
const fmt = (vals) => cols.map((k, i) => cell(vals[i], k, i === cols.length - 1)).join('');
|
|
72
|
+
const head = line('quox', 'sessions', { result: `${rows.length} running` });
|
|
73
|
+
const body = rows.map((r) => fmt([r.name, r.state, r.clients, r.created_age, r.active_age, r.slot || '-', r.agent || '-', r.backend]));
|
|
74
|
+
return [head, fmt(cols), ...body].join('\n');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function runClaudeLs({ json = false } = {}, over = {}) {
|
|
78
|
+
const d = {
|
|
79
|
+
spawnSync: realSpawnSync, now: () => new Date(), write: (s) => process.stdout.write(s),
|
|
80
|
+
held: undefined, attachLookup: readAttachSafe, ...over,
|
|
81
|
+
};
|
|
82
|
+
const r = d.spawnSync('tmux', ['list-sessions', '-F', LS_FORMAT], { encoding: 'utf8' });
|
|
83
|
+
if (r && r.error && r.error.code === 'ENOENT') {
|
|
84
|
+
d.write('tmux is not installed (apt install tmux / brew install tmux).\n');
|
|
85
|
+
return 1;
|
|
86
|
+
}
|
|
87
|
+
// A non-zero exit means no server is running (nothing to list), not an error.
|
|
88
|
+
const out = r && r.status === 0 ? r.stdout : '';
|
|
89
|
+
const rows = buildRows({ tmuxOut: out, held: d.held ?? readHeldSlotsSafe(), now: d.now(), attachLookup: d.attachLookup });
|
|
90
|
+
if (json) { d.write(JSON.stringify(rows, null, 2) + '\n'); return 0; }
|
|
91
|
+
if (!rows.length) { d.write('No quox sessions running.\n'); return 0; }
|
|
92
|
+
d.write(renderTable(rows) + '\n');
|
|
93
|
+
return 0;
|
|
94
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KEEPER-REEXEC: which quox build is installed, read from files only (cheap enough to check on
|
|
3
|
+
* every keeper control poll, no git or child process). A git checkout (the dev box runs quox from
|
|
4
|
+
* a detached worktree) reports its HEAD sha; an npm install reports `v<version>`. null = unknown,
|
|
5
|
+
* and an unknown build never triggers a re-exec or a takeover.
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync, existsSync, statSync } from 'node:fs';
|
|
8
|
+
import { dirname, join, resolve, isAbsolute } from 'node:path';
|
|
9
|
+
import { fileURLToPath } from 'node:url';
|
|
10
|
+
|
|
11
|
+
const SHA_RE = /^[0-9a-f]{40,64}$/;
|
|
12
|
+
const read = (p) => { try { return readFileSync(p, 'utf-8').trim(); } catch { return null; } };
|
|
13
|
+
|
|
14
|
+
function gitDirFor(root) {
|
|
15
|
+
const dotGit = join(root, '.git');
|
|
16
|
+
if (!existsSync(dotGit)) return null;
|
|
17
|
+
try {
|
|
18
|
+
if (statSync(dotGit).isDirectory()) return dotGit;
|
|
19
|
+
} catch { return null; }
|
|
20
|
+
const m = /^gitdir:\s*(.+)$/m.exec(read(dotGit) || '');
|
|
21
|
+
if (!m) return null;
|
|
22
|
+
return isAbsolute(m[1]) ? m[1] : resolve(root, m[1]);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function resolveRef(gitDir, ref) {
|
|
26
|
+
const loose = read(join(gitDir, ref));
|
|
27
|
+
if (loose && SHA_RE.test(loose)) return loose;
|
|
28
|
+
const commonRel = read(join(gitDir, 'commondir'));
|
|
29
|
+
const common = commonRel ? (isAbsolute(commonRel) ? commonRel : resolve(gitDir, commonRel)) : null;
|
|
30
|
+
if (common) {
|
|
31
|
+
const c = read(join(common, ref));
|
|
32
|
+
if (c && SHA_RE.test(c)) return c;
|
|
33
|
+
}
|
|
34
|
+
for (const d of [gitDir, common].filter(Boolean)) {
|
|
35
|
+
const packed = read(join(d, 'packed-refs')) || '';
|
|
36
|
+
for (const line of packed.split('\n')) {
|
|
37
|
+
const [sha, name] = line.trim().split(/\s+/);
|
|
38
|
+
if (name === ref && SHA_RE.test(sha)) return sha;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** cliDir = the CLI package dir (holds package.json); its parent may be the git root. */
|
|
45
|
+
export function readInstalledBuild(cliDir) {
|
|
46
|
+
try {
|
|
47
|
+
for (const root of [cliDir, dirname(cliDir)]) {
|
|
48
|
+
const gd = gitDirFor(root);
|
|
49
|
+
if (!gd) continue;
|
|
50
|
+
const head = read(join(gd, 'HEAD'));
|
|
51
|
+
if (!head) continue;
|
|
52
|
+
if (SHA_RE.test(head)) return head;
|
|
53
|
+
const m = /^ref:\s*(\S+)$/.exec(head);
|
|
54
|
+
if (m) { const sha = resolveRef(gd, m[1]); if (sha) return sha; }
|
|
55
|
+
}
|
|
56
|
+
const pkg = JSON.parse(readFileSync(join(cliDir, 'package.json'), 'utf-8'));
|
|
57
|
+
return pkg && pkg.version ? `v${pkg.version}` : null;
|
|
58
|
+
} catch { return null; }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** The CLI package this module was loaded from (cli/lib/core -> cli). */
|
|
62
|
+
export const CLI_DIR = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..');
|