create-hq 7.0.0 → 10.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.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=deps.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deps.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/deps.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,176 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { getInstallCommand } from "../deps.js";
3
+ // ─── Test Fixtures ──────────────────────────────────────────────────────────
4
+ function makeDep(overrides = {}) {
5
+ return {
6
+ name: "test-dep",
7
+ command: "test --version",
8
+ required: true,
9
+ installHint: "brew install test",
10
+ autoInstallable: true,
11
+ installCommands: {},
12
+ ...overrides,
13
+ };
14
+ }
15
+ function makePlatform(overrides = {}) {
16
+ return {
17
+ os: "macos",
18
+ packageManager: "brew",
19
+ npmAvailable: true,
20
+ ...overrides,
21
+ };
22
+ }
23
+ const yqDep = makeDep({
24
+ name: "yq",
25
+ command: "yq --version",
26
+ installHint: "brew install yq",
27
+ installCommands: {
28
+ brew: "brew install yq",
29
+ apt: "sudo snap install yq",
30
+ dnf: "sudo dnf install yq",
31
+ pacman: "sudo pacman -S yq",
32
+ },
33
+ });
34
+ const ghDep = makeDep({
35
+ name: "gh CLI",
36
+ command: "gh --version",
37
+ required: false,
38
+ installHint: "brew install gh",
39
+ installCommands: {
40
+ brew: "brew install gh",
41
+ apt: "sudo apt install gh",
42
+ dnf: "sudo dnf install gh",
43
+ pacman: "sudo pacman -S github-cli",
44
+ },
45
+ });
46
+ const claudeCodeDep = makeDep({
47
+ name: "Claude Code CLI",
48
+ command: "claude --version",
49
+ installHint: "npm install -g @anthropic-ai/claude-code",
50
+ installCommands: {
51
+ npm: "npm install -g @anthropic-ai/claude-code",
52
+ },
53
+ });
54
+ const qmdDep = makeDep({
55
+ name: "qmd (search)",
56
+ command: "qmd --version",
57
+ installHint: "npm install -g @tobilu/qmd",
58
+ installCommands: {
59
+ npm: "npm install -g @tobilu/qmd",
60
+ },
61
+ });
62
+ const vercelDep = makeDep({
63
+ name: "Vercel CLI",
64
+ command: "vercel --version",
65
+ required: false,
66
+ installHint: "npm install -g vercel",
67
+ installCommands: {
68
+ npm: "npm install -g vercel",
69
+ },
70
+ });
71
+ const hqCliDep = makeDep({
72
+ name: "hq-cli",
73
+ command: "hq --version",
74
+ required: false,
75
+ installHint: "npm install -g @indigoai-us/hq-cli",
76
+ installCommands: {
77
+ npm: "npm install -g @indigoai-us/hq-cli",
78
+ },
79
+ });
80
+ const nodeDep = makeDep({
81
+ name: "Node.js",
82
+ command: "node --version",
83
+ required: true,
84
+ installHint: "https://nodejs.org",
85
+ autoInstallable: false,
86
+ installCommands: {},
87
+ });
88
+ // ─── Platforms ──────────────────────────────────────────────────────────────
89
+ const macBrew = makePlatform({ os: "macos", packageManager: "brew", npmAvailable: true });
90
+ const linuxApt = makePlatform({ os: "linux-debian", packageManager: "apt", npmAvailable: true });
91
+ const linuxDnf = makePlatform({ os: "linux-fedora", packageManager: "dnf", npmAvailable: true });
92
+ const linuxPacman = makePlatform({ os: "linux-arch", packageManager: "pacman", npmAvailable: true });
93
+ const linuxYum = makePlatform({ os: "linux-fedora", packageManager: "yum", npmAvailable: true });
94
+ const noPmNoNpm = makePlatform({ os: "unix", packageManager: null, npmAvailable: false });
95
+ const noPmWithNpm = makePlatform({ os: "unix", packageManager: null, npmAvailable: true });
96
+ // ─── Tests ──────────────────────────────────────────────────────────────────
97
+ describe("getInstallCommand", () => {
98
+ describe("macOS + brew", () => {
99
+ it("returns brew command for yq", () => {
100
+ expect(getInstallCommand(yqDep, macBrew)).toBe("brew install yq");
101
+ });
102
+ it("returns brew command for gh CLI", () => {
103
+ expect(getInstallCommand(ghDep, macBrew)).toBe("brew install gh");
104
+ });
105
+ it("returns npm command for npm-only deps (prefers system PM, falls back to npm)", () => {
106
+ // Claude Code only has npm install command, no brew
107
+ expect(getInstallCommand(claudeCodeDep, macBrew)).toBe("npm install -g @anthropic-ai/claude-code");
108
+ });
109
+ });
110
+ describe("Linux + apt", () => {
111
+ it("returns apt command for yq", () => {
112
+ expect(getInstallCommand(yqDep, linuxApt)).toBe("sudo snap install yq");
113
+ });
114
+ it("returns apt command for gh CLI", () => {
115
+ expect(getInstallCommand(ghDep, linuxApt)).toBe("sudo apt install gh");
116
+ });
117
+ });
118
+ describe("Linux + dnf", () => {
119
+ it("returns dnf command for yq", () => {
120
+ expect(getInstallCommand(yqDep, linuxDnf)).toBe("sudo dnf install yq");
121
+ });
122
+ });
123
+ describe("Linux + pacman", () => {
124
+ it("returns pacman command for gh CLI", () => {
125
+ expect(getInstallCommand(ghDep, linuxPacman)).toBe("sudo pacman -S github-cli");
126
+ });
127
+ });
128
+ describe("yum → dnf fallback", () => {
129
+ it("maps yum to dnf commands", () => {
130
+ expect(getInstallCommand(yqDep, linuxYum)).toBe("sudo dnf install yq");
131
+ });
132
+ });
133
+ describe("npm-only deps", () => {
134
+ it("returns npm command for Claude Code when npm available", () => {
135
+ expect(getInstallCommand(claudeCodeDep, noPmWithNpm)).toBe("npm install -g @anthropic-ai/claude-code");
136
+ });
137
+ it("returns npm command for qmd when npm available", () => {
138
+ expect(getInstallCommand(qmdDep, noPmWithNpm)).toBe("npm install -g @tobilu/qmd");
139
+ });
140
+ it("returns npm command for Vercel CLI when npm available", () => {
141
+ expect(getInstallCommand(vercelDep, noPmWithNpm)).toBe("npm install -g vercel");
142
+ });
143
+ it("returns npm command for hq-cli when npm available", () => {
144
+ expect(getInstallCommand(hqCliDep, noPmWithNpm)).toBe("npm install -g @indigoai-us/hq-cli");
145
+ });
146
+ it("returns null for npm-only deps when npm not available", () => {
147
+ expect(getInstallCommand(claudeCodeDep, noPmNoNpm)).toBeNull();
148
+ });
149
+ });
150
+ describe("Node.js dep (no install path)", () => {
151
+ it("returns null — empty installCommands", () => {
152
+ expect(getInstallCommand(nodeDep, macBrew)).toBeNull();
153
+ });
154
+ it("returns null even with npm available", () => {
155
+ expect(getInstallCommand(nodeDep, noPmWithNpm)).toBeNull();
156
+ });
157
+ it("has autoInstallable set to false", () => {
158
+ expect(nodeDep.autoInstallable).toBe(false);
159
+ });
160
+ });
161
+ describe("no matching package manager and no npm", () => {
162
+ it("returns null for system deps when no PM and no npm", () => {
163
+ expect(getInstallCommand(yqDep, noPmNoNpm)).toBeNull();
164
+ });
165
+ it("returns null for gh CLI when no PM and no npm", () => {
166
+ expect(getInstallCommand(ghDep, noPmNoNpm)).toBeNull();
167
+ });
168
+ });
169
+ describe("npm fallback for system deps", () => {
170
+ it("falls back to npm when no system PM but npm available (for deps with npm command)", () => {
171
+ // yq has no npm command, so should return null
172
+ expect(getInstallCommand(yqDep, noPmWithNpm)).toBeNull();
173
+ });
174
+ });
175
+ });
176
+ //# sourceMappingURL=deps.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deps.test.js","sourceRoot":"","sources":["../../src/__tests__/deps.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=platform.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/platform.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,127 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
+ // We need to mock child_process before importing the module
3
+ const mockExecSync = vi.fn();
4
+ vi.mock("child_process", () => ({
5
+ execSync: (...args) => mockExecSync(...args),
6
+ }));
7
+ // Dynamic import so mocks are in place
8
+ const { detectPlatform } = await import("../platform.js");
9
+ describe("detectPlatform", () => {
10
+ const validOsTypes = [
11
+ "macos",
12
+ "linux-debian",
13
+ "linux-fedora",
14
+ "linux-arch",
15
+ "linux",
16
+ "unix",
17
+ ];
18
+ const validPackageManagers = [
19
+ "brew",
20
+ "apt",
21
+ "dnf",
22
+ "yum",
23
+ "pacman",
24
+ null,
25
+ ];
26
+ beforeEach(() => {
27
+ mockExecSync.mockReset();
28
+ });
29
+ afterEach(() => {
30
+ vi.restoreAllMocks();
31
+ });
32
+ it("returns a PlatformInfo object with valid os field matching process.platform", () => {
33
+ // Let hasBin calls succeed for common tools
34
+ mockExecSync.mockImplementation((cmd) => {
35
+ if (cmd === "which brew")
36
+ return Buffer.from("/opt/homebrew/bin/brew");
37
+ if (cmd === "which npm")
38
+ return Buffer.from("/usr/local/bin/npm");
39
+ throw new Error("not found");
40
+ });
41
+ const result = detectPlatform();
42
+ expect(result).toHaveProperty("os");
43
+ expect(result).toHaveProperty("packageManager");
44
+ expect(result).toHaveProperty("npmAvailable");
45
+ expect(validOsTypes).toContain(result.os);
46
+ // On macOS CI/local, process.platform is "darwin" → os should be "macos"
47
+ if (process.platform === "darwin") {
48
+ expect(result.os).toBe("macos");
49
+ }
50
+ else if (process.platform === "linux") {
51
+ expect(result.os).toMatch(/^linux/);
52
+ }
53
+ });
54
+ it("npmAvailable is a boolean", () => {
55
+ mockExecSync.mockImplementation((cmd) => {
56
+ if (cmd === "which npm")
57
+ return Buffer.from("/usr/local/bin/npm");
58
+ throw new Error("not found");
59
+ });
60
+ const result = detectPlatform();
61
+ expect(typeof result.npmAvailable).toBe("boolean");
62
+ });
63
+ it("packageManager is a valid value or null", () => {
64
+ mockExecSync.mockImplementation(() => {
65
+ throw new Error("not found");
66
+ });
67
+ const result = detectPlatform();
68
+ expect(validPackageManagers).toContain(result.packageManager);
69
+ });
70
+ it("detects brew on macOS when brew is available", () => {
71
+ // Mock process.platform to darwin
72
+ const originalPlatform = process.platform;
73
+ Object.defineProperty(process, "platform", { value: "darwin", writable: true });
74
+ mockExecSync.mockImplementation((cmd) => {
75
+ if (cmd === "which brew")
76
+ return Buffer.from("/opt/homebrew/bin/brew");
77
+ if (cmd === "which npm")
78
+ return Buffer.from("/usr/local/bin/npm");
79
+ throw new Error("not found");
80
+ });
81
+ const result = detectPlatform();
82
+ expect(result.os).toBe("macos");
83
+ expect(result.packageManager).toBe("brew");
84
+ expect(result.npmAvailable).toBe(true);
85
+ Object.defineProperty(process, "platform", { value: originalPlatform, writable: true });
86
+ });
87
+ it("returns null packageManager on macOS when brew is not available", () => {
88
+ const originalPlatform = process.platform;
89
+ Object.defineProperty(process, "platform", { value: "darwin", writable: true });
90
+ mockExecSync.mockImplementation(() => {
91
+ throw new Error("not found");
92
+ });
93
+ const result = detectPlatform();
94
+ expect(result.os).toBe("macos");
95
+ expect(result.packageManager).toBeNull();
96
+ Object.defineProperty(process, "platform", { value: originalPlatform, writable: true });
97
+ });
98
+ it("detects apt on linux-debian", () => {
99
+ const originalPlatform = process.platform;
100
+ Object.defineProperty(process, "platform", { value: "linux", writable: true });
101
+ mockExecSync.mockImplementation((cmd) => {
102
+ if (cmd === "cat /etc/os-release") {
103
+ return Buffer.from('ID=ubuntu\nID_LIKE=debian\nVERSION_ID="22.04"');
104
+ }
105
+ if (cmd === "which apt")
106
+ return Buffer.from("/usr/bin/apt");
107
+ if (cmd === "which npm")
108
+ return Buffer.from("/usr/bin/npm");
109
+ throw new Error("not found");
110
+ });
111
+ const result = detectPlatform();
112
+ expect(result.os).toBe("linux-debian");
113
+ expect(result.packageManager).toBe("apt");
114
+ Object.defineProperty(process, "platform", { value: originalPlatform, writable: true });
115
+ });
116
+ it("returns 'unix' for non-darwin non-linux platforms", () => {
117
+ const originalPlatform = process.platform;
118
+ Object.defineProperty(process, "platform", { value: "freebsd", writable: true });
119
+ mockExecSync.mockImplementation(() => {
120
+ throw new Error("not found");
121
+ });
122
+ const result = detectPlatform();
123
+ expect(result.os).toBe("unix");
124
+ Object.defineProperty(process, "platform", { value: originalPlatform, writable: true });
125
+ });
126
+ });
127
+ //# sourceMappingURL=platform.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform.test.js","sourceRoot":"","sources":["../../src/__tests__/platform.test.ts"],"names":[],"mappings":"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"}
package/dist/auth.d.ts ADDED
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Auth utilities for create-hq — OAuth PKCE flow for Clerk (US-008)
3
+ *
4
+ * Reuses the same patterns as hq-cli/src/utils/auth.ts and
5
+ * hq-cli/src/utils/token-store.ts but bundled inline so create-hq
6
+ * has no dependency on @indigoai-us/hq-cli.
7
+ *
8
+ * Token values are NEVER written to stdout or logs.
9
+ */
10
+ export interface AuthToken {
11
+ clerk_session_token: string;
12
+ user_id: string;
13
+ email: string;
14
+ expires_at: string;
15
+ }
16
+ /** Save auth token to ~/.hq/auth.json with 0600 permissions. */
17
+ export declare function saveToken(token: AuthToken): void;
18
+ /** Load auth token from ~/.hq/auth.json. Returns null if missing/invalid. */
19
+ export declare function loadToken(): AuthToken | null;
20
+ /** Check if a token is expired or within 5 minutes of expiry. */
21
+ export declare function isTokenExpired(token: AuthToken): boolean;
22
+ /**
23
+ * Start the OAuth PKCE auth flow:
24
+ * 1. Generate PKCE code_verifier + code_challenge
25
+ * 2. Start local HTTP server on a random port for the callback
26
+ * 3. Open browser to Clerk auth URL
27
+ * 4. Wait for callback with auth code
28
+ * 5. Exchange code for token via registry /auth/token endpoint
29
+ * 6. Save token and return AuthToken
30
+ */
31
+ export declare function startAuthFlow(registryUrl: string): Promise<AuthToken>;
32
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAWH,MAAM,WAAW,SAAS;IACxB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAaD,gEAAgE;AAChE,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAIhD;AAED,6EAA6E;AAC7E,wBAAgB,SAAS,IAAI,SAAS,GAAG,IAAI,CAqB5C;AAED,iEAAiE;AACjE,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAIxD;AA0BD;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAkG3E"}
package/dist/auth.js ADDED
@@ -0,0 +1,156 @@
1
+ /**
2
+ * Auth utilities for create-hq — OAuth PKCE flow for Clerk (US-008)
3
+ *
4
+ * Reuses the same patterns as hq-cli/src/utils/auth.ts and
5
+ * hq-cli/src/utils/token-store.ts but bundled inline so create-hq
6
+ * has no dependency on @indigoai-us/hq-cli.
7
+ *
8
+ * Token values are NEVER written to stdout or logs.
9
+ */
10
+ import * as crypto from "crypto";
11
+ import * as http from "http";
12
+ import * as fs from "fs";
13
+ import * as path from "path";
14
+ import * as os from "os";
15
+ import { exec } from "child_process";
16
+ const HQ_DIR = path.join(os.homedir(), ".hq");
17
+ const AUTH_FILE = path.join(HQ_DIR, "auth.json");
18
+ // ─── Token store ─────────────────────────────────────────────────────────────
19
+ function ensureHqDir() {
20
+ if (!fs.existsSync(HQ_DIR)) {
21
+ fs.mkdirSync(HQ_DIR, { recursive: true, mode: 0o700 });
22
+ }
23
+ }
24
+ /** Save auth token to ~/.hq/auth.json with 0600 permissions. */
25
+ export function saveToken(token) {
26
+ ensureHqDir();
27
+ const content = JSON.stringify(token, null, 2);
28
+ fs.writeFileSync(AUTH_FILE, content, { mode: 0o600 });
29
+ }
30
+ /** Load auth token from ~/.hq/auth.json. Returns null if missing/invalid. */
31
+ export function loadToken() {
32
+ try {
33
+ if (!fs.existsSync(AUTH_FILE)) {
34
+ return null;
35
+ }
36
+ const content = fs.readFileSync(AUTH_FILE, "utf-8");
37
+ const parsed = JSON.parse(content);
38
+ if (typeof parsed.clerk_session_token !== "string" ||
39
+ typeof parsed.user_id !== "string" ||
40
+ typeof parsed.email !== "string" ||
41
+ typeof parsed.expires_at !== "string") {
42
+ return null;
43
+ }
44
+ return parsed;
45
+ }
46
+ catch {
47
+ return null;
48
+ }
49
+ }
50
+ /** Check if a token is expired or within 5 minutes of expiry. */
51
+ export function isTokenExpired(token) {
52
+ const expiresAt = new Date(token.expires_at).getTime();
53
+ const bufferMs = 5 * 60 * 1000;
54
+ return Date.now() >= expiresAt - bufferMs;
55
+ }
56
+ // ─── PKCE helpers ────────────────────────────────────────────────────────────
57
+ function generateCodeVerifier() {
58
+ return crypto.randomBytes(32).toString("base64url");
59
+ }
60
+ function generateCodeChallenge(verifier) {
61
+ return crypto.createHash("sha256").update(verifier).digest("base64url");
62
+ }
63
+ function openBrowser(url) {
64
+ const command = process.platform === "darwin" ? `open "${url}"` : `xdg-open "${url}"`;
65
+ exec(command, (err) => {
66
+ if (err) {
67
+ console.error(`Could not open browser automatically. Please visit:\n ${url}`);
68
+ }
69
+ });
70
+ }
71
+ // ─── Auth flow ───────────────────────────────────────────────────────────────
72
+ /**
73
+ * Start the OAuth PKCE auth flow:
74
+ * 1. Generate PKCE code_verifier + code_challenge
75
+ * 2. Start local HTTP server on a random port for the callback
76
+ * 3. Open browser to Clerk auth URL
77
+ * 4. Wait for callback with auth code
78
+ * 5. Exchange code for token via registry /auth/token endpoint
79
+ * 6. Save token and return AuthToken
80
+ */
81
+ export async function startAuthFlow(registryUrl) {
82
+ const codeVerifier = generateCodeVerifier();
83
+ const codeChallenge = generateCodeChallenge(codeVerifier);
84
+ return new Promise((resolve, reject) => {
85
+ const server = http.createServer(async (req, res) => {
86
+ try {
87
+ const url = new URL(req.url ?? "/", "http://localhost");
88
+ if (url.pathname !== "/callback") {
89
+ res.writeHead(404);
90
+ res.end("Not found");
91
+ return;
92
+ }
93
+ const code = url.searchParams.get("code");
94
+ const error = url.searchParams.get("error");
95
+ if (error) {
96
+ res.writeHead(200, { "Content-Type": "text/html" });
97
+ res.end("<html><body><h2>Authentication failed</h2><p>You can close this window.</p></body></html>");
98
+ server.close();
99
+ reject(new Error(`Auth failed: ${error}`));
100
+ return;
101
+ }
102
+ if (!code) {
103
+ res.writeHead(400, { "Content-Type": "text/html" });
104
+ res.end("<html><body><h2>Missing auth code</h2><p>You can close this window.</p></body></html>");
105
+ server.close();
106
+ reject(new Error("No authorization code received"));
107
+ return;
108
+ }
109
+ // Exchange code for token
110
+ const tokenResponse = await fetch(`${registryUrl}/auth/token`, {
111
+ method: "POST",
112
+ headers: { "Content-Type": "application/json" },
113
+ body: JSON.stringify({
114
+ code,
115
+ code_verifier: codeVerifier,
116
+ redirect_uri: `http://localhost:${server.address().port}/callback`,
117
+ }),
118
+ });
119
+ if (!tokenResponse.ok) {
120
+ const body = await tokenResponse.text();
121
+ res.writeHead(200, { "Content-Type": "text/html" });
122
+ res.end("<html><body><h2>Token exchange failed</h2><p>You can close this window.</p></body></html>");
123
+ server.close();
124
+ reject(new Error(`Token exchange failed (${tokenResponse.status}): ${body}`));
125
+ return;
126
+ }
127
+ const tokenData = (await tokenResponse.json());
128
+ // Save token to ~/.hq/auth.json
129
+ saveToken(tokenData);
130
+ res.writeHead(200, { "Content-Type": "text/html" });
131
+ res.end("<html><body><h2>Authenticated!</h2><p>You can close this window and return to the terminal.</p></body></html>");
132
+ server.close();
133
+ resolve(tokenData);
134
+ }
135
+ catch (err) {
136
+ server.close();
137
+ reject(err);
138
+ }
139
+ });
140
+ // Listen on random port
141
+ server.listen(0, "127.0.0.1", () => {
142
+ const addr = server.address();
143
+ const redirectUri = `http://localhost:${addr.port}/callback`;
144
+ const authUrl = `${registryUrl}/auth/login?redirect_uri=${encodeURIComponent(redirectUri)}&code_challenge=${codeChallenge}&code_challenge_method=S256`;
145
+ console.log(" Opening browser for authentication...");
146
+ openBrowser(authUrl);
147
+ console.log(`\n If the browser doesn't open, visit:\n ${authUrl}\n`);
148
+ });
149
+ // Timeout after 2 minutes
150
+ setTimeout(() => {
151
+ server.close();
152
+ reject(new Error("Authentication timed out after 2 minutes"));
153
+ }, 120_000);
154
+ });
155
+ }
156
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
package/dist/deps.d.ts CHANGED
@@ -1,4 +1,34 @@
1
- export declare function checkDeps(): {
1
+ import type { PlatformInfo } from "./platform.js";
2
+ export type DepStatus = "installed" | "just-installed" | "missing" | "skipped";
3
+ export interface DepResult {
4
+ name: string;
5
+ required: boolean;
6
+ status: DepStatus;
7
+ version?: string;
8
+ installHint: string;
9
+ }
10
+ export interface InstallCommands {
11
+ brew?: string;
12
+ apt?: string;
13
+ dnf?: string;
14
+ pacman?: string;
15
+ npm?: string;
16
+ }
17
+ export interface Dep {
18
+ name: string;
19
+ command: string;
20
+ required: boolean;
21
+ installHint: string;
22
+ autoInstallable: boolean;
23
+ installCommands: InstallCommands;
24
+ }
25
+ /**
26
+ * Pick the best install command for a dep given the detected platform.
27
+ * Prefers the system package manager, falls back to npm if available.
28
+ * Returns null when no suitable command exists (e.g. Node.js — manual install).
29
+ */
30
+ export declare function getInstallCommand(dep: Dep, platform: PlatformInfo): string | null;
31
+ export declare function checkDeps(): Promise<{
2
32
  allRequired: boolean;
3
- };
33
+ }>;
4
34
  //# sourceMappingURL=deps.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"deps.d.ts","sourceRoot":"","sources":["../src/deps.ts"],"names":[],"mappings":"AA2DA,wBAAgB,SAAS,IAAI;IAAE,WAAW,EAAE,OAAO,CAAA;CAAE,CAoBpD"}
1
+ {"version":3,"file":"deps.d.ts","sourceRoot":"","sources":["../src/deps.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,MAAM,MAAM,SAAS,GAAG,WAAW,GAAG,gBAAgB,GAAG,SAAS,GAAG,SAAS,CAAC;AAE/E,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,SAAS,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,GAAG;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,OAAO,CAAC;IACzB,eAAe,EAAE,eAAe,CAAC;CAClC;AA+ED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,GAAG,EACR,QAAQ,EAAE,YAAY,GACrB,MAAM,GAAG,IAAI,CAef;AAoCD,wBAAsB,SAAS,IAAI,OAAO,CAAC;IAAE,WAAW,EAAE,OAAO,CAAA;CAAE,CAAC,CA+EnE"}