@usenexus/cli 0.0.1 → 0.1.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/README.md CHANGED
@@ -1,6 +1,64 @@
1
1
  # @usenexus/cli
2
2
 
3
- Placeholder. `npx @usenexus/cli` will launch the nexus GUI: onboarding,
4
- a live view of the loop at work, and oversight you can answer in place.
3
+ Using Claude Code? Enjoy a GUI on us. For free.
4
+
5
+ ```
6
+ npx @usenexus/cli
7
+ ```
8
+
9
+ Run it from your project's root. It starts a local server on
10
+ `127.0.0.1` (random port, a token per launch, strict Host and Origin
11
+ checks), opens your browser, and drives your own Claude Code login.
12
+ You need no API key.
13
+
14
+ ## What you get
15
+
16
+ - **Start**: a preflight (Claude Code installed and logged in, `gh`,
17
+ git remote, whether nexus is already adopted). You choose owner mode
18
+ (push straight to main) or contributor mode (pull requests), and how
19
+ `/next` builds (sub-agents, workflows). Then adopt in one click, or
20
+ "explode" a dump of messy thoughts into `/messy`.
21
+ - **Cockpit**: a 50/50 split. On the left are the transcript and a
22
+ composer with slash autocomplete. Free text routes itself: a bug goes
23
+ to `/bug`, a feature or task to `/plot`, and a question is answered
24
+ in place. On the right is the agent stage: the session is an orb,
25
+ sub-agents bloom out on filaments, and a question from an agent pulls
26
+ toward you.
27
+ - **Heads down**: the repo's own `progress.mjs` output as ASCII, plus
28
+ "go heads down" and "pause all".
29
+ - **Oversight**: live questions (`AskUserQuestion` rendered as
30
+ buttons) and durable questions from `plan/`. Your answers are applied
31
+ by `/oversight` and land per owner mode.
32
+ - **Claims**: who builds what, from `claims list --json`.
33
+ - **Cloud loop**: a GitHub Actions checklist, one checkbox per
34
+ workflow, and live runs.
35
+
36
+ Using another agent? The Start screen quotes the canonical prompt
37
+ from nexus `prompts/`, ready to paste.
38
+
39
+ ## Options
40
+
41
+ ```
42
+ npx @usenexus/cli --repo <dir> another folder
43
+ npx @usenexus/cli --no-open print the link instead of opening it
44
+ npx @usenexus/cli --port <n> a fixed port
45
+ NEXUS_PROVIDER=cli use `claude -p` stream-json instead of the Agent SDK
46
+ ```
47
+
48
+ ## Develop
49
+
50
+ ```
51
+ cd packages/cli
52
+ npm ci
53
+ npm test # node --test: beat reducer, routing, hub, server guards
54
+ npm run build # bundles prompts/ and builds the UI into dist/
55
+ npm start # serve this checkout's GUI
56
+ ```
57
+
58
+ The UI uses tokenized placeholder styling. Every colour, size and
59
+ motion value lives in `ui/tokens.css`, which is the file the design
60
+ handoff replaces. The agent stage moves only on structured beats
61
+ (`shared/beats.mjs`). Its pure reducer gives the same state whether
62
+ the page was opened mid-run, refreshed, or watched from the start.
5
63
 
6
64
  The kit: https://github.com/daretodave/nexus
package/bin/nexus.mjs CHANGED
@@ -1,7 +1,76 @@
1
1
  #!/usr/bin/env node
