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,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preflight for Getting started: real checks, each bounded by a timeout, never sudo, never a write.
|
|
3
|
+
* Thresholds and ports are the installer's own (read from the repo, keep in step):
|
|
4
|
+
* scripts/preflight.sh MIN_RAM_GB=4, MIN_DISK_GB=10
|
|
5
|
+
* README (public mirror) "Plan for 8 GB of RAM and 30 GB of free disk"
|
|
6
|
+
* scripts/setup.sh needs docker (daemon reachable), docker compose v2, openssl; get.quox.ai needs git
|
|
7
|
+
* docker-compose.yml host ports below
|
|
8
|
+
*/
|
|
9
|
+
import { execFile } from 'node:child_process';
|
|
10
|
+
import { statfs } from 'node:fs/promises';
|
|
11
|
+
import { totalmem, homedir } from 'node:os';
|
|
12
|
+
import { createConnection } from 'node:net';
|
|
13
|
+
import { CHECK } from './copy.js';
|
|
14
|
+
|
|
15
|
+
export const MIN_DISK_GB = 10;
|
|
16
|
+
export const REC_DISK_GB = 30;
|
|
17
|
+
export const MIN_RAM_GB = 4;
|
|
18
|
+
export const REC_RAM_GB = 8;
|
|
19
|
+
/** Every host port docker-compose.yml publishes (80, 3000 and 9848 on all interfaces, the rest on loopback). */
|
|
20
|
+
export const PORTS = [80, 3000, 9848, 3100, 3101, 3102, 3103, 3104, 3105, 3106, 3107, 3108, 3110, 3200, 5432, 6333, 9849];
|
|
21
|
+
export const CHECK_IDS = ['docker', 'compose', 'tools', 'disk', 'ram', 'ports'];
|
|
22
|
+
|
|
23
|
+
/** execFile with a hard timeout; never throws. -> { code, stdout, stderr, missing } */
|
|
24
|
+
export function run(cmd, args, timeout = 6000) {
|
|
25
|
+
return new Promise((resolve) => {
|
|
26
|
+
let child;
|
|
27
|
+
try {
|
|
28
|
+
child = execFile(cmd, args, { timeout, killSignal: 'SIGKILL', windowsHide: true, maxBuffer: 1 << 20 }, (err, stdout, stderr) => {
|
|
29
|
+
resolve({ code: err ? (typeof err.code === 'number' ? err.code : 1) : 0, stdout: String(stdout || ''), stderr: String(stderr || ''), missing: err?.code === 'ENOENT', timedOut: Boolean(err?.killed) });
|
|
30
|
+
});
|
|
31
|
+
} catch (e) { resolve({ code: 1, stdout: '', stderr: String(e?.message || e), missing: e?.code === 'ENOENT' }); }
|
|
32
|
+
child?.stdin?.end?.();
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Is something listening on 127.0.0.1:port? A connect, not a bind: needs no privileges, works for port 80. */
|
|
37
|
+
export function portInUse(port, timeout = 400) {
|
|
38
|
+
return new Promise((resolve) => {
|
|
39
|
+
const s = createConnection({ host: '127.0.0.1', port });
|
|
40
|
+
const done = (v) => { s.destroy(); resolve(v); };
|
|
41
|
+
s.setTimeout(timeout, () => done(false));
|
|
42
|
+
s.once('connect', () => done(true));
|
|
43
|
+
s.once('error', () => done(false));
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const defaultDeps = () => ({
|
|
48
|
+
run,
|
|
49
|
+
portInUse,
|
|
50
|
+
statfs: (p) => statfs(p),
|
|
51
|
+
totalmem,
|
|
52
|
+
home: homedir()
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const gb = (bytes) => Math.floor(bytes / 1024 ** 3);
|
|
56
|
+
const row = (id, status, body, extra = {}) => ({ id, name: CHECK[id].name, status, body, ...extra });
|
|
57
|
+
|
|
58
|
+
export async function checkDocker(d) {
|
|
59
|
+
const v = await d.run('docker', ['--version'], 5000);
|
|
60
|
+
if (v.missing || v.code !== 0) return row('docker', 'fail', CHECK.docker.missing, { fix: CHECK.docker.missingFix, link: CHECK.docker.missingLink });
|
|
61
|
+
const ver = (/version\s+([0-9][\w.\-+]*)/i.exec(v.stdout) || [])[1] || '';
|
|
62
|
+
const info = await d.run('docker', ['info', '--format', '{{.ServerVersion}}'], 10000);
|
|
63
|
+
if (info.code === 0 && info.stdout.trim()) return row('docker', 'ok', CHECK.docker.ok(ver || info.stdout.trim()));
|
|
64
|
+
if (/permission denied/i.test(info.stderr)) return row('docker', 'fail', CHECK.docker.perm, { fix: CHECK.docker.permFix, link: CHECK.docker.link });
|
|
65
|
+
return row('docker', 'fail', CHECK.docker.down, { fix: CHECK.docker.downFix, link: CHECK.docker.link });
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export async function checkCompose(d) {
|
|
69
|
+
const r = await d.run('docker', ['compose', 'version', '--short'], 6000);
|
|
70
|
+
const v = r.stdout.trim();
|
|
71
|
+
if (r.code !== 0 || !v) return row('compose', 'fail', CHECK.compose.missing, { fix: CHECK.compose.missingFix, link: CHECK.compose.link });
|
|
72
|
+
const major = Number((/^v?(\d+)/.exec(v) || [])[1]);
|
|
73
|
+
if (major < 2) return row('compose', 'fail', CHECK.compose.old(v), { fix: CHECK.compose.missingFix, link: CHECK.compose.link });
|
|
74
|
+
return row('compose', 'ok', CHECK.compose.ok(v));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export async function checkTools(d) {
|
|
78
|
+
const [git, ssl] = await Promise.all([d.run('git', ['--version'], 4000), d.run('openssl', ['version'], 4000)]);
|
|
79
|
+
const missing = [git.code === 0 ? null : 'git', ssl.code === 0 ? null : 'openssl'].filter(Boolean);
|
|
80
|
+
if (missing.length) return row('tools', 'fail', CHECK.tools.missing(missing), { fix: CHECK.tools.fix(missing), link: CHECK.tools.link });
|
|
81
|
+
return row('tools', 'ok', CHECK.tools.ok);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export async function checkDisk(d) {
|
|
85
|
+
try {
|
|
86
|
+
const s = await d.statfs(d.home);
|
|
87
|
+
const free = gb(Number(s.bavail) * Number(s.bsize));
|
|
88
|
+
if (free < MIN_DISK_GB) return row('disk', 'fail', CHECK.disk.fail(free, MIN_DISK_GB), { fix: CHECK.disk.fix(MIN_DISK_GB), link: CHECK.disk.link });
|
|
89
|
+
if (free < REC_DISK_GB) return row('disk', 'warn', CHECK.disk.low(free, REC_DISK_GB));
|
|
90
|
+
return row('disk', 'ok', CHECK.disk.ok(free));
|
|
91
|
+
} catch (e) {
|
|
92
|
+
return row('disk', 'warn', `could not measure free space (${e?.code || 'error'})`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export async function checkRam(d) {
|
|
97
|
+
const total = Math.round(d.totalmem() / 1024 ** 3);
|
|
98
|
+
if (total < MIN_RAM_GB) return row('ram', 'fail', CHECK.ram.fail(total, MIN_RAM_GB), { fix: CHECK.ram.fix(MIN_RAM_GB), link: CHECK.ram.link });
|
|
99
|
+
if (total < REC_RAM_GB) return row('ram', 'warn', CHECK.ram.low(total, REC_RAM_GB));
|
|
100
|
+
return row('ram', 'ok', CHECK.ram.ok(total));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export async function checkPorts(d, ports = PORTS) {
|
|
104
|
+
const used = [];
|
|
105
|
+
await Promise.all(ports.map(async (p) => { if (await d.portInUse(p)) used.push(p); }));
|
|
106
|
+
used.sort((a, b) => a - b);
|
|
107
|
+
const quox = used.includes(3000) && used.includes(9848); // the dashboard and collector ports: most likely Quox itself
|
|
108
|
+
// Resuming an install this guide started: Quox's own ports being busy is expected, not a blocker.
|
|
109
|
+
if (used.length && quox && d.ownInstall) return row('ports', 'warn', CHECK.ports.ownInstall);
|
|
110
|
+
if (used.length) return row('ports', 'fail', CHECK.ports.busy(used), { fix: quox ? CHECK.ports.quoxFix : CHECK.ports.fix(used[0]), link: CHECK.ports.link });
|
|
111
|
+
return row('ports', 'ok', CHECK.ports.ok(ports.length));
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const CHECKS = { docker: checkDocker, compose: checkCompose, tools: checkTools, disk: checkDisk, ram: checkRam, ports: checkPorts };
|
|
115
|
+
|
|
116
|
+
/** Rows in their running state, before any result. */
|
|
117
|
+
export const pendingRows = () => CHECK_IDS.map(id => row(id, 'running', CHECK.running));
|
|
118
|
+
|
|
119
|
+
/** Run every check in parallel; onRow(row) fires as each finishes. -> rows in CHECK_IDS order. */
|
|
120
|
+
export async function runPreflight(deps = defaultDeps(), onRow = () => {}) {
|
|
121
|
+
const rows = await Promise.all(CHECK_IDS.map(async (id) => {
|
|
122
|
+
let r;
|
|
123
|
+
try { r = await CHECKS[id](deps); } catch (e) { r = row(id, 'fail', `check failed: ${e?.message || e}`, { fix: 'Press r to check again.', link: 'https://quox.ai/docs/setup' }); }
|
|
124
|
+
onRow(r);
|
|
125
|
+
return r;
|
|
126
|
+
}));
|
|
127
|
+
return rows;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export const preflightPassed = (rows) => rows.length > 0 && rows.every(r => r.status === 'ok' || r.status === 'warn');
|
|
131
|
+
|
|
132
|
+
/** Ollama on this machine? A 1 s GET of its model list; never throws. */
|
|
133
|
+
export async function detectOllama({ fetchImpl = globalThis.fetch, timeout = 1000 } = {}) {
|
|
134
|
+
if (!fetchImpl) return false;
|
|
135
|
+
const ac = new AbortController();
|
|
136
|
+
let t;
|
|
137
|
+
const late = new Promise((res) => { t = setTimeout(() => { ac.abort(); res(null); }, timeout); });
|
|
138
|
+
try {
|
|
139
|
+
const r = await Promise.race([fetchImpl('http://127.0.0.1:11434/api/tags', { signal: ac.signal }), late]);
|
|
140
|
+
return Boolean(r?.ok);
|
|
141
|
+
} catch { return false; } finally { clearTimeout(t); }
|
|
142
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Install runner interface (C2a). The view only ever talks to this shape:
|
|
3
|
+
*
|
|
4
|
+
* runner = {
|
|
5
|
+
* kind: 'dry-run' | 'real',
|
|
6
|
+
* stages: [{ id, label }], // fetch, configure, build, start, health
|
|
7
|
+
* run({ onEvent, signal, request }) -> Promise<{ ok, dashboardUrl?, failedStage?, error? }>
|
|
8
|
+
* }
|
|
9
|
+
* events: { type: 'stage', id, status: 'running' | 'ok' | 'fail', at, ms? }
|
|
10
|
+
* { type: 'log', line } // the real log tail (`v` shows it)
|
|
11
|
+
*
|
|
12
|
+
* The real runner (C2b) wraps get.quox.ai -> scripts/setup.sh and maps its "Step n/7" lines onto these stages.
|
|
13
|
+
* Only the dry run exists today: simulated, labelled, nothing downloaded, built or started.
|
|
14
|
+
*/
|
|
15
|
+
import { STAGES } from './copy.js';
|
|
16
|
+
|
|
17
|
+
export const STAGE_IDS = ['fetch', 'configure', 'build', 'start', 'health'];
|
|
18
|
+
export const stageList = () => STAGE_IDS.map(id => ({ id, label: STAGES[id] }));
|
|
19
|
+
|
|
20
|
+
const DRY_LOG = {
|
|
21
|
+
fetch: ['[dry run] would clone quox, quoxflow and quoxmcp'],
|
|
22
|
+
configure: ['[dry run] would generate .env secrets and a self-signed certificate'],
|
|
23
|
+
build: ['[dry run] would run: docker compose build'],
|
|
24
|
+
start: ['[dry run] would run: docker compose up -d'],
|
|
25
|
+
health: ['[dry run] would wait for every service health check']
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const wait = (ms, signal) => new Promise((res) => {
|
|
29
|
+
if (signal?.aborted) return res();
|
|
30
|
+
const t = setTimeout(done, ms);
|
|
31
|
+
function done() { clearTimeout(t); signal?.removeEventListener?.('abort', done); res(); }
|
|
32
|
+
signal?.addEventListener?.('abort', done, { once: true });
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
/** Dry run: walks the stages on a timer. `failAt` makes one stage fail (tests, demo of the failure path). */
|
|
36
|
+
export function createDryRunRunner({ stepMs = 450, failAt = null, now = () => Date.now(), dashboardUrl = 'https://localhost:3000' } = {}) {
|
|
37
|
+
return {
|
|
38
|
+
kind: 'dry-run',
|
|
39
|
+
stages: stageList(),
|
|
40
|
+
async run({ onEvent = () => {}, signal } = {}) {
|
|
41
|
+
for (const id of STAGE_IDS) {
|
|
42
|
+
if (signal?.aborted) return { ok: false, interrupted: true };
|
|
43
|
+
const t0 = now();
|
|
44
|
+
onEvent({ type: 'stage', id, status: 'running', at: t0 });
|
|
45
|
+
for (const line of DRY_LOG[id]) onEvent({ type: 'log', line });
|
|
46
|
+
await wait(stepMs, signal);
|
|
47
|
+
if (signal?.aborted) return { ok: false, interrupted: true };
|
|
48
|
+
if (failAt === id) {
|
|
49
|
+
onEvent({ type: 'log', line: `[dry run] simulated failure at ${id}` });
|
|
50
|
+
onEvent({ type: 'stage', id, status: 'fail', at: now(), ms: now() - t0 });
|
|
51
|
+
return { ok: false, failedStage: id, error: 'simulated failure (dry run)' };
|
|
52
|
+
}
|
|
53
|
+
onEvent({ type: 'stage', id, status: 'ok', at: now(), ms: now() - t0 });
|
|
54
|
+
}
|
|
55
|
+
return { ok: true, dashboardUrl, dryRun: true };
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|