withvibe 0.1.4

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.
Files changed (62) hide show
  1. package/LICENSE +93 -0
  2. package/README.md +67 -0
  3. package/dist/api.js +29 -0
  4. package/dist/api.js.map +1 -0
  5. package/dist/assets/docker-compose.yml +130 -0
  6. package/dist/config.js +48 -0
  7. package/dist/config.js.map +1 -0
  8. package/dist/env-command.js +331 -0
  9. package/dist/env-command.js.map +1 -0
  10. package/dist/exec.js +35 -0
  11. package/dist/exec.js.map +1 -0
  12. package/dist/git-auth.js +64 -0
  13. package/dist/git-auth.js.map +1 -0
  14. package/dist/index.js +42 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/install/anthropic-validate.js +73 -0
  17. package/dist/install/anthropic-validate.js.map +1 -0
  18. package/dist/install/build-images.js +99 -0
  19. package/dist/install/build-images.js.map +1 -0
  20. package/dist/install/commands/build-images-cmd.js +68 -0
  21. package/dist/install/commands/build-images-cmd.js.map +1 -0
  22. package/dist/install/commands/configure.js +276 -0
  23. package/dist/install/commands/configure.js.map +1 -0
  24. package/dist/install/commands/lifecycle.js +129 -0
  25. package/dist/install/commands/lifecycle.js.map +1 -0
  26. package/dist/install/commands/uninstall.js +88 -0
  27. package/dist/install/commands/uninstall.js.map +1 -0
  28. package/dist/install/commands/upgrade.js +164 -0
  29. package/dist/install/commands/upgrade.js.map +1 -0
  30. package/dist/install/compose-rewriter.js +298 -0
  31. package/dist/install/compose-rewriter.js.map +1 -0
  32. package/dist/install/compose.js +118 -0
  33. package/dist/install/compose.js.map +1 -0
  34. package/dist/install/doctor.js +176 -0
  35. package/dist/install/doctor.js.map +1 -0
  36. package/dist/install/env-file.js +63 -0
  37. package/dist/install/env-file.js.map +1 -0
  38. package/dist/install/exec.js +32 -0
  39. package/dist/install/exec.js.map +1 -0
  40. package/dist/install/images.js +78 -0
  41. package/dist/install/images.js.map +1 -0
  42. package/dist/install/init.js +584 -0
  43. package/dist/install/init.js.map +1 -0
  44. package/dist/install/log.js +15 -0
  45. package/dist/install/log.js.map +1 -0
  46. package/dist/install/paths.js +26 -0
  47. package/dist/install/paths.js.map +1 -0
  48. package/dist/install/ports.js +23 -0
  49. package/dist/install/ports.js.map +1 -0
  50. package/dist/install/register.js +155 -0
  51. package/dist/install/register.js.map +1 -0
  52. package/dist/install/secrets.js +9 -0
  53. package/dist/install/secrets.js.map +1 -0
  54. package/dist/install/state.js +29 -0
  55. package/dist/install/state.js.map +1 -0
  56. package/dist/login.js +56 -0
  57. package/dist/login.js.map +1 -0
  58. package/dist/ports.js +33 -0
  59. package/dist/ports.js.map +1 -0
  60. package/dist/preflight.js +150 -0
  61. package/dist/preflight.js.map +1 -0
  62. package/package.json +38 -0