2
+ // npx @usenexus/cli [--repo <dir>] [--port <n>] [--no-open]
3
+ //
4
+ // Starts the nexus GUI on 127.0.0.1 (random port, per-launch token) for
5
+ // the repo in the current directory and opens it in the browser.
6
+ import { spawn } from 'node:child_process';
7
+ import path from 'node:path';
8
+ import fs from 'node:fs';
9
+ import { startServer } from '../server/server.mjs';
10
+
11
+ const argv = process.argv.slice(2);
12
+ const flag = (name) => argv.includes(name);
13
+ const opt = (name) => {
14
+ const i = argv.indexOf(name);
15
+ return i >= 0 ? argv[i + 1] : undefined;
16
+ };
17
+
18
+ if (flag('--help') || flag('-h')) {
19
+ console.log(`nexus: a GUI for Claude Code that runs the nexus loop on your repo.
20
+
21
+ npx @usenexus/cli open the GUI for the repo in this folder
22
+ npx @usenexus/cli --repo <dir> ...for another folder
23
+ npx @usenexus/cli --no-open print the URL instead of opening a browser
24
+ npx @usenexus/cli --port <n> a fixed port (default: any free port)
25
+
26
+ NEXUS_PROVIDER=cli drive \`claude -p\` instead of the Agent SDK
27
+
28
+ The kit: https://github.com/daretodave/nexus`);
29
+ process.exit(0);
30
+ }
31
+
32
+ if (flag('--version') || flag('-v')) {
33
+ const pkg = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
34
+ console.log(pkg.version);
35
+ process.exit(0);
36
+ }
37
+
38
+ const repo = path.resolve(opt('--repo') || process.cwd());
39
+ const port = Number(opt('--port') || 0);
40
+
41
+ const app = await startServer({ repo, port });
42
+
2
43
  console.log(`
3
- nexus · a repo that ships itself
44
+ nexus · ${path.basename(repo)}
45
+
46
+ ${app.url}
4
47
 
5
- The GUI is on its way. Until then, the kit lives at
6
- https://github.com/daretodave/nexus
48
+ Local only (127.0.0.1). The link carries this launch's token; do not share it.
49
+ Ctrl+C to stop.
7
50
  `);
