@caik.dev/cli 0.1.6 → 0.1.7
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/dist/index.js +291 -73
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -132,6 +132,12 @@ var CaikApiClient = class {
|
|
|
132
132
|
import { readFileSync, writeFileSync, mkdirSync, chmodSync, existsSync } from "fs";
|
|
133
133
|
import { join } from "path";
|
|
134
134
|
import { homedir } from "os";
|
|
135
|
+
var CONTRIBUTION_LEVELS = [
|
|
136
|
+
{ value: "none", name: "None", description: "Nothing sent. Directory access only." },
|
|
137
|
+
{ value: "minimal", name: "Minimal", description: "Install/uninstall events only. Basic recommendations." },
|
|
138
|
+
{ value: "contributor", name: "Contributor", description: "Error/success signals + co-installs. Full recommendations. (default)" },
|
|
139
|
+
{ value: "collective", name: "Collective", description: "Workflow patterns + stack signals. Proactive recommendations." }
|
|
140
|
+
];
|
|
135
141
|
var DEFAULT_CONFIG = {
|
|
136
142
|
apiUrl: "https://www.caik.dev",
|
|
137
143
|
defaultLimit: 10,
|
|
@@ -303,7 +309,7 @@ import { existsSync as existsSync7, unlinkSync as unlinkSync2 } from "fs";
|
|
|
303
309
|
import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync6 } from "fs";
|
|
304
310
|
import { dirname as dirname3, resolve } from "path";
|
|
305
311
|
import { execSync as execSync3 } from "child_process";
|
|
306
|
-
import {
|
|
312
|
+
import { select, confirm } from "@inquirer/prompts";
|
|
307
313
|
|
|
308
314
|
// src/platform/detect.ts
|
|
309
315
|
import { existsSync as existsSync2 } from "fs";
|
|
@@ -1404,20 +1410,13 @@ Examples:
|
|
|
1404
1410
|
} else {
|
|
1405
1411
|
const detected = detectPlatforms();
|
|
1406
1412
|
if (detected.length > 1 && !opts.yes && !globalOpts.json) {
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
rl.close();
|
|
1415
|
-
const idx = parseInt(answer, 10);
|
|
1416
|
-
if (isNaN(idx) || idx < 1 || idx > detected.length) {
|
|
1417
|
-
console.log(error("Invalid selection. Aborting."));
|
|
1418
|
-
return;
|
|
1419
|
-
}
|
|
1420
|
-
detectedPlatform = detected[idx - 1].name;
|
|
1413
|
+
detectedPlatform = await select({
|
|
1414
|
+
message: "Multiple platforms detected \u2014 install for which?",
|
|
1415
|
+
choices: detected.map((d) => ({
|
|
1416
|
+
name: `${d.name} (${d.tier})`,
|
|
1417
|
+
value: d.name
|
|
1418
|
+
}))
|
|
1419
|
+
});
|
|
1421
1420
|
} else if (detected.length > 0) {
|
|
1422
1421
|
detectedPlatform = detected[0].name;
|
|
1423
1422
|
}
|
|
@@ -1463,10 +1462,11 @@ Components (${ordered.length}):`));
|
|
|
1463
1462
|
}
|
|
1464
1463
|
console.log();
|
|
1465
1464
|
if (!opts.yes && !globalOpts.json) {
|
|
1466
|
-
const
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1465
|
+
const proceed = await confirm({
|
|
1466
|
+
message: `Install all ${ordered.length} components?`,
|
|
1467
|
+
default: true
|
|
1468
|
+
});
|
|
1469
|
+
if (!proceed) {
|
|
1470
1470
|
console.log(info("Stack installation cancelled."));
|
|
1471
1471
|
return;
|
|
1472
1472
|
}
|
|
@@ -1593,10 +1593,8 @@ Components (${ordered.length}):`));
|
|
|
1593
1593
|
console.log(info(`Post-install hook: ${installInfo.postInstallHook}`));
|
|
1594
1594
|
}
|
|
1595
1595
|
console.log();
|
|
1596
|
-
const
|
|
1597
|
-
|
|
1598
|
-
rl.close();
|
|
1599
|
-
if (answer.toLowerCase() !== "y") {
|
|
1596
|
+
const proceed = await confirm({ message: "Continue?", default: true });
|
|
1597
|
+
if (!proceed) {
|
|
1600
1598
|
console.log(info("Installation cancelled."));
|
|
1601
1599
|
return;
|
|
1602
1600
|
}
|
|
@@ -1710,7 +1708,8 @@ Components (${ordered.length}):`));
|
|
|
1710
1708
|
}
|
|
1711
1709
|
|
|
1712
1710
|
// src/commands/init.ts
|
|
1713
|
-
import {
|
|
1711
|
+
import { select as select2 } from "@inquirer/prompts";
|
|
1712
|
+
import { createInterface } from "readline/promises";
|
|
1714
1713
|
import { stdin, stdout } from "process";
|
|
1715
1714
|
|
|
1716
1715
|
// src/auth.ts
|
|
@@ -1732,12 +1731,135 @@ function openBrowser(url) {
|
|
|
1732
1731
|
}
|
|
1733
1732
|
});
|
|
1734
1733
|
}
|
|
1734
|
+
function authPage(title, message, isSuccess) {
|
|
1735
|
+
const iconColor = isSuccess ? "#059669" : "#DC2626";
|
|
1736
|
+
const iconBg = isSuccess ? "rgba(5,150,105,0.1)" : "rgba(220,38,38,0.1)";
|
|
1737
|
+
const icon = isSuccess ? `<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 256 256" fill="${iconColor}"><path d="M229.66,77.66l-128,128a8,8,0,0,1-11.32,0l-56-56a8,8,0,0,1,11.32-11.32L96,188.69,218.34,66.34a8,8,0,0,1,11.32,11.32Z"/></svg>` : `<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 256 256" fill="${iconColor}"><path d="M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z"/></svg>`;
|
|
1738
|
+
return `<!DOCTYPE html>
|
|
1739
|
+
<html lang="en">
|
|
1740
|
+
<head>
|
|
1741
|
+
<meta charset="utf-8" />
|
|
1742
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
1743
|
+
<title>${title} \u2014 CAIK</title>${isSuccess ? `
|
|
1744
|
+
<script src="https://cdn.jsdelivr.net/npm/canvas-confetti@1.9.3/dist/confetti.browser.min.js"></script>` : ""}
|
|
1745
|
+
<style>
|
|
1746
|
+
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
1747
|
+
body {
|
|
1748
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
1749
|
+
background: #0C0A09;
|
|
1750
|
+
color: #FAFAF9;
|
|
1751
|
+
display: flex;
|
|
1752
|
+
align-items: center;
|
|
1753
|
+
justify-content: center;
|
|
1754
|
+
min-height: 100vh;
|
|
1755
|
+
padding: 1rem;
|
|
1756
|
+
}
|
|
1757
|
+
.card {
|
|
1758
|
+
max-width: 420px;
|
|
1759
|
+
width: 100%;
|
|
1760
|
+
background: rgba(28, 25, 23, 0.8);
|
|
1761
|
+
border: 1px solid rgba(168,162,158,0.15);
|
|
1762
|
+
border-radius: 20px;
|
|
1763
|
+
padding: 2.5rem 2rem;
|
|
1764
|
+
text-align: center;
|
|
1765
|
+
backdrop-filter: blur(12px);
|
|
1766
|
+
box-shadow: 0 25px 50px rgba(0,0,0,0.4);
|
|
1767
|
+
animation: fadeUp 0.4s ease-out;
|
|
1768
|
+
}
|
|
1769
|
+
@keyframes fadeUp {
|
|
1770
|
+
from { opacity: 0; transform: translateY(12px); }
|
|
1771
|
+
to { opacity: 1; transform: translateY(0); }
|
|
1772
|
+
}
|
|
1773
|
+
.icon-wrap {
|
|
1774
|
+
display: inline-flex;
|
|
1775
|
+
align-items: center;
|
|
1776
|
+
justify-content: center;
|
|
1777
|
+
width: 64px;
|
|
1778
|
+
height: 64px;
|
|
1779
|
+
border-radius: 50%;
|
|
1780
|
+
background: ${iconBg};
|
|
1781
|
+
margin-bottom: 1.25rem;
|
|
1782
|
+
}
|
|
1783
|
+
h1 {
|
|
1784
|
+
font-size: 1.5rem;
|
|
1785
|
+
font-weight: 700;
|
|
1786
|
+
margin-bottom: 0.5rem;
|
|
1787
|
+
letter-spacing: -0.02em;
|
|
1788
|
+
}
|
|
1789
|
+
.subtitle {
|
|
1790
|
+
font-size: 0.938rem;
|
|
1791
|
+
color: #A8A29E;
|
|
1792
|
+
line-height: 1.5;
|
|
1793
|
+
margin-bottom: 1.5rem;
|
|
1794
|
+
}
|
|
1795
|
+
.badge {
|
|
1796
|
+
display: inline-flex;
|
|
1797
|
+
align-items: center;
|
|
1798
|
+
gap: 6px;
|
|
1799
|
+
font-size: 0.75rem;
|
|
1800
|
+
font-weight: 500;
|
|
1801
|
+
padding: 6px 14px;
|
|
1802
|
+
border-radius: 999px;
|
|
1803
|
+
background: rgba(234,88,12,0.12);
|
|
1804
|
+
color: #F97316;
|
|
1805
|
+
letter-spacing: 0.01em;
|
|
1806
|
+
}
|
|
1807
|
+
.badge svg { width: 14px; height: 14px; fill: currentColor; }
|
|
1808
|
+
.divider {
|
|
1809
|
+
height: 1px;
|
|
1810
|
+
background: rgba(168,162,158,0.12);
|
|
1811
|
+
margin: 1.5rem 0;
|
|
1812
|
+
}
|
|
1813
|
+
.hint {
|
|
1814
|
+
font-size: 0.813rem;
|
|
1815
|
+
color: #78716C;
|
|
1816
|
+
}
|
|
1817
|
+
.hint code {
|
|
1818
|
+
background: rgba(168,162,158,0.12);
|
|
1819
|
+
padding: 2px 8px;
|
|
1820
|
+
border-radius: 6px;
|
|
1821
|
+
font-family: "Geist Mono", ui-monospace, monospace;
|
|
1822
|
+
font-size: 0.75rem;
|
|
1823
|
+
color: #A8A29E;
|
|
1824
|
+
}
|
|
1825
|
+
</style>
|
|
1826
|
+
</head>
|
|
1827
|
+
<body>
|
|
1828
|
+
<div class="card">
|
|
1829
|
+
<div class="icon-wrap">${icon}</div>
|
|
1830
|
+
<h1>${title}</h1>
|
|
1831
|
+
<p class="subtitle">${message}</p>
|
|
1832
|
+
<p class="hint">You can close this tab and return to your terminal.</p>
|
|
1833
|
+
</div>${isSuccess ? `
|
|
1834
|
+
<script>
|
|
1835
|
+
(function(){
|
|
1836
|
+
var colors = ["#ff640d", "#0076db", "#ff915a", "#80def9"];
|
|
1837
|
+
var end = Date.now() + 3000;
|
|
1838
|
+
function frame() {
|
|
1839
|
+
if (Date.now() > end) return;
|
|
1840
|
+
confetti({ particleCount: 2, angle: 60, spread: 55, startVelocity: 60, origin: { x: 0, y: 0.5 }, colors: colors });
|
|
1841
|
+
confetti({ particleCount: 2, angle: 120, spread: 55, startVelocity: 60, origin: { x: 1, y: 0.5 }, colors: colors });
|
|
1842
|
+
requestAnimationFrame(frame);
|
|
1843
|
+
}
|
|
1844
|
+
frame();
|
|
1845
|
+
})();
|
|
1846
|
+
</script>` : ""}
|
|
1847
|
+
</body>
|
|
1848
|
+
</html>`;
|
|
1849
|
+
}
|
|
1735
1850
|
async function authenticate(apiUrl, port = 0) {
|
|
1736
1851
|
const state = randomBytes(16).toString("hex");
|
|
1852
|
+
let resolved = false;
|
|
1853
|
+
let listenPort = 0;
|
|
1737
1854
|
return new Promise((resolve3, reject) => {
|
|
1738
1855
|
const server = createServer((req, res) => {
|
|
1739
|
-
const
|
|
1740
|
-
|
|
1856
|
+
const addr = server.address();
|
|
1857
|
+
if (!addr || typeof addr === "string") {
|
|
1858
|
+
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
1859
|
+
res.end("Not found");
|
|
1860
|
+
return;
|
|
1861
|
+
}
|
|
1862
|
+
const reqUrl = new URL2(req.url ?? "/", `http://localhost:${listenPort}`);
|
|
1741
1863
|
if (reqUrl.pathname !== "/callback") {
|
|
1742
1864
|
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
1743
1865
|
res.end("Not found");
|
|
@@ -1746,43 +1868,57 @@ async function authenticate(apiUrl, port = 0) {
|
|
|
1746
1868
|
const returnedState = reqUrl.searchParams.get("state");
|
|
1747
1869
|
if (returnedState !== state) {
|
|
1748
1870
|
res.writeHead(403, { "Content-Type": "text/html" });
|
|
1749
|
-
res.end(
|
|
1750
|
-
"
|
|
1751
|
-
|
|
1871
|
+
res.end(authPage(
|
|
1872
|
+
"Authentication Failed",
|
|
1873
|
+
"Invalid state parameter (possible CSRF attack).",
|
|
1874
|
+
false
|
|
1875
|
+
));
|
|
1752
1876
|
return;
|
|
1753
1877
|
}
|
|
1754
1878
|
const apiKeyParam = reqUrl.searchParams.get("api_key");
|
|
1755
1879
|
if (!apiKeyParam) {
|
|
1756
1880
|
res.writeHead(400, { "Content-Type": "text/html" });
|
|
1757
|
-
res.end(
|
|
1758
|
-
"
|
|
1759
|
-
|
|
1881
|
+
res.end(authPage(
|
|
1882
|
+
"Authentication Failed",
|
|
1883
|
+
"No API key was received from the server.",
|
|
1884
|
+
false
|
|
1885
|
+
));
|
|
1760
1886
|
cleanup();
|
|
1761
1887
|
reject(new Error("No API key received in callback"));
|
|
1762
1888
|
return;
|
|
1763
1889
|
}
|
|
1764
1890
|
setApiKey(apiKeyParam);
|
|
1765
1891
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
1766
|
-
res.end(
|
|
1767
|
-
"
|
|
1768
|
-
|
|
1892
|
+
res.end(authPage(
|
|
1893
|
+
"Authenticated!",
|
|
1894
|
+
"Your CLI is now connected to your CAIK account. You're ready to search, install, and publish artifacts.",
|
|
1895
|
+
true
|
|
1896
|
+
));
|
|
1897
|
+
resolved = true;
|
|
1769
1898
|
cleanup();
|
|
1770
1899
|
resolve3(apiKeyParam);
|
|
1771
1900
|
});
|
|
1772
1901
|
const timeout = setTimeout(() => {
|
|
1773
1902
|
cleanup();
|
|
1774
|
-
|
|
1903
|
+
if (!resolved) {
|
|
1904
|
+
reject(new Error("Authentication timed out after 60 seconds"));
|
|
1905
|
+
}
|
|
1775
1906
|
}, TIMEOUT_MS);
|
|
1776
1907
|
function cleanup() {
|
|
1777
1908
|
clearTimeout(timeout);
|
|
1778
1909
|
server.close();
|
|
1779
1910
|
}
|
|
1780
1911
|
server.listen(port, async () => {
|
|
1781
|
-
const
|
|
1782
|
-
|
|
1912
|
+
const addr = server.address();
|
|
1913
|
+
if (!addr || typeof addr === "string") {
|
|
1914
|
+
reject(new Error("Failed to get server address after listen"));
|
|
1915
|
+
return;
|
|
1916
|
+
}
|
|
1917
|
+
listenPort = addr.port;
|
|
1918
|
+
const callbackUrl = `http://localhost:${listenPort}/callback`;
|
|
1783
1919
|
const cliCallbackUrl = `${apiUrl}/api/auth/cli-callback?redirect=${encodeURIComponent(callbackUrl)}&state=${encodeURIComponent(state)}`;
|
|
1784
1920
|
const loginUrl = `${apiUrl}/cli-auth?continue=${encodeURIComponent(cliCallbackUrl)}`;
|
|
1785
|
-
console.log(info(`Listening on http://localhost:${
|
|
1921
|
+
console.log(info(`Listening on http://localhost:${listenPort} for callback...`));
|
|
1786
1922
|
const opened = await openBrowser(loginUrl);
|
|
1787
1923
|
if (opened) {
|
|
1788
1924
|
console.log(info("Browser opened. Complete sign-in to continue."));
|
|
@@ -1806,6 +1942,33 @@ async function authenticate(apiUrl, port = 0) {
|
|
|
1806
1942
|
}
|
|
1807
1943
|
|
|
1808
1944
|
// src/commands/init.ts
|
|
1945
|
+
async function promptContributionLevel() {
|
|
1946
|
+
const config = readConfig();
|
|
1947
|
+
if (config.contributionLevel) return;
|
|
1948
|
+
console.log("");
|
|
1949
|
+
console.log(heading("Contribution Level"));
|
|
1950
|
+
console.log("\u2500".repeat(40));
|
|
1951
|
+
console.log(dim("CAIK is powered by collective intelligence. Your agent can"));
|
|
1952
|
+
console.log(dim("contribute anonymous usage signals to improve recommendations"));
|
|
1953
|
+
console.log(dim("for everyone. No prompts, files, or personal data \u2014 ever."));
|
|
1954
|
+
console.log("");
|
|
1955
|
+
const selected = await select2({
|
|
1956
|
+
message: "What level of contribution works for you?",
|
|
1957
|
+
choices: CONTRIBUTION_LEVELS.map((l) => ({
|
|
1958
|
+
name: `${l.name} \u2014 ${l.description}`,
|
|
1959
|
+
value: l.value
|
|
1960
|
+
})),
|
|
1961
|
+
default: "contributor"
|
|
1962
|
+
});
|
|
1963
|
+
config.contributionLevel = selected;
|
|
1964
|
+
writeConfig(config);
|
|
1965
|
+
console.log(success(`Contribution level set to ${selected}`));
|
|
1966
|
+
if (selected === "none") {
|
|
1967
|
+
console.log(info("No problem \u2014 you can change this anytime with `caik config contribution`."));
|
|
1968
|
+
} else {
|
|
1969
|
+
console.log(info("Change anytime with `caik config contribution`."));
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1809
1972
|
function registerInitCommand(program2) {
|
|
1810
1973
|
program2.command("init").description("Configure the CAIK CLI").option("--no-auth", "Skip authentication, only configure API URL").addHelpText("after", `
|
|
1811
1974
|
Examples:
|
|
@@ -1830,10 +1993,12 @@ Examples:
|
|
|
1830
1993
|
console.log(info(`Config saved to ~/.caik/config.json`));
|
|
1831
1994
|
} catch (err) {
|
|
1832
1995
|
console.log(error(`Authentication failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
1996
|
+
return;
|
|
1833
1997
|
}
|
|
1998
|
+
await promptContributionLevel();
|
|
1834
1999
|
return;
|
|
1835
2000
|
}
|
|
1836
|
-
const rl =
|
|
2001
|
+
const rl = createInterface({ input: stdin, output: stdout });
|
|
1837
2002
|
try {
|
|
1838
2003
|
const apiUrl = await rl.question(`API URL (${config.apiUrl}): `);
|
|
1839
2004
|
if (apiUrl.trim()) {
|
|
@@ -1882,6 +2047,7 @@ Examples:
|
|
|
1882
2047
|
} finally {
|
|
1883
2048
|
rl.close();
|
|
1884
2049
|
}
|
|
2050
|
+
await promptContributionLevel();
|
|
1885
2051
|
});
|
|
1886
2052
|
}
|
|
1887
2053
|
|
|
@@ -2224,7 +2390,7 @@ import { existsSync as existsSync10 } from "fs";
|
|
|
2224
2390
|
import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync7 } from "fs";
|
|
2225
2391
|
import { dirname as dirname4, resolve as resolve2 } from "path";
|
|
2226
2392
|
import { execSync as execSync4 } from "child_process";
|
|
2227
|
-
import {
|
|
2393
|
+
import { confirm as confirm2 } from "@inquirer/prompts";
|
|
2228
2394
|
function registerUpdateCommand(program2) {
|
|
2229
2395
|
program2.command("update [slug]").description("Check for and apply artifact updates").option("--platform <platform>", "Filter by platform").option("-y, --yes", "Skip confirmation prompts").addHelpText("after", `
|
|
2230
2396
|
Examples:
|
|
@@ -2329,10 +2495,8 @@ Examples:
|
|
|
2329
2495
|
console.log(renderTable(["Artifact", "Platform", "Installed", "Latest"], rows));
|
|
2330
2496
|
console.log(info(`${candidates.length} update(s) available.`));
|
|
2331
2497
|
if (!skipConfirm) {
|
|
2332
|
-
const
|
|
2333
|
-
|
|
2334
|
-
rl.close();
|
|
2335
|
-
if (answer.toLowerCase() !== "y") {
|
|
2498
|
+
const proceed = await confirm2({ message: "Update all?", default: true });
|
|
2499
|
+
if (!proceed) {
|
|
2336
2500
|
console.log(info("Update cancelled."));
|
|
2337
2501
|
return;
|
|
2338
2502
|
}
|
|
@@ -2386,10 +2550,8 @@ async function performUpdate(client, entry, skipConfirm, globalOpts) {
|
|
|
2386
2550
|
console.log(info(`Install command: ${installInfo.installCommand}`));
|
|
2387
2551
|
}
|
|
2388
2552
|
console.log();
|
|
2389
|
-
const
|
|
2390
|
-
|
|
2391
|
-
rl.close();
|
|
2392
|
-
if (answer.toLowerCase() !== "y") {
|
|
2553
|
+
const proceed = await confirm2({ message: "Continue?", default: true });
|
|
2554
|
+
if (!proceed) {
|
|
2393
2555
|
console.log(info("Update cancelled."));
|
|
2394
2556
|
return;
|
|
2395
2557
|
}
|
|
@@ -2443,7 +2605,7 @@ async function performUpdate(client, entry, skipConfirm, globalOpts) {
|
|
|
2443
2605
|
}
|
|
2444
2606
|
|
|
2445
2607
|
// src/commands/uninstall.ts
|
|
2446
|
-
import {
|
|
2608
|
+
import { confirm as confirm3 } from "@inquirer/prompts";
|
|
2447
2609
|
function registerUninstallCommand(program2) {
|
|
2448
2610
|
program2.command("uninstall <slug>").description("Remove an installed artifact").option("--platform <platform>", "Target platform (disambiguates if installed on multiple)").option("-y, --yes", "Skip confirmation prompts").addHelpText("after", `
|
|
2449
2611
|
Examples:
|
|
@@ -2495,10 +2657,8 @@ Artifact: ${entry.slug} (${entry.artifactType})`));
|
|
|
2495
2657
|
}
|
|
2496
2658
|
}
|
|
2497
2659
|
if (!skipConfirm) {
|
|
2498
|
-
const
|
|
2499
|
-
|
|
2500
|
-
rl.close();
|
|
2501
|
-
if (answer.toLowerCase() !== "y") {
|
|
2660
|
+
const proceed = await confirm3({ message: "Uninstall?", default: false });
|
|
2661
|
+
if (!proceed) {
|
|
2502
2662
|
console.log(info("Uninstall cancelled."));
|
|
2503
2663
|
return;
|
|
2504
2664
|
}
|
|
@@ -2747,7 +2907,7 @@ function registerHookCommand(program2) {
|
|
|
2747
2907
|
}
|
|
2748
2908
|
|
|
2749
2909
|
// src/commands/setup.ts
|
|
2750
|
-
import {
|
|
2910
|
+
import { checkbox } from "@inquirer/prompts";
|
|
2751
2911
|
import { existsSync as existsSync12 } from "fs";
|
|
2752
2912
|
|
|
2753
2913
|
// src/platform/templates/claude-code-skill.ts
|
|
@@ -3127,23 +3287,17 @@ Examples:
|
|
|
3127
3287
|
if (autoYes || detected.length === 1 || platformFlag) {
|
|
3128
3288
|
selected = detected;
|
|
3129
3289
|
} else {
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
if (
|
|
3139
|
-
selected
|
|
3140
|
-
|
|
3141
|
-
const indices = answer.split(",").map((s) => parseInt(s.trim(), 10) - 1);
|
|
3142
|
-
selected = indices.filter((i) => i >= 0 && i < detected.length).map((i) => detected[i]);
|
|
3143
|
-
if (selected.length === 0) {
|
|
3144
|
-
console.log(warn("No valid platforms selected. Exiting."));
|
|
3145
|
-
return;
|
|
3146
|
-
}
|
|
3290
|
+
selected = await checkbox({
|
|
3291
|
+
message: "Which platforms would you like to configure?",
|
|
3292
|
+
choices: detected.map((p) => ({
|
|
3293
|
+
name: `${p.name} ${dim(`(${p.tier})`)}`,
|
|
3294
|
+
value: p,
|
|
3295
|
+
checked: true
|
|
3296
|
+
}))
|
|
3297
|
+
});
|
|
3298
|
+
if (selected.length === 0) {
|
|
3299
|
+
console.log(warn("No platforms selected. Exiting."));
|
|
3300
|
+
return;
|
|
3147
3301
|
}
|
|
3148
3302
|
}
|
|
3149
3303
|
console.log();
|
|
@@ -3343,7 +3497,7 @@ function registerUpgradeCommand(program2) {
|
|
|
3343
3497
|
});
|
|
3344
3498
|
spinner.stop();
|
|
3345
3499
|
console.log(success(`Upgraded to ${update.latest}`));
|
|
3346
|
-
} catch
|
|
3500
|
+
} catch {
|
|
3347
3501
|
spinner.stop();
|
|
3348
3502
|
console.log(error("Upgrade failed. Try manually:"));
|
|
3349
3503
|
console.log(info("npm install -g @caik.dev/cli@latest"));
|
|
@@ -3351,6 +3505,68 @@ function registerUpgradeCommand(program2) {
|
|
|
3351
3505
|
});
|
|
3352
3506
|
}
|
|
3353
3507
|
|
|
3508
|
+
// src/commands/logout.ts
|
|
3509
|
+
function registerLogoutCommand(program2) {
|
|
3510
|
+
program2.command("logout").description("Sign out and remove stored API key").action(() => {
|
|
3511
|
+
const config = readConfig();
|
|
3512
|
+
if (!config.apiKey) {
|
|
3513
|
+
console.log(info("No API key stored \u2014 already signed out."));
|
|
3514
|
+
return;
|
|
3515
|
+
}
|
|
3516
|
+
delete config.apiKey;
|
|
3517
|
+
writeConfig(config);
|
|
3518
|
+
console.log(success("Signed out. API key removed from ~/.caik/config.json"));
|
|
3519
|
+
});
|
|
3520
|
+
}
|
|
3521
|
+
|
|
3522
|
+
// src/commands/config.ts
|
|
3523
|
+
import { select as select3 } from "@inquirer/prompts";
|
|
3524
|
+
function registerConfigCommand(program2) {
|
|
3525
|
+
const cmd = program2.command("config").description("View or update CLI configuration");
|
|
3526
|
+
cmd.command("show").description("Show current configuration").action(() => {
|
|
3527
|
+
const config = readConfig();
|
|
3528
|
+
console.log(heading("\nCAIK Configuration"));
|
|
3529
|
+
console.log("\u2500".repeat(40));
|
|
3530
|
+
console.log(` API URL: ${config.apiUrl}`);
|
|
3531
|
+
console.log(` API Key: ${config.apiKey ? "\u2022\u2022\u2022\u2022" + config.apiKey.slice(-6) : dim("not set")}`);
|
|
3532
|
+
console.log(` Contribution Level: ${config.contributionLevel ?? "contributor"} ${dim("(default)")}`);
|
|
3533
|
+
console.log(` Default Platform: ${config.defaultPlatform ?? dim("auto-detect")}`);
|
|
3534
|
+
console.log(` Config Path: ${dim("~/.caik/config.json")}`);
|
|
3535
|
+
console.log();
|
|
3536
|
+
});
|
|
3537
|
+
cmd.command("contribution").description("Set your contribution level").argument("[level]", "Level to set: none, minimal, contributor, collective").action(async (level) => {
|
|
3538
|
+
const config = readConfig();
|
|
3539
|
+
const current = config.contributionLevel ?? "contributor";
|
|
3540
|
+
if (level) {
|
|
3541
|
+
const valid = CONTRIBUTION_LEVELS.map((l) => l.value);
|
|
3542
|
+
if (!valid.includes(level)) {
|
|
3543
|
+
console.log(`Invalid level "${level}". Choose: ${valid.join(", ")}`);
|
|
3544
|
+
return;
|
|
3545
|
+
}
|
|
3546
|
+
config.contributionLevel = level;
|
|
3547
|
+
writeConfig(config);
|
|
3548
|
+
console.log(success(`Contribution level set to ${level}`));
|
|
3549
|
+
return;
|
|
3550
|
+
}
|
|
3551
|
+
const selected = await select3({
|
|
3552
|
+
message: "Select your contribution level",
|
|
3553
|
+
choices: CONTRIBUTION_LEVELS.map((l) => ({
|
|
3554
|
+
name: `${l.name} \u2014 ${l.description}`,
|
|
3555
|
+
value: l.value
|
|
3556
|
+
})),
|
|
3557
|
+
default: current
|
|
3558
|
+
});
|
|
3559
|
+
config.contributionLevel = selected;
|
|
3560
|
+
writeConfig(config);
|
|
3561
|
+
console.log(success(`Contribution level set to ${selected}`));
|
|
3562
|
+
if (selected === "none") {
|
|
3563
|
+
console.log(info("No telemetry will be sent. You can still search and install artifacts."));
|
|
3564
|
+
} else if (selected === "collective") {
|
|
3565
|
+
console.log(info("Thank you! You'll get proactive recommendations and provider analytics."));
|
|
3566
|
+
}
|
|
3567
|
+
});
|
|
3568
|
+
}
|
|
3569
|
+
|
|
3354
3570
|
// src/index.ts
|
|
3355
3571
|
var __filename = fileURLToPath(import.meta.url);
|
|
3356
3572
|
var __dirname = dirname5(__filename);
|
|
@@ -3365,6 +3581,8 @@ var program = new Command().name("caik").description("CAIK \u2014 Collective AI
|
|
|
3365
3581
|
registerSearchCommand(program);
|
|
3366
3582
|
registerInstallCommand(program);
|
|
3367
3583
|
registerInitCommand(program);
|
|
3584
|
+
registerLogoutCommand(program);
|
|
3585
|
+
registerConfigCommand(program);
|
|
3368
3586
|
registerStatusCommand(program);
|
|
3369
3587
|
registerStatsCommand(program);
|
|
3370
3588
|
registerPublishCommand(program);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@caik.dev/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "CAIK CLI — Search, install, and publish AI artifacts from your terminal",
|
|
6
6
|
"keywords": [
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"typecheck": "tsc --noEmit"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
+
"@inquirer/prompts": "^8.3.2",
|
|
37
38
|
"chalk": "^5.6.2",
|
|
38
39
|
"cli-table3": "^0.6.5",
|
|
39
40
|
"commander": "^14.0.3",
|