@@ -0,0 +1,23 @@
1
+ import net from "node:net";
2
+ // Returns true iff the given TCP port is free on 0.0.0.0. We probe by
3
+ // trying to bind a transient server — that's the same behavior `compose up`
4
+ // would hit, so an "in use" result here always reflects reality.
5
+ export function isPortFree(port) {
6
+ return new Promise((resolve) => {
7
+ const srv = net.createServer();
8
+ srv.once("error", () => resolve(false));
9
+ srv.once("listening", () => srv.close(() => resolve(true)));
10
+ srv.listen(port, "0.0.0.0");
11
+ });
12
+ }
13
+ // Walk upward from `start` until we hit a free port or run out of tries.
14
+ // Returns the chosen port, or null if nothing in [start, start+maxTries) is
15
+ // free (very rare — only happens on truly busy hosts).
16
+ export async function findFreePort(start, maxTries = 50) {
17
+ for (let p = start; p < start + maxTries; p++) {
18
+ if (await isPortFree(p))
19
+ return p;
20
+ }
21
+ return null;
22
+ }
23
+ //# sourceMappingURL=ports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ports.js","sourceRoot":"","sources":["../../src/install/ports.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,UAAU,CAAC;AAE3B,sEAAsE;AACtE,4EAA4E;AAC5E,iEAAiE;AACjE,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,GAAG,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC;QAC/B,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;QACxC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC5D,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,yEAAyE;AACzE,4EAA4E;AAC5E,uDAAuD;AACvD,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,KAAa,EACb,QAAQ,GAAG,EAAE;IAEb,KAAK,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,KAAK,GAAG,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9C,IAAI,MAAM,UAAU,CAAC,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC;IACpC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,155 @@
1
+ // Wires every installer subcommand onto a parent commander program.
2
+ // The host CLI (packages/cli) calls this with a `Command` named "install"
3
+ // so users invoke them as `withvibe install <subcmd>`. Keeping the wiring
4
+ // here means the subcommand names + descriptions stay co-located with the
5
+ // rest of the installer code.
6
+ import { runDoctor, printReport } from "./doctor.js";
7
+ import { runInit } from "./init.js";
8
+ import { runBuildImages } from "./commands/build-images-cmd.js";
9
+ import { runStart, runStop, runRestart, runStatus, runLogs, } from "./commands/lifecycle.js";
10
+ import { runConfigure } from "./commands/configure.js";
11
+ import { runUpgrade } from "./commands/upgrade.js";
12
+ import { runUninstall } from "./commands/uninstall.js";
13
+ import { log } from "./log.js";
14
+ export function registerInstallCommands(program) {
15
+ program
16
+ .command("doctor")
17
+ .description("Run host preflight checks (read-only)")
18
+ .action(async () => {
19
+ const report = await runDoctor();
20
+ printReport(report);
21
+ if (!report.ok) {
22
+ log.fail("\nSome checks failed. Fix the items above before running `init`.");
23
+ process.exit(1);
24
+ }
25
+ log.ok("\nAll checks passed.");
26
+ });
27
+ program
28
+ .command("init")
29
+ .description("Guided first-time install: collect secrets, write config, prepare images")
30
+ .option("-m, --mode <mode>", "Install mode: from-source | from-bundle | from-registry")
31
+ .option("-d, --install-dir <path>", "Where .env, docker-compose.yml, and state live")
32
+ .option("--bundle-path <path>", "Bundle path for from-bundle mode (skips the prompt and allows Default preset)")
33
+ .option("--skip-key-check", "Don't validate the Anthropic key against the live API", false)
34
+ .option("-y, --yes", "Pick the Default preset and skip every prompt (one-click install)", false)
35
+ .option("--no-build", "Don't run `build-images` after writing config")
36
+ .option("--no-start", "Don't run `start` after building")
37
+ .action(async (opts) => {
38
+ const mode = opts.mode;
39
+ if (mode && !["from-source", "from-bundle", "from-registry"].includes(mode)) {
40
+ log.fail(`Unknown mode: ${mode}`);
41
+ process.exit(1);
42
+ }
43
+ await runInit({
44
+ mode,
45
+ installDir: opts.installDir,
46
+ bundlePath: opts.bundlePath,
47
+ skipKeyCheck: opts.skipKeyCheck,
48
+ yes: opts.yes,
49
+ noBuild: !opts.build,
50
+ noStart: !opts.start,
51
+ });
52
+ });
53
+ program
54
+ .command("build-images")
55
+ .description("Build / load / pull the images this install needs")
56
+ .option("-d, --install-dir <path>", "Install directory")
57
+ .option("--repo-path <path>", "Source tree (overrides state, for from-source)")
58
+ .option("--bundle-path <path>", "Bundle path (overrides state, for from-bundle)")
59
+ .action(async (opts) => {
60
+ await runBuildImages({
61
+ installDir: opts.installDir,
62
+ repoPath: opts.repoPath,
63
+ bundlePath: opts.bundlePath,
64
+ });
65
+ });
66
+ program
67
+ .command("configure")
68
+ .description("Edit/add/remove features (Traefik, QA browser, OAuth, secrets…)")
69
+ .option("-d, --install-dir <path>", "Install directory")
70
+ .action(async (opts) => {
71
+ await runConfigure({ installDir: opts.installDir });
72
+ });
73
+ program
74
+ .command("start")
75
+ .description("docker compose up -d, with health gating")
76
+ .option("-d, --install-dir <path>", "Install directory")
77
+ .action(async (opts) => {
78
+ await runStart({ installDir: opts.installDir });
79
+ });
80
+ program
81
+ .command("stop")
82
+ .description("docker compose down (data preserved)")
83
+ .option("-d, --install-dir <path>", "Install directory")
84
+ .action(async (opts) => {
85
+ await runStop({ installDir: opts.installDir });
86
+ });
87
+ program
88
+ .command("restart")
89
+ .description("docker compose restart")
90
+ .option("-d, --install-dir <path>", "Install directory")
91
+ .action(async (opts) => {
92
+ await runRestart({ installDir: opts.installDir });
93
+ });
94
+ program
95
+ .command("status")
96
+ .description("Service state + sidecar image presence + URLs")
97
+ .option("-d, --install-dir <path>", "Install directory")
98
+ .action(async (opts) => {
99
+ await runStatus({ installDir: opts.installDir });
100
+ });
101
+ program
102
+ .command("logs [service]")
103
+ .description("Tail logs (optionally for a single service: postgres, api, web, traefik)")
104
+ .option("-d, --install-dir <path>", "Install directory")
105
+ .option("-f, --follow", "Follow logs", true)
106
+ .action(async (service, opts) => {
107
+ await runLogs({
108
+ installDir: opts.installDir,
109
+ service,
110
+ follow: opts.follow,
111
+ });
112
+ });
113
+ program
114
+ .command("upgrade")
115
+ .description("Snapshot postgres, refresh images, restart, rollback on health failure")
116
+ .option("-d, --install-dir <path>", "Install directory")
117
+ .option("-m, --mode <mode>", "Override mode for this upgrade")
118
+ .option("--bundle-path <path>", "New bundle path (for from-bundle)")
119
+ .option("--repo-path <path>", "Source tree (for from-source)")
120
+ .option("--registry-namespace <ns>", "Override registry namespace (for from-registry)")
121
+ .option("--registry-tag <tag>", "Override registry tag (for from-registry)")
122
+ .option("--skip-backup", "Skip the postgres dump (no rollback safety net)", false)
123
+ .action(async (opts) => {
124
+ const mode = opts.mode;
125
+ if (mode && !["from-source", "from-bundle", "from-registry"].includes(mode)) {
126
+ log.fail(`Unknown mode: ${mode}`);
127
+ process.exit(1);
128
+ }
129
+ await runUpgrade({
130
+ installDir: opts.installDir,
131
+ mode,
132
+ bundlePath: opts.bundlePath,
133
+ repoPath: opts.repoPath,
134
+ registryNamespace: opts.registryNamespace,
135
+ registryTag: opts.registryTag,
136
+ skipBackup: opts.skipBackup,
137
+ });
138
+ });
139
+ program
140
+ .command("uninstall")
141
+ .description("Remove the stack (with data-loss confirmation)")
142
+ .option("-d, --install-dir <path>", "Install directory")
143
+ .option("--keep-data", "Keep the postgres volume", false)
144
+ .option("--remove-images", "Also remove local images", false)
145
+ .option("-y, --yes", "Skip confirmation prompts", false)
146
+ .action(async (opts) => {
147
+ await runUninstall({
148
+ installDir: opts.installDir,
149
+ keepData: opts.keepData,
150
+ removeImages: opts.removeImages,
151
+ yes: opts.yes,
152
+ });
153
+ });
154
+ }
155
+ //# sourceMappingURL=register.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.js","sourceRoot":"","sources":["../../src/install/register.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import crypto from "node:crypto";
2
+ export function randomSecret(bytes = 32) {
3
+ return crypto.randomBytes(bytes).toString("hex");
4
+ }
5
+ export function randomPassword(bytes = 24) {
6
+ // base64url is shell-safe and slightly shorter than hex.
7
+ return crypto.randomBytes(bytes).toString("base64url");
8
+ }
9
+ //# sourceMappingURL=secrets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../src/install/secrets.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AAEjC,MAAM,UAAU,YAAY,CAAC,KAAK,GAAG,EAAE;IACrC,OAAO,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAK,GAAG,EAAE;IACvC,yDAAyD;IACzD,OAAO,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AACzD,CAAC"}
@@ -0,0 +1,29 @@
1
+ import { promises as fs } from "node:fs";
2
+ import { ensureDir, statePath } from "./paths.js";
3
+ export async function readState(installDir) {
4
+ try {
5
+ const text = await fs.readFile(statePath(installDir), "utf8");
6
+ const parsed = JSON.parse(text);
7
+ if (parsed?.version === 1)
8
+ return parsed;
9
+ return null;
10
+ }
11
+ catch {
12
+ return null;
13
+ }
14
+ }
15
+ export async function writeState(installDir, state) {
16
+ await ensureDir(installDir);
17
+ const tmp = statePath(installDir) + ".tmp";
18
+ await fs.writeFile(tmp, JSON.stringify(state, null, 2), { mode: 0o600 });
19
+ await fs.rename(tmp, statePath(installDir));
20
+ }
21
+ export function defaultFeatures() {
22
+ return {
23
+ traefik: false,
24
+ qaBrowser: true,
25
+ codeServer: true,
26
+ googleOAuth: false,
27
+ };
28
+ }
29
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/install/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AAEzC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAgClD,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,UAAkB;IAChD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,CAAC;QAC9D,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAiB,CAAC;QAChD,IAAI,MAAM,EAAE,OAAO,KAAK,CAAC;YAAE,OAAO,MAAM,CAAC;QACzC,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,UAAkB,EAClB,KAAmB;IAEnB,MAAM,SAAS,CAAC,UAAU,CAAC,CAAC;IAC5B,MAAM,GAAG,GAAG,SAAS,CAAC,UAAU,CAAC,GAAG,MAAM,CAAC;IAC3C,MAAM,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACzE,MAAM,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,OAAO;QACL,OAAO,EAAE,KAAK;QACd,SAAS,EAAE,IAAI;QACf,UAAU,EAAE,IAAI;QAChB,WAAW,EAAE,KAAK;KACnB,CAAC;AACJ,CAAC"}
package/dist/login.js ADDED
@@ -0,0 +1,56 @@
1
+ import os from "node:os";
2
+ import chalk from "chalk";
3
+ import open from "open";
4
+ import ora from "ora";
5
+ import { initiateLogin, pollLogin } from "./api.js";
6
+ import { loadConfig, saveConfig } from "./config.js";
7
+ const POLL_INTERVAL_MS = 2000;
8
+ export async function loginCommand(opts) {
9
+ if (!opts.force) {
10
+ const existing = await loadConfig();
11
+ if (existing && existing.server === opts.server) {
12
+ console.log(chalk.green("✓"), `Already logged in to ${opts.server}. Pass --force to re-auth.`);
13
+ return existing;
14
+ }
15
+ }
16
+ const label = `${os.hostname() || "device"} (${os.userInfo().username})`;
17
+ const init = await initiateLogin(opts.server, label);
18
+ const authUrl = `${opts.server.replace(/\/$/, "")}/cli-auth/${encodeURIComponent(init.code)}`;
19
+ console.log();
20
+ console.log(chalk.bold("Opening browser to authorize this device:"), authUrl);
21
+ console.log(chalk.dim("If the browser doesn't open, copy the URL above and paste it into a browser signed in as you."));
22
+ console.log();
23
+ open(authUrl).catch(() => {
24
+ // open() can fail silently on some linux desktops without throwing —
25
+ // the user will see the URL printed above either way.
26
+ });
27
+ const spinner = ora("Waiting for approval…").start();
28
+ const deadline = new Date(init.expiresAt).getTime();
29
+ let token = null;
30
+ while (Date.now() < deadline) {
31
+ await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
32
+ const poll = await pollLogin(opts.server, init.code);
33
+ if (poll.status === "confirmed") {
34
+ token = poll.token;
35
+ break;
36
+ }
37
+ if (poll.status === "expired") {
38
+ spinner.fail("Login code expired. Re-run `withvibe login`.");
39
+ process.exit(1);
40
+ }
41
+ }
42
+ if (!token) {
43
+ spinner.fail("Timed out waiting for approval.");
44
+ process.exit(1);
45
+ }
46
+ spinner.succeed("Device approved");
47
+ const cfg = {
48
+ server: opts.server,
49
+ token,
50
+ savedAt: new Date().toISOString(),
51
+ };
52
+ await saveConfig(cfg);
53
+ console.log(chalk.green("✓"), "Saved to ~/.withvibe/config.json");
54
+ return cfg;
55
+ }
56
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../src/login.ts"],"names":[],"mappings":"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"}
package/dist/ports.js ADDED
@@ -0,0 +1,33 @@
1
+ import net from "node:net";
2
+ // Pick a free host port by asking the OS for port 0 on localhost. The OS hands
3
+ // us an ephemeral port, then we immediately close the listener. There's a
4
+ // tiny race between close+reuse, but for a compose `up` 1-2s later the odds
5
+ // of collision are negligible in practice.
6
+ export async function pickFreePort() {
7
+ return new Promise((resolve, reject) => {
8
+ const server = net.createServer();
9
+ server.unref();
10
+ server.on("error", reject);
11
+ server.listen(0, "127.0.0.1", () => {
12
+ const addr = server.address();
13
+ if (addr && typeof addr === "object") {
14
+ const port = addr.port;
15
+ server.close(() => resolve(port));
16
+ }
17
+ else {
18
+ server.close();
19
+ reject(new Error("Failed to pick free port"));
20
+ }
21
+ });
22
+ });
23
+ }
24
+ export async function pickFreePorts(n) {
25
+ const ports = [];
26
+ // Serial allocation so we don't double-assign the same OS-ephemeral port.
27
+ // The cost (a few ms per port) doesn't matter at the scale of a compose stack.
28
+ for (let i = 0; i < n; i++) {
29
+ ports.push(await pickFreePort());
30
+ }
31
+ return ports;
32
+ }
33
+ //# sourceMappingURL=ports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ports.js","sourceRoot":"","sources":["../src/ports.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,UAAU,CAAC;AAE3B,+EAA+E;AAC/E,0EAA0E;AAC1E,4EAA4E;AAC5E,2CAA2C;AAC3C,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC;QAClC,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC3B,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE;YACjC,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;YAC9B,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACrC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;gBACvB,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;YACpC,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC,CAAC;YAChD,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,CAAS;IAC3C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,0EAA0E;IAC1E,+EAA+E;IAC/E,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,KAAK,CAAC,IAAI,CAAC,MAAM,YAAY,EAAE,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,150 @@
1
+ import { promises as fs } from "node:fs";
2
+ import chalk from "chalk";
3
+ import prompts from "prompts";
4
+ import { run, which } from "./exec.js";
5
+ // On macOS the `code` shell command is NOT installed by default — the user
6
+ // has to run "Shell Command: Install 'code' command in PATH" from VSCode's
7
+ // command palette. So PATH absence ≠ VSCode absence. Same story for Cursor.
8
+ // We check the standard app bundle locations before triggering an install.
9
+ const MAC_EDITOR_APPS = [
10
+ "/Applications/Visual Studio Code.app",
11
+ "/Applications/Cursor.app",
12
+ "/Applications/VSCodium.app",
13
+ ];
14
+ async function macEditorAppExists() {
15
+ if (process.platform !== "darwin")
16
+ return null;
17
+ for (const p of MAC_EDITOR_APPS) {
18
+ try {
19
+ await fs.access(p);
20
+ return p;
21
+ }
22
+ catch {
23
+ // keep looking
24
+ }
25
+ }
26
+ return null;
27
+ }
28
+ const TOOLS = [
29
+ {
30
+ cmd: "git",
31
+ label: "Git",
32
+ installers: {
33
+ darwin: [{ cmd: "brew", args: ["install", "git"] }],
34
+ linux: [
35
+ { cmd: "apt-get", args: ["install", "-y", "git"], note: "requires sudo" },
36
+ { cmd: "dnf", args: ["install", "-y", "git"], note: "requires sudo" },
37
+ ],
38
+ win32: [{ cmd: "winget", args: ["install", "--id", "Git.Git", "-e"] }],
39
+ },
40
+ manualUrl: "https://git-scm.com/downloads",
41
+ },
42
+ {
43
+ cmd: "docker",
44
+ label: "Docker",
45
+ installers: {
46
+ darwin: [{ cmd: "brew", args: ["install", "--cask", "docker"] }],
47
+ linux: [
48
+ {
49
+ cmd: "sh",
50
+ args: ["-c", "curl -fsSL https://get.docker.com | sh"],
51
+ note: "requires sudo and adds your user to the docker group",
52
+ },
53
+ ],
54
+ win32: [{ cmd: "winget", args: ["install", "--id", "Docker.DockerDesktop", "-e"] }],
55
+ },
56
+ manualUrl: "https://docs.docker.com/get-docker/",
57
+ },
58
+ {
59
+ cmd: "code",
60
+ label: "VSCode",
61
+ optional: true,
62
+ installers: {
63
+ darwin: [{ cmd: "brew", args: ["install", "--cask", "visual-studio-code"] }],
64
+ linux: [
65
+ {
66
+ cmd: "sh",
67
+ args: ["-c", "echo 'See manual install link'; exit 1"],
68
+ note: "apt/yum repos vary — use the manual link",
69
+ },
70
+ ],
71
+ win32: [
72
+ { cmd: "winget", args: ["install", "--id", "Microsoft.VisualStudioCode", "-e"] },
73
+ ],
74
+ },
75
+ manualUrl: "https://code.visualstudio.com/download",
76
+ },
77
+ ];
78
+ export async function runPreflight({ autoInstall, }) {
79
+ let haveCode = true;
80
+ let macAppPath = null;
81
+ for (const tool of TOOLS) {
82
+ const ok = await which(tool.cmd);
83
+ if (ok) {
84
+ console.log(chalk.green("✓"), `${tool.label} found`);
85
+ continue;
86
+ }
87
+ // VSCode special case: before offering to install, check if the app
88
+ // bundle is already there and the user just hasn't installed the
89
+ // `code` shell command.
90
+ if (tool.cmd === "code") {
91
+ const appPath = await macEditorAppExists();
92
+ if (appPath) {
93
+ macAppPath = appPath;
94
+ console.log(chalk.green("✓"), `${tool.label} app installed at ${appPath}`);
95
+ console.log(chalk.dim(" (The `code` shell command isn't on PATH. We'll launch via `open -a` instead. To enable `code`: open VSCode → Command Palette → \"Shell Command: Install 'code' command in PATH\".)"));
96
+ // We have a way to launch the editor, so haveCode stays true.
97
+ continue;
98
+ }
99
+ }
100
+ console.log(chalk.yellow("!"), `${tool.label} not found on PATH`);
101
+ const installed = await offerInstall(tool, autoInstall);
102
+ if (!installed && tool.optional && tool.cmd === "code") {
103
+ haveCode = false;
104
+ continue;
105
+ }
106
+ if (!installed) {
107
+ console.error(chalk.red(`\n${tool.label} is required. Install it and re-run the command.`));
108
+ console.error(` Manual install: ${tool.manualUrl}`);
109
+ process.exit(1);
110
+ }
111
+ }
112
+ return { haveCode, macAppPath };
113
+ }
114
+ async function offerInstall(tool, autoInstall) {
115
+ const platform = process.platform;
116
+ const candidates = tool.installers[platform] || [];
117
+ // Pick the first candidate whose command is actually available on the
118
+ // system. On Linux this is how we choose between apt-get and dnf.
119
+ let chosen = null;
120
+ for (const c of candidates) {
121
+ if (c.cmd === "sh" || (await which(c.cmd))) {
122
+ chosen = c;
123
+ break;
124
+ }
125
+ }
126
+ if (!chosen) {
127
+ console.log(` No automatic installer available on ${platform}. Install manually: ${tool.manualUrl}`);
128
+ return false;
129
+ }
130
+ const noteSuffix = chosen.note ? ` (${chosen.note})` : "";
131
+ const confirmInstall = autoInstall
132
+ ? { install: true }
133
+ : await prompts({
134
+ type: "confirm",
135
+ name: "install",
136
+ message: `Install ${tool.label} via \`${chosen.cmd} ${chosen.args.join(" ")}\`${noteSuffix}?`,
137
+ initial: true,
138
+ });
139
+ if (!confirmInstall.install)
140
+ return false;
141
+ const result = await run(chosen.cmd, chosen.args, { streamTo: "inherit" });
142
+ if (result.code !== 0) {
143
+ console.error(chalk.red(`Install command exited with code ${result.code}`));
144
+ return false;
145
+ }
146
+ // Re-check PATH — some installers need a shell reload but the binary is
147
+ // usually on PATH for the next spawn already.
148
+ return await which(tool.cmd);
149
+ }
150
+ //# sourceMappingURL=preflight.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preflight.js","sourceRoot":"","sources":["../src/preflight.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "withvibe",
3
+ "version": "0.1.4",
4
+ "description": "withvibe CLI — install/manage the server stack and run shared environments locally.",
5
+ "license": "Elastic-2.0",
6
+ "type": "module",
7
+ "bin": {
8
+ "withvibe": "./dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "README.md",
13
+ "LICENSE"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc -p tsconfig.json && npm run bundle-assets",
17
+ "bundle-assets": "node -e \"const fs=require('fs');fs.mkdirSync('dist/assets',{recursive:true});fs.copyFileSync('../../docker-compose.yml','dist/assets/docker-compose.yml')\"",
18
+ "dev": "tsc -w -p tsconfig.json",
19
+ "start": "node dist/index.js",
20
+ "typecheck": "tsc --noEmit -p tsconfig.json",
21
+ "prepublishOnly": "npm run build"
22
+ },
23
+ "dependencies": {
24
+ "chalk": "^5.3.0",
25
+ "commander": "^12.1.0",
26
+ "open": "^10.1.0",
27
+ "ora": "^8.1.0",
28
+ "prompts": "^2.4.2"
29
+ },
30
+ "devDependencies": {
31
+ "@types/node": "^20",
32
+ "@types/prompts": "^2.4.9",
33
+ "typescript": "^5"
34
+ },
35
+ "engines": {
36
+ "node": ">=20"
37
+ }
38
+ }