@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 +60 -2
- package/bin/nexus.mjs +72 -3
- package/dist/assets/index-Bj0JERnz.css +1 -0
- package/dist/assets/index-DycaEuDy.js +10 -0
- package/dist/index.html +14 -0
- package/package.json +45 -7
- package/prompts/adopt.md +119 -0
- package/prompts/pitch.md +93 -0
- package/server/gh.mjs +89 -0
- package/server/hub.mjs +104 -0
- package/server/normalize.mjs +89 -0
- package/server/preflight.mjs +59 -0
- package/server/provider.mjs +218 -0
- package/server/repo.mjs +192 -0
- package/server/server.mjs +279 -0
- package/server/sh.mjs +47 -0
- package/shared/beats.mjs +190 -0
- package/shared/route.mjs +60 -0
package/README.md
CHANGED
|
@@ -1,6 +1,64 @@
|
|
|
1
1
|
# @usenexus/cli
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
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 ·
|
|
44
|
+
nexus · ${path.basename(repo)}
|
|
45
|
+
|
|
46
|
+
${app.url}
|
|
4
47
|
|
|
5
|
-
|
|
6
|
-
|
|
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}}
|