solrouter 0.3.1 → 0.3.3
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/package.json +1 -1
- package/src/banner.js +11 -52
- package/src/setup.js +20 -57
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "solrouter",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "Local privacy router for coding tools: pseudonymises every request before it leaves your machine, and sends work a frontier model would refuse to an uncensored open-weight model you control.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/banner.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
// banner.js —
|
|
2
|
-
//
|
|
3
|
-
// plus helpers the interactive setup uses to compose the full-width screen.
|
|
1
|
+
// banner.js — the wave mark + wordmark for the terminal, rendered with truecolor
|
|
2
|
+
// half-blocks. The mark is decoded from the real logo (see mark.js).
|
|
4
3
|
|
|
5
|
-
import { MARK_LG
|
|
4
|
+
import { MARK_LG } from "./mark.js";
|
|
6
5
|
|
|
7
6
|
export const PAL = {
|
|
8
7
|
bg: "#0a0908", raised: "#161412", accent: "#F5E6D3", ink: "#e8e0d4",
|
|
@@ -16,46 +15,6 @@ export const bgc = (h) => { const [r, g, b] = rgb(h); return `\x1b[48;2;${r};${g
|
|
|
16
15
|
export const RESET = "\x1b[0m";
|
|
17
16
|
export const paint = (h, t, bold = false) => fg(h) + (bold ? "\x1b[1m" : "") + t + RESET;
|
|
18
17
|
|
|
19
|
-
// Base cat, clean hoodie. .=transparent o=outline b=body e=eye n=nose p=ear H=hoodie
|
|
20
|
-
const CAT = [
|
|
21
|
-
"...oo................oo....",
|
|
22
|
-
"..obbo..............obbo..",
|
|
23
|
-
"..obpbo............obpbo..",
|
|
24
|
-
"..obbbbo..........obbbbo..",
|
|
25
|
-
"...obbbboooooooooobbbbo...",
|
|
26
|
-
"....obbbbbbbbbbbbbbbbo....",
|
|
27
|
-
"...obbbbbbbbbbbbbbbbbbo...",
|
|
28
|
-
"..obbbbbbbbbbbbbbbbbbbbo..",
|
|
29
|
-
"..obbbeebbbbbbbbeebbbbbo..",
|
|
30
|
-
"..obbbeebbbbbbbbeebbbbbo..",
|
|
31
|
-
"..obbbbbbbbbnnbbbbbbbbbo..",
|
|
32
|
-
"..obbbbbbbbbnnbbbbbbbbbo..",
|
|
33
|
-
"...obbbbbbbbbbbbbbbbbbo...",
|
|
34
|
-
"....obbbbbbbbbbbbbbbbo....",
|
|
35
|
-
"...oHHHHHHHHHHHHHHHHHHo...",
|
|
36
|
-
"..oHHHHHHHHHHHHHHHHHHHHo..",
|
|
37
|
-
"..oHHHHHHHHHHHHHHHHHHHHo..",
|
|
38
|
-
"..oHHHHHHHHHHHHHHHHHHHHo..",
|
|
39
|
-
"..oHHHHHHHHHHHHHHHHHHHHo..",
|
|
40
|
-
"..oHHHHHHHHHHHHHHHHHHHHo..",
|
|
41
|
-
"..oHHHHHHHHHHHHHHHHHHHHo..",
|
|
42
|
-
"..obbHHHHHHHHHHHHHHHHbbo..",
|
|
43
|
-
"..obbboHHHHHHHHHHHHobbbo..",
|
|
44
|
-
"...oooo.oooooooooo.oooo...",
|
|
45
|
-
];
|
|
46
|
-
|
|
47
|
-
// Overlay the real mark (SM) onto the hoodie, centred.
|
|
48
|
-
function catWithMark() {
|
|
49
|
-
const g = CAT.map(r => r.split(""));
|
|
50
|
-
const mw = MARK_SM[0].length, mh = MARK_SM.length;
|
|
51
|
-
const c0 = Math.round((CAT[0].length - mw) / 2); // centre horizontally
|
|
52
|
-
const r0 = 16; // centred on the black hoodie
|
|
53
|
-
for (let y = 0; y < mh; y++) for (let x = 0; x < mw; x++) {
|
|
54
|
-
if (MARK_SM[y][x] === "v" && g[r0 + y] && g[r0 + y][c0 + x] === "H") g[r0 + y][c0 + x] = "v";
|
|
55
|
-
}
|
|
56
|
-
return g.map(r => r.join(""));
|
|
57
|
-
}
|
|
58
|
-
|
|
59
18
|
const CMAP = { o: PAL.out, b: PAL.cream, e: PAL.eye, n: PAL.nose, p: PAL.nose, H: PAL.hood, v: PAL.cream };
|
|
60
19
|
|
|
61
20
|
/** Render a pixel grid to ANSI half-block lines. Display width = grid width in chars. */
|
|
@@ -76,16 +35,16 @@ export function renderGrid(grid, cmap = CMAP) {
|
|
|
76
35
|
return lines;
|
|
77
36
|
}
|
|
78
37
|
|
|
79
|
-
export const catLines = () => renderGrid(catWithMark());
|
|
80
|
-
export const catWidth = () => CAT[0].length;
|
|
81
38
|
export const markLines = () => renderGrid(MARK_LG, { v: PAL.cream });
|
|
82
39
|
|
|
83
|
-
/**
|
|
40
|
+
/** One-shot splash: the wave mark + wordmark. */
|
|
84
41
|
export function banner() {
|
|
85
|
-
const L = [""
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
L.push(""
|
|
42
|
+
const L = [""];
|
|
43
|
+
markLines().forEach(m => L.push(" " + m));
|
|
44
|
+
L.push(" " + paint(PAL.accent, "SOLROUTER", true));
|
|
45
|
+
L.push(" " + paint(PAL.muted, "private routing for your coding agent"));
|
|
46
|
+
L.push("");
|
|
47
|
+
return L.join("\n");
|
|
89
48
|
}
|
|
90
49
|
|
|
91
|
-
export default { banner,
|
|
50
|
+
export default { banner, markLines, renderGrid, PAL, paint, fg, bgc, RESET };
|
package/src/setup.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// setup.js — the interactive first-run wizard.
|
|
2
|
-
//
|
|
1
|
+
// setup.js — the interactive first-run wizard. A clean single-column TUI: the wave
|
|
2
|
+
// mark, the step question as a heading, and selectable option cards.
|
|
3
3
|
// Arrow keys move, enter selects, esc/ctrl-c quits.
|
|
4
4
|
//
|
|
5
5
|
// Steps (v1 — API-key only for the frontier leg; no subscription relay):
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// 4. done — save config, offer to launch
|
|
10
10
|
|
|
11
11
|
import readline from "node:readline";
|
|
12
|
-
import {
|
|
12
|
+
import { markLines, PAL, paint, fg, RESET } from "./banner.js";
|
|
13
13
|
import { loadConfig, saveAuth, loadAuth, isLoggedIn, HOME_DIR } from "./config.js";
|
|
14
14
|
import { browserLogin } from "./auth.js";
|
|
15
15
|
import { writeFileSync, readFileSync, mkdirSync, existsSync } from "node:fs";
|
|
@@ -21,67 +21,30 @@ const clear = () => process.stdout.write("\x1b[2J\x1b[H");
|
|
|
21
21
|
const hideCur = () => process.stdout.write("\x1b[?25l");
|
|
22
22
|
const showCur = () => process.stdout.write("\x1b[?25h");
|
|
23
23
|
|
|
24
|
-
// A rounded speech bubble in accent with a consistent width, tail pointing to the cat.
|
|
25
|
-
function bubble(lines) {
|
|
26
|
-
const iw = Math.max(...lines.map(l => l.length)); // inner text width
|
|
27
|
-
const A = PAL.accent;
|
|
28
|
-
const out = [];
|
|
29
|
-
out.push(fg(A) + "╭" + "─".repeat(iw + 2) + "╮" + RESET);
|
|
30
|
-
for (const l of lines) out.push(fg(A) + "│ " + RESET + paint(PAL.ink, l.padEnd(iw)) + fg(A) + " │" + RESET);
|
|
31
|
-
out.push(fg(A) + "╰" + "─".repeat(iw + 2) + "╯" + RESET);
|
|
32
|
-
out.push(" " + fg(A) + "╲" + RESET); // tail toward the cat below
|
|
33
|
-
return out;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Right block = bubble (with the step's question) stacked above the cat, cat indented.
|
|
37
|
-
function rightBlock(question) {
|
|
38
|
-
const cat = catLines().map(l => " " + l);
|
|
39
|
-
const b = bubble(question);
|
|
40
|
-
return [...b, "", ...cat, "", " " + paint(PAL.faint, "the router")];
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Left block = header (stacked, no long inline rows) + step + body lines.
|
|
44
|
-
function leftBlock(step, bodyLines) {
|
|
45
|
-
const L = [];
|
|
46
|
-
markLines().forEach(m => L.push(m)); // real wave mark
|
|
47
|
-
L.push(paint(PAL.accent, "SOLROUTER", true));
|
|
48
|
-
L.push(paint(PAL.muted, "private routing for your coding agent"));
|
|
49
|
-
L.push("");
|
|
50
|
-
L.push(paint(PAL.faint, `STEP ${step} / 3`));
|
|
51
|
-
L.push("");
|
|
52
|
-
bodyLines.forEach(l => L.push(l));
|
|
53
|
-
return L;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
24
|
// One option card (two lines): selected gets an accent bar + bright text.
|
|
57
25
|
function card(name, desc, selected) {
|
|
58
26
|
const bar = selected ? fg(PAL.accent) + "▐ " + RESET : " ";
|
|
59
27
|
const nm = selected ? paint(PAL.accent, "▸ " + name, true) : paint(PAL.ink, " " + name);
|
|
60
|
-
const ds = paint(selected ? PAL.muted : PAL.faint, " " + desc);
|
|
61
|
-
return [bar + nm, bar + ds, ""];
|
|
28
|
+
const ds = desc ? paint(selected ? PAL.muted : PAL.faint, " " + desc) : "";
|
|
29
|
+
return desc ? [bar + nm, bar + ds, ""] : [bar + nm, ""];
|
|
62
30
|
}
|
|
63
31
|
|
|
32
|
+
// Clean single-column frame: header (wave mark + wordmark), step, the question as a
|
|
33
|
+
// heading, then the option cards. No cat.
|
|
64
34
|
function compose(step, question, bodyLines) {
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
if (visLen(l) > rightCol - 2) l = l.slice(0, rightCol - 2); // safety clamp
|
|
79
|
-
const pad = Math.max(2, rightCol - visLen(l));
|
|
80
|
-
out.push(" " + l + " ".repeat(pad) + r);
|
|
81
|
-
}
|
|
82
|
-
out.push("");
|
|
83
|
-
out.push(" " + paint(PAL.faint, "↑↓ move ↵ select esc quit"));
|
|
84
|
-
return out.join("\n");
|
|
35
|
+
const L = [""];
|
|
36
|
+
markLines().forEach(m => L.push(" " + m)); // the real wave mark
|
|
37
|
+
L.push(" " + paint(PAL.accent, "SOLROUTER", true));
|
|
38
|
+
L.push(" " + paint(PAL.muted, "private routing for your coding agent"));
|
|
39
|
+
L.push("");
|
|
40
|
+
L.push(" " + paint(PAL.faint, `STEP ${step} / 3`));
|
|
41
|
+
L.push("");
|
|
42
|
+
L.push(" " + paint(PAL.ink, question.join(" "), true));
|
|
43
|
+
L.push("");
|
|
44
|
+
bodyLines.forEach(l => L.push(" " + l));
|
|
45
|
+
L.push("");
|
|
46
|
+
L.push(" " + paint(PAL.faint, "↑↓ move ↵ select esc quit"));
|
|
47
|
+
return L.join("\n");
|
|
85
48
|
}
|
|
86
49
|
|
|
87
50
|
function render(step, question, bodyLines) { clear(); process.stdout.write(compose(step, question, bodyLines)); }
|