quoxcli 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +35 -0
- package/README.md +142 -2
- package/bin/quox.js +292 -0
- package/bin/quoxon.js +8 -0
- package/lib/api/endpoints/admin.js +125 -0
- package/lib/api/endpoints/aee.js +38 -0
- package/lib/api/endpoints/agent-attach.js +126 -0
- package/lib/api/endpoints/agents.js +56 -0
- package/lib/api/endpoints/assistants.js +50 -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/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 +54 -0
- package/lib/api/endpoints/consent.js +26 -0
- package/lib/api/endpoints/contactsq.js +66 -0
- package/lib/api/endpoints/conversations.js +32 -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 +32 -0
- package/lib/api/endpoints/file.js +20 -0
- package/lib/api/endpoints/files.js +26 -0
- package/lib/api/endpoints/github.js +21 -0
- package/lib/api/endpoints/governance.js +43 -0
- package/lib/api/endpoints/hat.js +36 -0
- package/lib/api/endpoints/inbox.js +32 -0
- package/lib/api/endpoints/inboxq.js +120 -0
- package/lib/api/endpoints/index.js +228 -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 +75 -0
- package/lib/api/endpoints/mfa.js +32 -0
- package/lib/api/endpoints/mon.js +178 -0
- package/lib/api/endpoints/notesq.js +43 -0
- package/lib/api/endpoints/objectives.js +62 -0
- package/lib/api/endpoints/orgs.js +38 -0
- package/lib/api/endpoints/plugins.js +134 -0
- package/lib/api/endpoints/powers.js +75 -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 +114 -0
- package/lib/api/endpoints/quoxseo.js +108 -0
- package/lib/api/endpoints/reach.js +47 -0
- package/lib/api/endpoints/runs.js +38 -0
- package/lib/api/endpoints/safety.js +46 -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 +180 -0
- package/lib/api/endpoints/sso.js +67 -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 +70 -0
- package/lib/api/endpoints/user-library.js +41 -0
- package/lib/api/endpoints/users.js +20 -0
- package/lib/api/endpoints/v1.js +499 -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 +40 -0
- package/lib/api/endpoints/webhooks.js +46 -0
- package/lib/api/endpoints/workflows.js +162 -0
- package/lib/api/endpoints/x.js +24 -0
- package/lib/api/endpoints.js +15 -0
- package/lib/commands/admin.js +359 -0
- package/lib/commands/aee.js +99 -0
- package/lib/commands/agent.js +201 -0
- package/lib/commands/agentAttach.js +1440 -0
- package/lib/commands/approvals.js +47 -0
- package/lib/commands/assistant.js +114 -0
- package/lib/commands/auth.js +458 -0
- package/lib/commands/awareness.js +88 -0
- package/lib/commands/backup.js +373 -0
- package/lib/commands/brain.js +994 -0
- package/lib/commands/budget.js +241 -0
- package/lib/commands/build.js +156 -0
- package/lib/commands/calendar.js +216 -0
- package/lib/commands/capabilities.js +34 -0
- package/lib/commands/chat.js +240 -0
- package/lib/commands/claude.js +354 -0
- package/lib/commands/config-cmd.js +106 -0
- package/lib/commands/consent.js +84 -0
- package/lib/commands/contacts.js +967 -0
- package/lib/commands/contactsSelftest.js +132 -0
- package/lib/commands/conversation.js +74 -0
- package/lib/commands/department.js +75 -0
- package/lib/commands/dev.js +620 -0
- package/lib/commands/devResident.js +314 -0
- package/lib/commands/devSupervisor.js +1050 -0
- package/lib/commands/discord.js +96 -0
- package/lib/commands/doctor.js +181 -0
- package/lib/commands/domain.js +114 -0
- package/lib/commands/done.js +277 -0
- package/lib/commands/engagement.js +586 -0
- package/lib/commands/entity.js +119 -0
- package/lib/commands/facebook.js +212 -0
- package/lib/commands/file.js +128 -0
- package/lib/commands/fleet.js +882 -0
- package/lib/commands/governance.js +638 -0
- package/lib/commands/gripe.js +324 -0
- package/lib/commands/hat.js +205 -0
- package/lib/commands/helpers.js +79 -0
- package/lib/commands/inbox.js +122 -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 +280 -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 +591 -0
- package/lib/commands/mail.js +531 -0
- package/lib/commands/memory.js +284 -0
- package/lib/commands/mon.js +514 -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 +92 -0
- package/lib/commands/objective.js +229 -0
- package/lib/commands/onboard.js +328 -0
- package/lib/commands/open.js +56 -0
- package/lib/commands/org.js +266 -0
- package/lib/commands/plan.js +906 -0
- package/lib/commands/plugin-doctor.js +1091 -0
- package/lib/commands/plugin.js +539 -0
- package/lib/commands/policy.js +78 -0
- package/lib/commands/powers.js +296 -0
- package/lib/commands/prompt.js +350 -0
- package/lib/commands/qlarity.js +690 -0
- package/lib/commands/quoxbox.js +270 -0
- package/lib/commands/quoxchat.js +266 -0
- package/lib/commands/quoxseo.js +340 -0
- package/lib/commands/reach.js +158 -0
- package/lib/commands/role.js +286 -0
- package/lib/commands/run.js +132 -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/service.js +89 -0
- package/lib/commands/settings.js +99 -0
- package/lib/commands/setup.js +543 -0
- package/lib/commands/skillManifest.js +113 -0
- package/lib/commands/skillRightsFormat.js +38 -0
- package/lib/commands/skills.js +644 -0
- package/lib/commands/slot.js +1198 -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 +140 -0
- package/lib/commands/tg.js +240 -0
- package/lib/commands/tiktok.js +218 -0
- package/lib/commands/tool.js +216 -0
- package/lib/commands/trace.js +525 -0
- package/lib/commands/trigger.js +128 -0
- package/lib/commands/vault.js +1424 -0
- package/lib/commands/voice.js +182 -0
- package/lib/commands/volt.js +528 -0
- package/lib/commands/watch.js +115 -0
- package/lib/commands/webhook.js +137 -0
- package/lib/commands/workflow.js +503 -0
- package/lib/commands/x.js +439 -0
- package/lib/core/actingAs.js +136 -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/auth.js +350 -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/client.js +584 -0
- package/lib/core/completions.js +163 -0
- package/lib/core/config.js +551 -0
- package/lib/core/confirm.js +37 -0
- package/lib/core/deeplinks.js +76 -0
- package/lib/core/doneEngineFetch.js +219 -0
- package/lib/core/errors.js +132 -0
- package/lib/core/global-flags.js +90 -0
- package/lib/core/governedSession.js +402 -0
- package/lib/core/lazyCommands.js +119 -0
- package/lib/core/liveSessionsReport.js +112 -0
- package/lib/core/org-override.js +52 -0
- package/lib/core/output.js +239 -0
- package/lib/core/prodEnv.js +7 -0
- package/lib/core/quoxglyph.js +158 -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 +104 -0
- package/lib/core/sessionHeartbeat.js +192 -0
- package/lib/core/sessionsOverview.js +160 -0
- package/lib/core/slotKeeper.js +282 -0
- package/lib/core/supervisorEngine.js +864 -0
- package/lib/core/systemdInstaller.js +256 -0
- package/lib/core/version.js +87 -0
- package/lib/core/websiteSession.js +148 -0
- package/lib/lucid/LucidIntro.jsx +105 -0
- package/lib/lucid/blind.js +71 -0
- package/lib/lucid/deck.js +32 -0
- package/lib/lucid/fmt.js +139 -0
- package/lib/lucid/sitrep.js +173 -0
- package/lib/plugins/loader.js +93 -0
- package/lib/quoxon/activity.js +104 -0
- package/lib/quoxon/api.js +473 -0
- package/lib/quoxon/app.js +1262 -0
- package/lib/quoxon/capabilities.js +75 -0
- package/lib/quoxon/commands.js +154 -0
- package/lib/quoxon/connect.js +467 -0
- package/lib/quoxon/connectCard.js +28 -0
- package/lib/quoxon/context.js +68 -0
- package/lib/quoxon/copy.js +33 -0
- package/lib/quoxon/demo.fixtures.js +24 -0
- package/lib/quoxon/demo.js +35 -0
- package/lib/quoxon/egg.js +36 -0
- package/lib/quoxon/events.js +458 -0
- package/lib/quoxon/gallery.js +223 -0
- package/lib/quoxon/indicator.js +193 -0
- package/lib/quoxon/intent.js +41 -0
- package/lib/quoxon/keys.js +121 -0
- package/lib/quoxon/main.js +244 -0
- package/lib/quoxon/markdown.js +317 -0
- package/lib/quoxon/model.js +205 -0
- package/lib/quoxon/motion/clock.js +69 -0
- package/lib/quoxon/motion/color.js +35 -0
- package/lib/quoxon/motion/frame.js +14 -0
- package/lib/quoxon/motion/reveal.js +54 -0
- package/lib/quoxon/motion/ring.js +79 -0
- package/lib/quoxon/objects/agent.js +61 -0
- package/lib/quoxon/objects/crystal.js +100 -0
- package/lib/quoxon/objects/fetch.js +170 -0
- package/lib/quoxon/objects/index.js +85 -0
- package/lib/quoxon/objects/ladder.js +71 -0
- package/lib/quoxon/objects/memory.js +44 -0
- package/lib/quoxon/objects/model.js +118 -0
- package/lib/quoxon/objects/proof.js +110 -0
- package/lib/quoxon/objects/skill.js +105 -0
- package/lib/quoxon/objects/view.js +76 -0
- package/lib/quoxon/objects/workflow.js +119 -0
- package/lib/quoxon/observers.js +42 -0
- package/lib/quoxon/onboarding/copy.js +235 -0
- package/lib/quoxon/onboarding/credential.js +95 -0
- package/lib/quoxon/onboarding/detect.js +22 -0
- package/lib/quoxon/onboarding/finish.js +119 -0
- package/lib/quoxon/onboarding/index.js +67 -0
- package/lib/quoxon/onboarding/installRunner.js +225 -0
- package/lib/quoxon/onboarding/intent.js +53 -0
- package/lib/quoxon/onboarding/journey.js +73 -0
- package/lib/quoxon/onboarding/preflight.js +142 -0
- package/lib/quoxon/onboarding/runner.js +58 -0
- package/lib/quoxon/onboarding/view.js +625 -0
- package/lib/quoxon/print.js +94 -0
- package/lib/quoxon/qart.js +379 -0
- package/lib/quoxon/qglyph.js +143 -0
- package/lib/quoxon/qhello.js +58 -0
- package/lib/quoxon/qmotion.js +111 -0
- package/lib/quoxon/render.js +648 -0
- package/lib/quoxon/roster.js +221 -0
- package/lib/quoxon/route.js +38 -0
- package/lib/quoxon/rules.js +130 -0
- package/lib/quoxon/session.js +68 -0
- package/lib/quoxon/skills.js +30 -0
- package/lib/quoxon/slash/compact.js +90 -0
- package/lib/quoxon/slash/ledger.js +83 -0
- package/lib/quoxon/slash/listView.js +28 -0
- package/lib/quoxon/slash/palette.js +104 -0
- package/lib/quoxon/slash/paletteController.js +59 -0
- package/lib/quoxon/slash/panels.js +101 -0
- package/lib/quoxon/slash/picker.js +38 -0
- package/lib/quoxon/slash/restart.js +144 -0
- package/lib/quoxon/slash/resume.js +59 -0
- package/lib/quoxon/slash/settings.js +50 -0
- package/lib/quoxon/sound/index.js +186 -0
- package/lib/quoxon/sound/mapping.js +119 -0
- package/lib/quoxon/sound/output.js +52 -0
- package/lib/quoxon/sound/synth.js +122 -0
- package/lib/quoxon/term.js +106 -0
- package/lib/quoxon/textBuffer.js +242 -0
- package/lib/quoxon/theme.js +253 -0
- package/lib/quoxon/transcript.js +150 -0
- package/lib/quoxon/web/qface.js +81 -0
- package/lib/quoxon/welcome.js +52 -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/InboxView.jsx +228 -0
- package/lib/tui/views/LucidDeck.jsx +727 -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 +72 -4
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* /capabilities and the K2 offer helper. Pure: everything comes from the server's
|
|
3
|
+
* GET /api/v1/capabilities answer (QUOXON E1), which derives each availability from
|
|
4
|
+
* real health, licence, install and provider signals. This module never decides a
|
|
5
|
+
* capability exists; when the server cannot answer it says so and claims nothing.
|
|
6
|
+
*
|
|
7
|
+
* `res` is { ok:true, capabilities } or { ok:false, status?, missing?, error? }.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const norm = (s) => String(s || '').trim().toLowerCase();
|
|
11
|
+
|
|
12
|
+
/** -> the capability matching an id, a provider short name, or a display name; else null. */
|
|
13
|
+
export function findCapability(query, res) {
|
|
14
|
+
if (!res?.ok || !Array.isArray(res.capabilities)) return null;
|
|
15
|
+
const q = norm(query);
|
|
16
|
+
if (!q) return null;
|
|
17
|
+
return res.capabilities.find(c => norm(c.id) === q)
|
|
18
|
+
|| res.capabilities.find(c => norm(c.id) === `provider.${q}`)
|
|
19
|
+
|| res.capabilities.find(c => norm(c.name) === q || norm(c.name).split(/\s+\(/)[0] === q)
|
|
20
|
+
|| null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* K2: the honest one-line offer for a gap, or null when there is no gap (or we cannot tell).
|
|
25
|
+
* Offers a place to set it up; never asks for a secret in the conversation.
|
|
26
|
+
*/
|
|
27
|
+
export function offerFor(capabilityId, res) {
|
|
28
|
+
const c = findCapability(capabilityId, res);
|
|
29
|
+
if (!c) return null;
|
|
30
|
+
const name = c.name || c.id;
|
|
31
|
+
switch (c.availability) {
|
|
32
|
+
case 'installed': return null;
|
|
33
|
+
case 'planned': return `Ⓠ ${name} is planned, not built yet.`;
|
|
34
|
+
case 'requires_setup': {
|
|
35
|
+
const why = c.reason ? ` (${c.reason})` : '';
|
|
36
|
+
if (!c.setup) return `Ⓠ ${name} isn't set up yet${why}.`;
|
|
37
|
+
if (c.permissions_ok === false) return `Ⓠ ${name} isn't set up yet${why}. An org admin can set it up: ${String(c.setup).replace(/ \(ask an org admin\)$/, '')}`;
|
|
38
|
+
return `Ⓠ ${name} isn't set up yet${why}. Set it up now? ${c.setup}`;
|
|
39
|
+
}
|
|
40
|
+
case 'unavailable':
|
|
41
|
+
return `Ⓠ ${name} isn't available on this Quox${c.reason ? `: ${c.reason}` : ''}.`;
|
|
42
|
+
default: return null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** -> [[text, tone?]] for /capabilities. */
|
|
47
|
+
export function capabilityLines(res) {
|
|
48
|
+
if (!res?.ok || !Array.isArray(res.capabilities)) {
|
|
49
|
+
if (res?.missing) return [['This Quox does not report its capabilities yet (no /api/v1/capabilities route). Nothing is assumed.', 'warn']];
|
|
50
|
+
return [[`Could not read capabilities: ${res?.error || 'no answer'}. Nothing is assumed.`, 'warn']];
|
|
51
|
+
}
|
|
52
|
+
const caps = res.capabilities;
|
|
53
|
+
const of = (a) => caps.filter(c => c.availability === a);
|
|
54
|
+
const out = [['What this Quox can do here:']];
|
|
55
|
+
const installed = of('installed');
|
|
56
|
+
for (const c of installed) out.push([`● ${c.name} ${c.intent}`, 'ok']);
|
|
57
|
+
if (!installed.length) out.push([' nothing is ready yet']);
|
|
58
|
+
const setup = of('requires_setup');
|
|
59
|
+
if (setup.length) {
|
|
60
|
+
out.push(['Needs setup:']);
|
|
61
|
+
for (const c of setup) out.push([`◐ ${c.name} ${c.reason || 'needs setup'}${c.setup ? ` · ${c.setup}` : ''}`, 'warn']);
|
|
62
|
+
}
|
|
63
|
+
const off = of('unavailable');
|
|
64
|
+
if (off.length) {
|
|
65
|
+
out.push(['Not available here:']);
|
|
66
|
+
for (const c of off) out.push([`○ ${c.name} ${c.reason || 'unavailable'}${c.setup ? ` · ${c.setup}` : ''}`]);
|
|
67
|
+
}
|
|
68
|
+
const planned = of('planned');
|
|
69
|
+
if (planned.length) {
|
|
70
|
+
out.push(['Planned (not built yet):']);
|
|
71
|
+
for (const c of planned) out.push([`· ${c.name} ${c.intent}`]);
|
|
72
|
+
}
|
|
73
|
+
out.push([' /capabilities <name> for one, e.g. /capabilities workflows']);
|
|
74
|
+
return out;
|
|
75
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The single registry behind /help and slash-command dispatch. Anything shown
|
|
3
|
+
* as active here is wired in app.js; planned entries are listed dim under
|
|
4
|
+
* "Coming" and refuse to run. Add a command here first, or it does not exist.
|
|
5
|
+
*/
|
|
6
|
+
export const GROUPS = ['Talk', 'Approvals', 'Skills', 'Conversation', 'Connect', 'Verbose', 'Context', 'Awareness'];
|
|
7
|
+
|
|
8
|
+
export const REGISTRY = [
|
|
9
|
+
// Talk (keys)
|
|
10
|
+
{ id: 'type', kind: 'key', group: 'Talk', usage: 'just type', desc: 'ask Quox anything; CommanderQ routes it to the right agent', status: 'active' },
|
|
11
|
+
{ id: 'enter', kind: 'key', group: 'Talk', usage: 'Enter', desc: 'send; while Quox works, steer the running turn if this server supports it, else queue it', status: 'active',
|
|
12
|
+
detail: 'Idle: sends. During a turn: steers when the server supports it (shown here once known), delivered at the next model boundary (never kills a running tool). If the server cannot steer, or the turn already finished, it is queued instead and you are told.' },
|
|
13
|
+
{ id: 'tab', kind: 'key', group: 'Talk', usage: 'Tab', desc: 'queue your message to run after this turn', status: 'active',
|
|
14
|
+
detail: 'Queued messages show above the composer. Up (empty composer) pulls the last one back to edit. After an interrupt they wait; press Enter on an empty composer to send the next one.' },
|
|
15
|
+
{ id: 'esc', kind: 'key', group: 'Talk', usage: 'Esc', desc: 'ask the server to stop the turn (idle: Esc Esc clears the draft to history)', status: 'active',
|
|
16
|
+
detail: 'Asks the server to stop before the next model call or tool; you see "stopping" until the server confirms. A tool already dispatched finishes and is reported, never hidden. Until the server route exists the stream is aborted locally and you are told work already sent may still finish.' },
|
|
17
|
+
{ id: 'newline', kind: 'key', group: 'Talk', usage: 'Shift+Enter / Ctrl+J', desc: 'new line in the composer (a trailing \\ then Enter also works)', status: 'active' },
|
|
18
|
+
{ id: 'editor', kind: 'key', group: 'Talk', usage: 'Ctrl+G', desc: 'edit the draft in $EDITOR', status: 'active' },
|
|
19
|
+
{ id: 'stash', kind: 'key', group: 'Talk', usage: 'Ctrl+S', desc: 'stash the draft; on an empty composer, restore it', status: 'active' },
|
|
20
|
+
{ id: 'undo', kind: 'key', group: 'Talk', usage: 'Ctrl+_', desc: 'undo in the composer', status: 'active' },
|
|
21
|
+
{ id: 'paste', kind: 'key', group: 'Talk', usage: 'paste', desc: 'long pastes collapse to [Pasted text #N +L lines] and expand on send', status: 'active' },
|
|
22
|
+
{ id: 'ctrlc', kind: 'key', group: 'Talk', usage: 'Ctrl+C', desc: 'clear the draft; during a turn interrupt; twice when idle quits', status: 'active' },
|
|
23
|
+
// Approvals
|
|
24
|
+
{ id: 'approvals', kind: 'command', group: 'Approvals', usage: '/approvals', desc: 'list what is waiting for you', server: true, cap: 'approvals', status: 'active' },
|
|
25
|
+
{ id: 'approve', kind: 'command', group: 'Approvals', usage: '/approve N', desc: 'approve item N from the list', server: true, cap: 'approvals', status: 'active',
|
|
26
|
+
detail: 'Run /approvals first. Mid-turn approval cards also take a (approve), d (deny), o (open); they arm after 300 ms and never default to approve.' },
|
|
27
|
+
{ id: 'deny', kind: 'command', group: 'Approvals', usage: '/deny N', desc: 'deny item N from the list', server: true, cap: 'approvals', status: 'active' },
|
|
28
|
+
// Skills and rules
|
|
29
|
+
{ id: 'skills', kind: 'command', group: 'Skills', usage: '/skills [name]', desc: 'list your org\'s governed skills, or show one as a card', needs: ['skills'], cap: 'skills', status: 'active',
|
|
30
|
+
detail: 'Lists your org skills (reusable procedures an agent follows; not Crystals, which are deterministic replays) with edition and one-line description. /skills <name> shows its card: purpose, version and review state, tests (results only when run-tests recorded them), the agents it is for, where it came from, recorded use, and how to run it.' },
|
|
31
|
+
{ id: 'skill', kind: 'command', group: 'Skills', usage: '/skill <name> [args]', desc: 'ask Quox to run a skill (governed: approvals still apply)', server: true, cap: 'skills', status: 'active',
|
|
32
|
+
detail: 'Sends "Run the skill <name> with: <args>" as a normal turn, so CommanderQ runs it through the usual governed path. Nothing is executed from here, and approval cards work as always.' },
|
|
33
|
+
{ id: 'rules', kind: 'command', group: 'Skills', usage: '/rules [files|off|on|N]', desc: 'which rules win: advisory QUOX.md, the dev pack, enforced server policy', status: 'active',
|
|
34
|
+
detail: '/rules shows the precedence: QUOX.md and the dev pack only guide; armed governance policies on the server are enforced and win. /rules files shows the QUOX.md text. QUOX.md in this directory and parents up to the git root, plus ~/.quox/QUOX.md, are sent with each turn as your rules. World-writable files and symlinks leaving your home or repo are ignored. /rules N shows page N.' },
|
|
35
|
+
// Conversation
|
|
36
|
+
{ id: 'clear', kind: 'command', group: 'Conversation', usage: '/clear', desc: 'fresh conversation and a clear screen; rules and memory kept, /resume goes back', status: 'active', aliases: ['new', 'reset'],
|
|
37
|
+
detail: 'Clears the screen and starts a new conversation. Your QUOX.md rules, attached agent, model choice and Quox memory stay as they are. The previous conversation is kept on the server: /resume lists it.' },
|
|
38
|
+
{ id: 'resume', kind: 'command', group: 'Conversation', usage: '/resume [id|name]', desc: 'pick a recent conversation and carry on where it left off', status: 'active', needs: ['conversations', 'conversationTurns'],
|
|
39
|
+
detail: 'Alone: a picker of your recent conversations (title, agent, age); Up/Down and Enter resume, Esc cancels. With an id (or the start of one) or a /rename name it resumes directly. The last turns are shown as history and your next message continues that conversation. Also at launch: quox --resume [id|name] or quox --conversation <id>.' },
|
|
40
|
+
{ id: 'compact', kind: 'command', group: 'Conversation', usage: '/compact [show]', desc: 'summarise the conversation on the server, keeping decisions', status: 'active', needs: ['compactConversation'],
|
|
41
|
+
detail: 'The server summarises this conversation with your AI provider, keeping decisions, and the summary becomes the start of the conversation for later turns. Shows the token change and the first lines of the summary; /compact show prints all of it. Refused while a turn runs, and when the org has not given AI processing consent. Asking "compact this conversation" in words only suggests it.' },
|
|
42
|
+
{ id: 'help', kind: 'command', group: 'Conversation', usage: '/help [command]', desc: 'this reference, or detail for one command or key', status: 'active' },
|
|
43
|
+
{ id: 'note', kind: 'command', group: 'Conversation', usage: '/note <text>', desc: 'jot an observation for the dev observer (also: // text); not sent to Quox', status: 'active',
|
|
44
|
+
detail: 'Records your text in the dev transcript only: not sent to the model or the server, no turn, not in chat history. Needs dev transcripts on (touch ~/.config/quox/dev-transcripts). Up to 2000 characters.' },
|
|
45
|
+
{ id: 'copy', kind: 'command', group: 'Conversation', usage: '/copy [N|code]', desc: 'copy the last answer (raw markdown) to the clipboard; N = Nth-last, code = last code block', status: 'active',
|
|
46
|
+
detail: 'Uses the OSC 52 terminal escape (works over SSH in most terminals; wrapped for tmux). Needs a terminal that allows OSC 52. Mouse selection is untouched: select and copy with your terminal as usual.' },
|
|
47
|
+
{ id: 'eye', kind: 'command', group: 'Conversation', usage: '/eye', desc: 'the Q opens its eye and blinks (the Dragon\'s Eye)', status: 'active',
|
|
48
|
+
detail: 'A small Easter egg. Under reduced motion (QUOX_REDUCED_MOTION=1) it shows a still open eye instead.' },
|
|
49
|
+
{ id: 'sound', kind: 'command', group: 'Conversation', usage: '/sound [profile|test]', desc: 'earcons for approvals, failures and long turns: Silent | Minimal | Operational | Full', status: 'active',
|
|
50
|
+
detail: 'Same setting as the dashboard (your account\'s soundProfile). Minimal (default) sounds for approvals, critical alerts and failures; Operational adds a short tick when a turn over 20 s finishes or the terminal is in the background. Over SSH only the terminal bell rings, for approvals and critical alerts. QUOX_SOUND=off mutes this terminal; --print never makes sound.' },
|
|
51
|
+
{ id: 'about', kind: 'command', group: 'Conversation', usage: '/about', desc: 'who we are, terms, privacy, licence and docs links', status: 'active' },
|
|
52
|
+
{ id: 'quit', kind: 'command', group: 'Conversation', usage: '/quit', desc: 'leave; finished work is kept and /resume picks the conversation up', status: 'active', aliases: ['exit'],
|
|
53
|
+
detail: 'Idle: leaves at once; the conversation stays on the server for /resume (or quox --resume). During a turn it asks first, because leaving disconnects the turn and the server stops it before its next step (a tool already running finishes and is recorded). /quit again within 5 s leaves anyway.' },
|
|
54
|
+
{ id: 'restart', kind: 'command', group: 'Conversation', usage: '/restart', desc: 'restart into the latest installed quox and resume this conversation', status: 'active',
|
|
55
|
+
detail: 'Re-runs the quox on your PATH in this terminal with the same arguments and profile, plus --resume for this conversation. During a turn it asks first: restarting disconnects the turn and the server stops it before its next step (this server cannot reattach a running turn yet); /restart again within 5 s goes ahead. When a newer build is installed than the one running, a dim line says so (checked at most once a minute, no network).' },
|
|
56
|
+
{ id: 'gripe', kind: 'command', group: 'Conversation', usage: '/gripe <text>', desc: 'file a GitHub issue through the GRIPE agent; shows it first, /gripe! files at once', needs: ['gripe'], status: 'active', aliases: ['gripe!'],
|
|
57
|
+
detail: 'The same governed path as `quox gripe`: the GRIPE agent files the issue through your org\'s GitHub connector (default repo quoxai/quox). /gripe <text> shows what would be filed and asks; /gripe! (alone, within 2 minutes) files it, or /gripe! <text> files straight away. The issue link is shown when one comes back; with no link it says so and treats it as not filed.' },
|
|
58
|
+
{ id: 'sessions', kind: 'command', group: 'Conversation', usage: '/sessions [all]', desc: 'your recent conversations; /sessions all shows everything live in your org', needs: ['conversations'], status: 'active',
|
|
59
|
+
detail: '/sessions all is the same overview as `quox sessions`: every live tmux session, conversation, held slot and running objective, loop or workflow in your org, grouped by agent, with how to attach. Bare /sessions lists recent conversations from the server. Names set with /rename are kept on this machine (~/.config/quox/sessions.json) because the server has no rename route yet.' },
|
|
60
|
+
{ id: 'rename', kind: 'command', group: 'Conversation', usage: '/rename [name]', desc: 'name this session (shown in the top rule); alone shows the current name', status: 'active',
|
|
61
|
+
detail: 'Also settable at launch with quox -n <name>. The name is kept on this machine, keyed by conversation, and shown in /sessions.' },
|
|
62
|
+
{ id: 'slot', kind: 'command', group: 'Conversation', usage: '/slot <name>', desc: 'give this session a slot address (checks out the slot)', needs: ['checkoutSlot'], cap: 'slots', status: 'active',
|
|
63
|
+
detail: 'Checks out the slot, creating it if needed, as `quox slot checkout <name> --create --session <session>` does; typing it is your consent. Discord replies are not relayed into this window yet (no slot wait loop here).' },
|
|
64
|
+
{ id: 'attach', kind: 'command', group: 'Conversation', usage: '/attach [agent]', desc: 'send your turns to a specific agent; alone shows the current one', needs: ['agents'], cap: 'agents', status: 'active',
|
|
65
|
+
detail: 'The agent name is checked against your org\'s agent list. Later turns go to that agent (the chat stream assistant field) until /detach.' },
|
|
66
|
+
{ id: 'detach', kind: 'command', group: 'Conversation', usage: '/detach', desc: 'back to CommanderQ', status: 'active' },
|
|
67
|
+
{ id: 'peek', kind: 'command', group: 'Conversation', usage: '/peek <id>', desc: 'look up an envelope, task or agent by id', status: 'planned' },
|
|
68
|
+
{ id: 'aside', kind: 'command', group: 'Conversation', usage: '/aside', desc: 'a read-only side question', status: 'planned' },
|
|
69
|
+
// Connect
|
|
70
|
+
{ id: 'connect', kind: 'command', group: 'Connect', usage: '/connect [provider]', desc: 'see what is connected; /connect openai adds a key safely', needs: ['connections'], cap: 'vault', status: 'active',
|
|
71
|
+
detail: 'Alone: AI providers (OpenAI, Claude API, Ollama) and the integrations in your org vault, with real status from the server; anything it cannot read shows ? unknown. /connect openai (or anthropic) opens a secure card: paste the key, Enter tests it with the provider and saves it to your org vault as the default; Esc cancels. Keys typed there never reach chat, history or transcripts. A key pasted into the composer is never sent.' },
|
|
72
|
+
{ id: 'capabilities', kind: 'command', group: 'Connect', usage: '/capabilities [name]', desc: 'what this Quox can do here: ready, needs setup, not available, planned', status: 'active',
|
|
73
|
+
detail: 'Asks the server (GET /api/v1/capabilities), which checks real service health, your plan, plugin install state and connected providers. Each gap says why and how to set it up; /capabilities <name> gives the one-line offer for one. If the server cannot answer, nothing is assumed.' },
|
|
74
|
+
// Verbose
|
|
75
|
+
{ id: 'verbose', kind: 'command', group: 'Verbose', usage: '/verbose off|on|full', desc: 'protocol lines: off = receipts only, on = compact, full = adds thinking', status: 'active',
|
|
76
|
+
detail: 'on (default) shows compact AEE / AOCL / WARD lines as they happen. off collapses to the receipt line. full adds the thinking stream.' },
|
|
77
|
+
{ id: 'proof', kind: 'command', group: 'Verbose', usage: '/proof [envelope]', desc: 'the evidence chain for the last tool call: AEE, AOCL, tool, WARD', server: true, cap: 'receipts', status: 'active',
|
|
78
|
+
detail: 'Each link is read back from the server and drawn confirmed only when the read says so. WARD is the server-verified inclusion receipt; it can be slow on a large chain and is bounded, so a link may stay open.' },
|
|
79
|
+
{ id: 'reconcile', kind: 'command', group: 'Verbose', usage: '/reconcile', desc: 'check tool calls that ended with effect unknown against the server\'s record', server: true, cap: 'receipts', status: 'active' },
|
|
80
|
+
// Awareness
|
|
81
|
+
{ id: 'roster', kind: 'command', group: 'Awareness', usage: '/roster [all]', desc: 'show or hide the live roster under the status line; all includes background work', needs: ['roster'], status: 'active',
|
|
82
|
+
detail: 'The roster lists what needs you: pending approvals, then work you started (objectives, loops, manual workflows). Scheduled and event-driven workflows are hidden; background failures show once per workflow in the bar below. /roster all shows everything. Refreshed every 15 s from the server. Down on an empty composer focuses it; Enter peeks, s asks to stop (y confirms), Esc returns. A source the server cannot answer shows nothing and is named here.' },
|
|
83
|
+
{ id: 'workflow', kind: 'command', group: 'Skills', usage: '/workflow <name|id|run>', desc: 'the step flow of a workflow\'s latest run (or one run): state, timings, human gates', server: true, cap: 'workflows', status: 'active',
|
|
84
|
+
detail: 'Steps come from the workflow definition and each state and duration from that run\'s recorded envelopes. A reached human gate shows amber. Enter on a workflow row in the roster shows the same flow.' },
|
|
85
|
+
{ id: 'crystal', kind: 'command', group: 'Skills', usage: '/crystal <workflow>', desc: 'is this workflow eligible to become a Crystal? checked against the real gate', server: true, cap: 'crystals', status: 'active',
|
|
86
|
+
detail: 'Computed from the workflow\'s recorded runs with quoxflow\'s crystalliser rule: at least 3 runs, at least 80% successful, one action sequence. Says how many more successful runs are needed.' },
|
|
87
|
+
{ id: 'agents', kind: 'command', group: 'Awareness', usage: '/agents <name>', desc: 'an agent\'s card: role, tools, slot, last action and its WARD witness', server: true, cap: 'agents', status: 'active' },
|
|
88
|
+
{ id: 'memory', kind: 'command', group: 'Awareness', usage: '/memory <query>', desc: 'facts Quox remembers, each with where it came from, age, trust and conflicts', server: true, cap: 'memory', status: 'active' },
|
|
89
|
+
{ id: 'observers', kind: 'command', group: 'Awareness', usage: '/observers', desc: 'LUCID situation, what changed since you last looked, what Quox records about its own learning', needs: ['observers'], cap: 'lucid', status: 'active',
|
|
90
|
+
detail: 'Facts only, read from persisted data: the LUCID situation (without moving your cursor), recent changes, lessons taught, and the reflect / learn / insight counters. Nothing is summarised by a model.' },
|
|
91
|
+
// Context
|
|
92
|
+
{ id: 'statusline', kind: 'key', group: 'Context', usage: 'status line', desc: 'profile · org · agent · model · mode, under the composer', status: 'active' },
|
|
93
|
+
{ id: 'status', kind: 'command', group: 'Context', usage: '/status', desc: 'profile, org, server and its health, model, agent, slot, session, version', status: 'active',
|
|
94
|
+
detail: 'The provider and model shown are what the server last reported running (turn.started), not what was asked for. Server health is checked live. Asking "what is my status" in words prints the same panel as a tip.' },
|
|
95
|
+
{ id: 'cost', kind: 'command', group: 'Context', usage: '/cost', desc: 'tokens and cost per model for this session, from real usage', status: 'active', aliases: ['usage'],
|
|
96
|
+
detail: 'Counts only what the server reported on turn.finished (input, output and cache tokens, cost when the provider gives one). Cost stays blank when the server did not report it, and says so; nothing is estimated. Asking "what is this costing" prints the same panel.' },
|
|
97
|
+
{ id: 'context', kind: 'command', group: 'Context', usage: '/context', desc: 'model, conversation tokens, rules, skills, memory and the attached agent', status: 'active',
|
|
98
|
+
detail: 'Conversation tokens are the sum the server reported for this conversation in this session. Skills and memory are real calls to your server; anything it cannot answer shows ? with the reason. Asking "how much context have we used" prints the same panel.' },
|
|
99
|
+
{ id: 'doctor', kind: 'command', group: 'Context', usage: '/doctor', desc: 'the quox doctor checks plus chat checks, as rows', status: 'active', needs: ['doctorChecks'],
|
|
100
|
+
detail: 'Runs the same checks as `quox doctor` (services, auth token, CLI version) in this process, then chat checks: the chat routes answer, a provider is connected, the capability contract.' },
|
|
101
|
+
{ id: 'config', kind: 'command', group: 'Context', usage: '/config', desc: 'settings: theme, motion, verbose, model; saved on this profile', status: 'active', aliases: ['settings'],
|
|
102
|
+
detail: 'An interactive card: Up/Down pick a setting, Left/Right or Space change it (saved at once to this CLI profile), Enter on Model opens /model, Esc closes. Theme replaces the env-only QUOX_THEME; if QUOX_THEME is set in your shell it still wins and the card says so.' },
|
|
103
|
+
{ id: 'profile', kind: 'command', group: 'Context', usage: '/profile', desc: 'switch profile or org without leaving', status: 'planned' },
|
|
104
|
+
{ id: 'model', kind: 'command', group: 'Context', usage: '/model [provider [model] [compact|full]|auto]', desc: 'see what is connected and choose the provider/model for your next turns', needs: ['connections'], status: 'active',
|
|
105
|
+
detail: 'Alone: auto, OpenAI, Claude API and Ollama with real status from your org vault (the same source as /connect). /model openai, /model openai gpt-5.4-mini, /model anthropic, /model auto (server policy). The choice is saved for this profile (no keys) and sent with each turn; the server decides, and the status line shows what it actually ran. A provider that is not connected is refused with a /connect offer; if the server runs something else, you are told once. quox --provider openai does the same for one run. A trailing compact or full picks the prompt profile: compact is a short system prompt for small or local models (the default on Ollama, LM Studio and vLLM), full is the default elsewhere; --prompt-profile does the same for one --print run.' },
|
|
106
|
+
{ id: 'mentions', kind: 'key', group: 'Context', usage: '@mention', desc: 'complete agents, hosts, tasks and receipts', status: 'planned' }
|
|
107
|
+
];
|
|
108
|
+
|
|
109
|
+
const norm = (s) => String(s || '').trim().toLowerCase().replace(/^\//, '');
|
|
110
|
+
|
|
111
|
+
export function findEntry(name) {
|
|
112
|
+
const n = norm(name);
|
|
113
|
+
if (!n) return null;
|
|
114
|
+
return REGISTRY.find(e => e.id === n || e.aliases?.includes(n) || norm(e.usage.split(/\s/)[0]) === n || e.usage.toLowerCase() === n) || null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** Slash commands only. */
|
|
118
|
+
export const commandNames = () => REGISTRY.filter(e => e.kind === 'command' && e.status === 'active').flatMap(e => ['/' + e.id, ...(e.aliases || []).map(a => '/' + a)]);
|
|
119
|
+
|
|
120
|
+
/** Pure help model: [{ kind: 'head'|'row'|'dim'|'gap'|'plain', key?, text? }]. */
|
|
121
|
+
const capView = (e, caps = {}) => {
|
|
122
|
+
if (e.id === 'enter' && caps.steer === false) return { ...e, desc: 'send; while Quox works, queue it (this server cannot steer a running turn)', detail: 'This server has no steer route: Enter during a turn queues your message as the next turn.' };
|
|
123
|
+
if (e.id === 'esc' && caps.interrupt === false) return { ...e, desc: 'disconnect from the turn (this server cannot stop it; idle: Esc Esc clears the draft)', detail: 'This server has no interrupt route: Esc aborts only your stream. Work already sent may still finish and be charged.' };
|
|
124
|
+
return e;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
export function helpModel(topic, caps = {}) {
|
|
128
|
+
if (topic) {
|
|
129
|
+
const e0 = findEntry(topic);
|
|
130
|
+
const e = e0 && capView(e0, caps);
|
|
131
|
+
if (!e) return [{ kind: 'plain', text: `No help for "${topic}". Try /help` }];
|
|
132
|
+
return [
|
|
133
|
+
{ kind: 'head', text: e.usage },
|
|
134
|
+
{ kind: 'plain', text: e.desc },
|
|
135
|
+
...(e.detail ? [{ kind: 'plain', text: e.detail }] : []),
|
|
136
|
+
...(e.status === 'planned' ? [{ kind: 'dim', text: 'Planned, not built yet.' }] : [])
|
|
137
|
+
];
|
|
138
|
+
}
|
|
139
|
+
const out = [];
|
|
140
|
+
for (const g of GROUPS) {
|
|
141
|
+
const active = REGISTRY.filter(e => e.group === g && e.status === 'active').map(e => capView(e, caps));
|
|
142
|
+
if (!active.length) continue;
|
|
143
|
+
if (out.length) out.push({ kind: 'gap' });
|
|
144
|
+
out.push({ kind: 'head', text: g });
|
|
145
|
+
for (const e of active) out.push({ kind: 'row', key: e.usage, text: e.desc });
|
|
146
|
+
}
|
|
147
|
+
const planned = REGISTRY.filter(e => e.status === 'planned');
|
|
148
|
+
if (planned.length) {
|
|
149
|
+
out.push({ kind: 'gap' }, { kind: 'head', text: 'Coming', dim: true });
|
|
150
|
+
for (const e of planned) out.push({ kind: 'dim', key: e.usage, text: e.desc });
|
|
151
|
+
}
|
|
152
|
+
out.push({ kind: 'gap' }, { kind: 'dim', text: '/help <command> for detail, e.g. /help esc' });
|
|
153
|
+
return out;
|
|
154
|
+
}
|