lopebase 0.3.0 → 0.4.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 +9 -7
- package/dist/lopebase.js +86 -25
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -30,12 +30,14 @@ In the folder of any project you run:
|
|
|
30
30
|
npx lopebase
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
1. **Scan.**
|
|
34
|
-
variable *names* in example env files, then shows your
|
|
35
|
-
you already use, and what
|
|
36
|
-
|
|
37
|
-
2. **Connect this computer.** It opens your
|
|
38
|
-
short code.
|
|
33
|
+
1. **Scan.** After you say yes, it reads your dependency names, config file
|
|
34
|
+
names, and the variable *names* in example env files, then shows your
|
|
35
|
+
stack, the services you already use, and what it did not find (for example
|
|
36
|
+
analytics or error logging). You see each thing it reads as it reads it.
|
|
37
|
+
2. **Connect this computer.** It opens LopeBase in your browser and shows a
|
|
38
|
+
short code. Sign in, or create a free account if you are new, check the code
|
|
39
|
+
matches, and press Connect. No address to type: it finds your workspace.
|
|
40
|
+
For a custom domain or your own server, add `--url https://your-address`.
|
|
39
41
|
3. **Pick what to connect.** Services already in your code are ticked; the
|
|
40
42
|
ones you do not use yet are offered, never forced.
|
|
41
43
|
4. **Hand over to your agent.** It finds the coding agents you have installed
|
|
@@ -76,7 +78,7 @@ Made for web products, and fine with anything else:
|
|
|
76
78
|
| Command | What it does |
|
|
77
79
|
| --- | --- |
|
|
78
80
|
| `npx lopebase` | Scan, connect, choose, and hand over to your agent. |
|
|
79
|
-
| `npx lopebase login` | Connect this computer to your workspace with a short code. `--paste` to paste an agent token instead. |
|
|
81
|
+
| `npx lopebase login` | Connect this computer to your workspace with a short code, creating an account if you need one. `--paste` to paste an agent token instead. |
|
|
80
82
|
| `npx lopebase scan` | Show what the scan found. `--json` for scripts. |
|
|
81
83
|
| `npx lopebase prompt` | Print the setup prompt instead of starting an agent. |
|
|
82
84
|
| `npx lopebase mcp` | Run the LopeBase tools as a local MCP server (stdio) for any agent. |
|
package/dist/lopebase.js
CHANGED
|
@@ -832,6 +832,24 @@ class x {
|
|
|
832
832
|
}
|
|
833
833
|
}
|
|
834
834
|
}
|
|
835
|
+
|
|
836
|
+
class dD extends x {
|
|
837
|
+
get cursor() {
|
|
838
|
+
return this.value ? 0 : 1;
|
|
839
|
+
}
|
|
840
|
+
get _value() {
|
|
841
|
+
return this.cursor === 0;
|
|
842
|
+
}
|
|
843
|
+
constructor(u) {
|
|
844
|
+
super(u, !1), this.value = !!u.initialValue, this.on("value", () => {
|
|
845
|
+
this.value = this._value;
|
|
846
|
+
}), this.on("confirm", (t) => {
|
|
847
|
+
this.output.write(import_sisteransi.cursor.move(0, -1)), this.value = t, this.state = "submit", this.close();
|
|
848
|
+
}), this.on("cursor", () => {
|
|
849
|
+
this.value = !this.value;
|
|
850
|
+
});
|
|
851
|
+
}
|
|
852
|
+
}
|
|
835
853
|
var A;
|
|
836
854
|
A = /* @__PURE__ */ new WeakMap;
|
|
837
855
|
var kD = Object.defineProperty, $D = (e, u, t) => (u in e) ? kD(e, u, { enumerable: !0, configurable: !0, writable: !0, value: t }) : e[u] = t, H = (e, u, t) => ($D(e, typeof u != "symbol" ? u + "" : u, t), t), SD = class extends x {
|
|
@@ -997,8 +1015,25 @@ ${import_picocolors2.default.gray(o)}` : ""}`;
|
|
|
997
1015
|
${import_picocolors2.default.cyan(d2)}
|
|
998
1016
|
`;
|
|
999
1017
|
}
|
|
1000
|
-
} }).prompt()
|
|
1001
|
-
|
|
1018
|
+
} }).prompt(), ye = (t) => {
|
|
1019
|
+
let n = t.active ?? "Yes", r2 = t.inactive ?? "No";
|
|
1020
|
+
return new dD({ active: n, inactive: r2, initialValue: t.initialValue ?? !0, render() {
|
|
1021
|
+
let i = `${import_picocolors2.default.gray(o)}
|
|
1022
|
+
${b2(this.state)} ${t.message}
|
|
1023
|
+
`, s = this.value ? n : r2;
|
|
1024
|
+
switch (this.state) {
|
|
1025
|
+
case "submit":
|
|
1026
|
+
return `${i}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.dim(s)}`;
|
|
1027
|
+
case "cancel":
|
|
1028
|
+
return `${i}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}
|
|
1029
|
+
${import_picocolors2.default.gray(o)}`;
|
|
1030
|
+
default:
|
|
1031
|
+
return `${i}${import_picocolors2.default.cyan(o)} ${this.value ? `${import_picocolors2.default.green(k2)} ${n}` : `${import_picocolors2.default.dim(P2)} ${import_picocolors2.default.dim(n)}`} ${import_picocolors2.default.dim("/")} ${this.value ? `${import_picocolors2.default.dim(P2)} ${import_picocolors2.default.dim(r2)}` : `${import_picocolors2.default.green(k2)} ${r2}`}
|
|
1032
|
+
${import_picocolors2.default.cyan(d2)}
|
|
1033
|
+
`;
|
|
1034
|
+
}
|
|
1035
|
+
} }).prompt();
|
|
1036
|
+
}, ve = (t) => {
|
|
1002
1037
|
let n = (r2, i) => {
|
|
1003
1038
|
let s = r2.label ?? String(r2.value);
|
|
1004
1039
|
switch (i) {
|
|
@@ -1544,6 +1579,18 @@ function workspaceUrl(input) {
|
|
|
1544
1579
|
return null;
|
|
1545
1580
|
}
|
|
1546
1581
|
}
|
|
1582
|
+
function signInUrl(input) {
|
|
1583
|
+
for (let [raw, from] of [
|
|
1584
|
+
[input.flag, "--url"],
|
|
1585
|
+
[input.env, "LOPEBASE_URL"]
|
|
1586
|
+
]) {
|
|
1587
|
+
if (raw === void 0 || raw.trim() === "")
|
|
1588
|
+
continue;
|
|
1589
|
+
let url = workspaceUrl(raw);
|
|
1590
|
+
return url ? { url } : { error: `${from} is not an address: ${raw}` };
|
|
1591
|
+
}
|
|
1592
|
+
return { url: input.saved && workspaceUrl(input.saved) || DEFAULT_URL };
|
|
1593
|
+
}
|
|
1547
1594
|
function configDir() {
|
|
1548
1595
|
let base = process.env.XDG_CONFIG_HOME || path.join(os.homedir(), ".config");
|
|
1549
1596
|
return path.join(base, "lopebase");
|
|
@@ -2085,7 +2132,7 @@ function detectStack(facts) {
|
|
|
2085
2132
|
why: "Know the moment the site goes down. Nothing to install."
|
|
2086
2133
|
});
|
|
2087
2134
|
if (isWebsite && !has("posthog") && !has("ga4")) {
|
|
2088
|
-
if (gaps.push("No product analytics found.
|
|
2135
|
+
if (gaps.push("No product analytics found."), !listed("posthog"))
|
|
2089
2136
|
sources.push({
|
|
2090
2137
|
source: "posthog",
|
|
2091
2138
|
label: "PostHog",
|
|
@@ -2095,7 +2142,7 @@ function detectStack(facts) {
|
|
|
2095
2142
|
});
|
|
2096
2143
|
}
|
|
2097
2144
|
if (!has("sentry")) {
|
|
2098
|
-
if (gaps.push("No error
|
|
2145
|
+
if (gaps.push("No error logging found."), !listed("sentry"))
|
|
2099
2146
|
sources.push({
|
|
2100
2147
|
source: "sentry",
|
|
2101
2148
|
label: "Sentry",
|
|
@@ -2635,24 +2682,22 @@ function scanProject(root, onProgress) {
|
|
|
2635
2682
|
// src/ui.ts
|
|
2636
2683
|
var import_picocolors3 = __toESM(require_picocolors(), 1), MARK = [
|
|
2637
2684
|
" ▗▖ ▗▖ ",
|
|
2638
|
-
" ▐▌ ▐▌ ",
|
|
2639
2685
|
" ▐█▖▗█▌ ",
|
|
2640
2686
|
" ▜██▛ ",
|
|
2641
2687
|
" ▟██▙ ",
|
|
2642
2688
|
" ▟████▙ ",
|
|
2643
2689
|
" ▟██████▙ ",
|
|
2644
|
-
"
|
|
2645
|
-
"
|
|
2646
|
-
|
|
2647
|
-
], HORIZON = /* @__PURE__ */ new Set([8, 9]);
|
|
2690
|
+
" ▄▄▄▄▄▄▄▄▄▄ ",
|
|
2691
|
+
" ▄▄▄▄▄▄ "
|
|
2692
|
+
], HORIZON = /* @__PURE__ */ new Set([6, 7]);
|
|
2648
2693
|
function motionAllowed(argv = process.argv, env = process.env, isTTY = Boolean(process.stdout.isTTY)) {
|
|
2649
2694
|
return isTTY && !env.CI && !env.LOPEBASE_NO_MOTION && env.TERM !== "dumb" && !argv.includes("--no-motion");
|
|
2650
2695
|
}
|
|
2651
2696
|
var sleep = (ms) => new Promise((r2) => setTimeout(r2, ms));
|
|
2652
2697
|
function logoLines(opts) {
|
|
2653
2698
|
let right = {
|
|
2654
|
-
|
|
2655
|
-
|
|
2699
|
+
3: `${import_picocolors3.default.bold("Lope")}${import_picocolors3.default.dim("Base")}${opts.version ? import_picocolors3.default.dim(` v${opts.version}`) : ""}`,
|
|
2700
|
+
4: import_picocolors3.default.dim(opts.tagline)
|
|
2656
2701
|
};
|
|
2657
2702
|
return MARK.map((row, i) => {
|
|
2658
2703
|
let mark = HORIZON.has(i) ? import_picocolors3.default.yellow(import_picocolors3.default.dim(row)) : import_picocolors3.default.yellow(row);
|
|
@@ -2683,7 +2728,7 @@ ${lines.join(`
|
|
|
2683
2728
|
for (let i = MARK.length - 1;i >= 0; i--)
|
|
2684
2729
|
shown.add(i), write(`${up}\r${frame(shown).join(`
|
|
2685
2730
|
`)}
|
|
2686
|
-
`), await sleep(i
|
|
2731
|
+
`), await sleep(HORIZON.has(i) ? 70 : 35);
|
|
2687
2732
|
write(`${up}\r${lines.join(`
|
|
2688
2733
|
`)}
|
|
2689
2734
|
|
|
@@ -2767,6 +2812,7 @@ ${import_picocolors4.default.bold("Usage")}
|
|
|
2767
2812
|
|
|
2768
2813
|
${import_picocolors4.default.bold("Options")}
|
|
2769
2814
|
--print print the agent prompt instead of starting an agent
|
|
2815
|
+
--url <address> sign in to this workspace or server (also LOPEBASE_URL)
|
|
2770
2816
|
--no-motion no animation (also LOPEBASE_NO_MOTION=1)
|
|
2771
2817
|
|
|
2772
2818
|
${import_picocolors4.default.bold("Learn more")}
|
|
@@ -2825,20 +2871,23 @@ async function checkToken(auth) {
|
|
|
2825
2871
|
}
|
|
2826
2872
|
}
|
|
2827
2873
|
async function login() {
|
|
2828
|
-
let
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2874
|
+
let start = signInUrl({
|
|
2875
|
+
flag: option("url"),
|
|
2876
|
+
env: process.env.LOPEBASE_URL,
|
|
2877
|
+
saved: loadAuth()?.url
|
|
2878
|
+
});
|
|
2879
|
+
if ("error" in start)
|
|
2880
|
+
bail(start.error);
|
|
2881
|
+
let url = start.url;
|
|
2834
2882
|
if (!flag("paste")) {
|
|
2835
2883
|
let device = await startDeviceLogin(url);
|
|
2836
2884
|
if (device) {
|
|
2837
2885
|
Me([
|
|
2838
2886
|
`Your code: ${import_picocolors4.default.bold(import_picocolors4.default.yellow(device.userCode))}`,
|
|
2839
2887
|
"",
|
|
2840
|
-
"We opened
|
|
2841
|
-
"check the code matches
|
|
2888
|
+
"We opened LopeBase in your browser. Sign in, or create a free",
|
|
2889
|
+
"account if you are new. Then check the code matches and press",
|
|
2890
|
+
"Connect."
|
|
2842
2891
|
].join(`
|
|
2843
2892
|
`), "Connect this computer"), openBrowser(device.verifyUrl), M2.info(import_picocolors4.default.dim(device.verifyUrl));
|
|
2844
2893
|
let s = Y2();
|
|
@@ -2846,14 +2895,21 @@ async function login() {
|
|
|
2846
2895
|
let res = await pollDeviceLogin(url, device);
|
|
2847
2896
|
if (res.ok) {
|
|
2848
2897
|
let file2 = saveAuth({ url: res.url, token: res.token });
|
|
2849
|
-
return s.stop(`Connected
|
|
2898
|
+
return s.stop(`Connected to ${import_picocolors4.default.bold(res.url)}. Saved to ${import_picocolors4.default.dim(file2)}`), { url: res.url, token: res.token };
|
|
2850
2899
|
}
|
|
2851
2900
|
if (s.stop(import_picocolors4.default.red(res.message)), res.reason === "denied")
|
|
2852
2901
|
bail("Nothing was connected.");
|
|
2853
2902
|
M2.warn("Falling back to pasting a token.");
|
|
2854
2903
|
}
|
|
2855
2904
|
}
|
|
2856
|
-
return pasteLogin(url);
|
|
2905
|
+
return pasteLogin(url === DEFAULT_URL ? await askWorkspace() : url);
|
|
2906
|
+
}
|
|
2907
|
+
async function askWorkspace() {
|
|
2908
|
+
return workspaceUrl(guard(await he({
|
|
2909
|
+
message: "Your LopeBase workspace (name or address)",
|
|
2910
|
+
placeholder: "yourteam or https://yourteam.lopebase.com",
|
|
2911
|
+
validate: (v2) => workspaceUrl(v2 ?? "") ? void 0 : "Type your workspace name, like yourteam, or its full address"
|
|
2912
|
+
})));
|
|
2857
2913
|
}
|
|
2858
2914
|
async function pasteLogin(url) {
|
|
2859
2915
|
let settings = `${url}/settings#agent-access`;
|
|
@@ -2889,7 +2945,7 @@ async function printDetection(d3, facts) {
|
|
|
2889
2945
|
Me(possible.map((s) => `${import_picocolors4.default.yellow("?")} ${import_picocolors4.default.bold(s.label)} ${import_picocolors4.default.dim(`only ${s.evidence.join(", ")}`)}`).join(`
|
|
2890
2946
|
`), "Maybe in use, your agent will check"), await pace(motion, 150);
|
|
2891
2947
|
for (let gap of d3.gaps)
|
|
2892
|
-
M2.
|
|
2948
|
+
M2.info(import_picocolors4.default.dim(gap));
|
|
2893
2949
|
}
|
|
2894
2950
|
async function scanWithProgress() {
|
|
2895
2951
|
let s = Y2();
|
|
@@ -2919,8 +2975,13 @@ function registerMcp(agent) {
|
|
|
2919
2975
|
return res.status === 0 || /already exists/i.test(`${res.stderr}${res.stdout}`);
|
|
2920
2976
|
}
|
|
2921
2977
|
async function init() {
|
|
2922
|
-
console.clear(), await showLogo({ tagline: TAGLINE, version: version(), motion }), Ie(`${import_picocolors4.default.bgYellow(import_picocolors4.default.black(" LopeBase "))} set up this project`), Me(planLines().join(`
|
|
2923
|
-
`), "Here is what happens"), await
|
|
2978
|
+
if (console.clear(), await showLogo({ tagline: TAGLINE, version: version(), motion }), Ie(`${import_picocolors4.default.bgYellow(import_picocolors4.default.black(" LopeBase "))} set up this project`), Me(planLines().join(`
|
|
2979
|
+
`), "Here is what happens"), !guard(await ye({
|
|
2980
|
+
message: `Scan ${import_picocolors4.default.bold(cwd)}?`,
|
|
2981
|
+
initialValue: !0
|
|
2982
|
+
})))
|
|
2983
|
+
xe("Nothing was read. Run lopebase again any time."), process.exit(0);
|
|
2984
|
+
M2.step(stepTitle(1));
|
|
2924
2985
|
let { facts, detection } = await scanWithProgress();
|
|
2925
2986
|
await printDetection(detection, facts), M2.step(stepTitle(2));
|
|
2926
2987
|
let auth = loadAuth();
|
package/package.json
CHANGED