51
+
52
+ if (!flag('--no-open')) openBrowser(app.url);
53
+
54
+ let closing = false;
55
+ const shutdown = async () => {
56
+ if (closing) process.exit(1);
57
+ closing = true;
58
+ console.log('\n stopping...');
59
+ await app.close().catch(() => {});
60
+ process.exit(0);
61
+ };
62
+ process.on('SIGINT', shutdown);
63
+ process.on('SIGTERM', shutdown);
64
+
65
+ function openBrowser(url) {
66
+ const [cmd, args] = process.platform === 'win32'
67
+ ? ['rundll32', ['url.dll,FileProtocolHandler', url]]
68
+ : process.platform === 'darwin' ? ['open', [url]] : ['xdg-open', [url]];
69
+ try {
70
+ const c = spawn(cmd, args, { stdio: 'ignore', detached: true, windowsHide: true });
71
+ c.on('error', () => console.log(' (could not open a browser; open the link above)'));
72
+ c.unref();
73
+ } catch {
74
+ console.log(' (could not open a browser; open the link above)');
75
+ }
76
+ }
@@ -0,0 +1 @@
1
+ :root{--ink-0:#07090f;--ink-1:#0c1018;--ink-2:#121826;--ink-3:#1a2233;--ink-4:#253047;--ink-5:#36425e;--ink-6:#5a6886;--ink-7:#8b97b3;--ink-8:#c3cbe0;--ink-9:#eef1f8;--bg:var(--ink-0);--surface:var(--ink-1);--surface-2:var(--ink-2);--surface-3:var(--ink-3);--line:var(--ink-4);--line-strong:var(--ink-5);--text:var(--ink-9);--text-2:var(--ink-8);--muted:var(--ink-7);--faint:var(--ink-6);--accent:#6fd6ff;--accent-2:#a98bff;--accent-text:#04121c;--aurora:linear-gradient(120deg, var(--accent), var(--accent-2));--focus:0 0 0 2px var(--bg), 0 0 0 4px var(--accent);--state-idle:#7d89a6;--state-running:#6fd6ff;--state-tool:#8be0c4;--state-writing:#a98bff;--state-waiting:#ffc66b;--state-done:#7ee08a;--state-failed:#ff7a8a;--stage-bg:var(--ink-0);--stage-filament:#6fd6ff47;--stage-orb:var(--accent);--stage-orb-glow:#6fd6ff59;--stage-label:var(--ink-8);--stage-agent-1:#6fd6ff;--stage-agent-2:#a98bff;--stage-agent-3:#8be0c4;--stage-agent-4:#ffb3d9;--stage-agent-5:#ffd27a;--stage-tug:var(--state-waiting);--font-ui:"Inter", "Segoe UI", system-ui, -apple-system, sans-serif;--font-mono:"JetBrains Mono", "Cascadia Mono", "SFMono-Regular", Consolas, monospace;--font-display:var(--font-ui);--text-xs:11px;--text-sm:12.5px;--text-md:14px;--text-lg:17px;--text-xl:22px;--text-2xl:30px;--leading:1.5;--leading-tight:1.2;--s-1:4px;--s-2:8px;--s-3:12px;--s-4:16px;--s-5:20px;--s-6:24px;--s-8:32px;--s-10:40px;--r-sm:6px;--r-md:10px;--r-lg:16px;--r-pill:999px;--glow-1:0 0 0 1px var(--line), 0 0 24px -12px var(--stage-orb-glow);--glow-2:0 0 0 1px var(--line-strong), 0 0 40px -10px var(--stage-orb-glow);--ease-drift:cubic-bezier(.37, 0, .63, 1);--ease-settle:cubic-bezier(.22, 1, .36, 1);--ease-snap:cubic-bezier(.5, 0, .1, 1);--dur-snap:.12s;--dur-settle:.28s;--dur-drift:1.8s;--dur-breathe:4.2s;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}:root[data-theme=light]{--ink-0:#f7f6f2;--ink-1:#fff;--ink-2:#f1efe9;--ink-3:#e7e4dc;--ink-4:#d8d4ca;--ink-5:#bdb8ab;--ink-6:#8a8576;--ink-7:#625e52;--ink-8:#36332b;--ink-9:#15140f;--accent:#0a7bb0;--accent-2:#6a4fd8;--accent-text:#fff;--state-idle:#6b7280;--state-running:#0a7bb0;--state-tool:#12806a;--state-writing:#6a4fd8;--state-waiting:#a8600a;--state-done:#2f7d3a;--state-failed:#c0303f;--stage-filament:#0a7bb04d;--stage-orb-glow:#0a7bb038;--stage-agent-1:#0a7bb0;--stage-agent-2:#6a4fd8;--stage-agent-3:#12806a;--stage-agent-4:#b3407a;--stage-agent-5:#a8600a;--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light}@media (prefers-color-scheme:light){:root:not([data-theme=dark]):not([data-theme=light]){--ink-0:#f7f6f2;--ink-1:#fff;--ink-2:#f1efe9;--ink-3:#e7e4dc;--ink-4:#d8d4ca;--ink-5:#bdb8ab;--ink-6:#8a8576;--ink-7:#625e52;--ink-8:#36332b;--ink-9:#15140f;--accent:#0a7bb0;--accent-2:#6a4fd8;--accent-text:#fff;--state-idle:#6b7280;--state-running:#0a7bb0;--state-tool:#12806a;--state-writing:#6a4fd8;--state-waiting:#a8600a;--state-done:#2f7d3a;--state-failed:#c0303f;--stage-filament:#0a7bb04d;--stage-orb-glow:#0a7bb038;--stage-agent-1:#0a7bb0;--stage-agent-2:#6a4fd8;--stage-agent-3:#12806a;--stage-agent-4:#b3407a;--stage-agent-5:#a8600a;--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light}}@media (prefers-reduced-motion:reduce){:root{--dur-snap:0s;--dur-settle:0s;--dur-drift:0s;--dur-breathe:0s}}*{box-sizing:border-box}html,body,#root{height:100%;margin:0}body{background:var(--bg);color:var(--text);font:var(--text-md) / var(--leading) var(--font-ui);-webkit-font-smoothing:antialiased}button,input,textarea,select{font:inherit;color:inherit}:focus-visible{box-shadow:var(--focus);border-radius:var(--r-sm);outline:none}code,pre,.mono{font-family:var(--font-mono)}a{color:var(--accent)}.shell{grid-template-rows:auto 1fr;height:100%;display:grid}.topbar{align-items:center;gap:var(--s-4);padding:var(--s-2) var(--s-4);border-bottom:1px solid var(--line);background:var(--surface);flex-wrap:wrap;display:flex}.brand{letter-spacing:.02em;background:var(--aurora);color:#0000;-webkit-background-clip:text;background-clip:text;font-weight:650}.repo{color:var(--muted);font-size:var(--text-sm)}.nav{gap:var(--s-1);flex-wrap:wrap;display:flex}.nav button{color:var(--muted);padding:var(--s-1) var(--s-3);border-radius:var(--r-pill);cursor:pointer;transition:background var(--dur-snap) var(--ease-snap), color var(--dur-snap) var(--ease-snap);background:0 0;border:0}.nav button:hover{color:var(--text);background:var(--surface-2)}.nav button[aria-current=page]{color:var(--text);background:var(--surface-3)}.spacer{flex:1}.badge{border-radius:var(--r-pill);background:var(--state-waiting);min-width:18px;color:var(--bg);font-size:var(--text-xs);text-align:center;margin-left:6px;padding:0 6px;display:inline-block}.main{min-height:0;overflow:auto}.page{max-width:980px;padding:var(--s-6) var(--s-4) var(--s-10);margin:0 auto}.page h1{font:600 var(--text-xl) / var(--leading-tight) var(--font-display);margin:0 0 var(--s-2)}.page h2{font-size:var(--text-lg);margin:var(--s-8) 0 var(--s-3)}.lede{color:var(--text-2);margin:0 0 var(--s-6)}.muted{color:var(--muted)}.small{font-size:var(--text-sm)}.btn{align-items:center;gap:var(--s-2);padding:var(--s-2) var(--s-4);border-radius:var(--r-md);border:1px solid var(--line-strong);background:var(--surface-2);cursor:pointer;transition:border-color var(--dur-snap) var(--ease-snap), background var(--dur-snap) var(--ease-snap);display:inline-flex}.btn:hover{border-color:var(--accent)}.btn:disabled{opacity:.5;cursor:default}.btn.primary{background:var(--aurora);color:var(--accent-text);border-color:#0000;font-weight:600}.btn.quiet{background:0 0}.btn.danger:hover{border-color:var(--state-failed)}.row{gap:var(--s-2);flex-wrap:wrap;align-items:center;display:flex}.check{gap:var(--s-2);padding:var(--s-2) 0;cursor:pointer;align-items:flex-start;display:flex}.check input{accent-color:var(--accent);margin-top:3px}.field{width:100%;padding:var(--s-2) var(--s-3);border-radius:var(--r-md);border:1px solid var(--line-strong);background:var(--surface)}textarea.field{resize:vertical;min-height:80px}select.field{width:auto}.card{background:var(--surface);border-radius:var(--r-lg);box-shadow:var(--glow-1);padding:var(--s-4);margin-bottom:var(--s-3)}.card h3{margin:0 0 var(--s-2);font-size:var(--text-md)}.list{margin:0;padding:0;list-style:none}.list>li{gap:var(--s-3);padding:var(--s-3) 0;border-bottom:1px solid var(--line);align-items:flex-start;display:flex}.list>li:last-child{border-bottom:0}.glyph{text-align:center;width:20px;font-family:var(--font-mono);flex:none}.ok{color:var(--state-done)}.bad{color:var(--state-failed)}.warn{color:var(--state-waiting)}.pill{padding:0 var(--s-2);border-radius:var(--r-pill);border:1px solid var(--line-strong);font-size:var(--text-xs);color:var(--muted);display:inline-block}.pill.owner{border-color:var(--accent);color:var(--accent)}.prompt-box{white-space:pre-wrap;background:var(--surface-2);border-radius:var(--r-md);padding:var(--s-3);font-family:var(--font-mono);font-size:var(--text-sm);max-height:320px;overflow:auto}table.grid{border-collapse:collapse;width:100%;font-size:var(--text-sm)}table.grid th,table.grid td{text-align:left;padding:var(--s-2);border-bottom:1px solid var(--line);vertical-align:top}table.grid th{color:var(--muted);font-weight:500}.hero{padding:var(--s-10) 0 var(--s-6)}.hero h1{font-size:var(--text-2xl)}.hero .tag{background:var(--aurora);color:#0000;-webkit-background-clip:text;background-clip:text}.choice{gap:var(--s-3);grid-template-columns:1fr 1fr;display:grid}.choice label{border:1px solid var(--line-strong);border-radius:var(--r-md);padding:var(--s-3);cursor:pointer}.choice input{accent-color:var(--accent)}.choice label:has(input:checked){border-color:var(--accent);box-shadow:var(--glow-2)}.cockpit{grid-template-columns:1fr 1fr;height:100%;min-height:0;display:grid}.left{border-right:1px solid var(--line);grid-template-rows:auto 1fr auto;min-height:0;display:grid}.context{gap:var(--s-2);padding:var(--s-2) var(--s-4);border-bottom:1px solid var(--line);font-size:var(--text-sm);color:var(--muted);flex-wrap:wrap;display:flex}.context .layer{padding:2px var(--s-2);border-radius:var(--r-sm);background:var(--surface-2)}.transcript{padding:var(--s-4);min-height:0;overflow:auto}.msg{margin:0 0 var(--s-3);white-space:pre-wrap;overflow-wrap:anywhere}.msg.user{color:var(--accent)}.msg.user:before{content:"> ";color:var(--faint);font-family:var(--font-mono)}.msg.system{color:var(--faint);font-size:var(--text-sm)}.msg.error{color:var(--state-failed)}.tool{font-family:var(--font-mono);font-size:var(--text-sm);color:var(--muted);padding:2px 0}.tool .name{color:var(--state-tool)}.tool.sub{padding-left:var(--s-4);border-left:2px solid var(--line)}.result{font-size:var(--text-sm);color:var(--muted);border-top:1px dashed var(--line);padding-top:var(--s-2);margin-bottom:var(--s-3)}.composer{border-top:1px solid var(--line);padding:var(--s-3) var(--s-4);background:var(--surface);position:relative}.composer textarea{min-height:64px}.complete{bottom:100%;left:var(--s-4);right:var(--s-4);background:var(--surface-2);border-radius:var(--r-md);box-shadow:var(--glow-2);padding:var(--s-1);margin:0;list-style:none;position:absolute}.complete li{padding:var(--s-1) var(--s-2);border-radius:var(--r-sm);cursor:pointer;font-size:var(--text-sm)}.complete li[aria-selected=true]{background:var(--surface-3)}.route{font-size:var(--text-xs)}.right{background:var(--stage-bg);min-height:0;position:relative}.right canvas{width:100%;height:100%;display:block}.stage-legend{left:var(--s-3);bottom:var(--s-3);font-size:var(--text-xs);color:var(--muted);gap:var(--s-3);flex-wrap:wrap;display:flex;position:absolute}.ask{border-left:3px solid var(--state-waiting)}.ask .opts{gap:var(--s-2);margin:var(--s-2) 0;flex-wrap:wrap;display:flex}.ask .opt[aria-pressed=true]{border-color:var(--accent);background:var(--surface-3)}.tug-in{animation:tug var(--dur-settle) var(--ease-settle)}@keyframes tug{0%{opacity:0;transform:translate(24px)}to{opacity:1;transform:none}}.ascii{font-family:var(--font-mono);font-size:var(--text-sm);background:var(--surface);color:var(--text-2);padding:var(--s-4);border-radius:var(--r-md);box-shadow:var(--glow-1);white-space:pre;min-height:240px;line-height:1.45;overflow:auto}@media (width<=900px){.cockpit{grid-template-rows:1fr 320px;grid-template-columns:1fr}.left{border-right:0;border-bottom:1px solid var(--line)}.choice{grid-template-columns:1fr}}@media (prefers-reduced-motion:reduce){.tug-in{animation:none}}