@caik.dev/cli 0.1.7 → 0.1.8
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 +315 -294
- package/package.json +1 -2
package/dist/index.js
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { Command } from "commander";
|
|
5
|
-
import { readFileSync as
|
|
5
|
+
import { readFileSync as readFileSync10 } from "fs";
|
|
6
6
|
import { fileURLToPath } from "url";
|
|
7
|
-
import { dirname as dirname5, join as
|
|
7
|
+
import { dirname as dirname5, join as join10 } from "path";
|
|
8
8
|
import chalk3 from "chalk";
|
|
9
9
|
|
|
10
10
|
// src/errors.ts
|
|
@@ -132,12 +132,6 @@ 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
|
-
];
|
|
141
135
|
var DEFAULT_CONFIG = {
|
|
142
136
|
apiUrl: "https://www.caik.dev",
|
|
143
137
|
defaultLimit: 10,
|
|
@@ -309,7 +303,7 @@ import { existsSync as existsSync7, unlinkSync as unlinkSync2 } from "fs";
|
|
|
309
303
|
import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync6 } from "fs";
|
|
310
304
|
import { dirname as dirname3, resolve } from "path";
|
|
311
305
|
import { execSync as execSync3 } from "child_process";
|
|
312
|
-
import {
|
|
306
|
+
import { createInterface } from "readline/promises";
|
|
313
307
|
|
|
314
308
|
// src/platform/detect.ts
|
|
315
309
|
import { existsSync as existsSync2 } from "fs";
|
|
@@ -1410,13 +1404,20 @@ Examples:
|
|
|
1410
1404
|
} else {
|
|
1411
1405
|
const detected = detectPlatforms();
|
|
1412
1406
|
if (detected.length > 1 && !opts.yes && !globalOpts.json) {
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
});
|
|
1407
|
+
console.log(info("Multiple platforms detected:"));
|
|
1408
|
+
for (let i = 0; i < detected.length; i++) {
|
|
1409
|
+
const d = detected[i];
|
|
1410
|
+
console.log(info(` ${i + 1}) ${d.name} (${d.tier})`));
|
|
1411
|
+
}
|
|
1412
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
1413
|
+
const answer = await rl.question(`Select platform [1-${detected.length}]: `);
|
|
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;
|
|
1420
1421
|
} else if (detected.length > 0) {
|
|
1421
1422
|
detectedPlatform = detected[0].name;
|
|
1422
1423
|
}
|
|
@@ -1462,11 +1463,10 @@ Components (${ordered.length}):`));
|
|
|
1462
1463
|
}
|
|
1463
1464
|
console.log();
|
|
1464
1465
|
if (!opts.yes && !globalOpts.json) {
|
|
1465
|
-
const
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
if (!proceed) {
|
|
1466
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
1467
|
+
const answer = await rl.question(`Install all ${ordered.length} components? (y/N) `);
|
|
1468
|
+
rl.close();
|
|
1469
|
+
if (answer.toLowerCase() !== "y") {
|
|
1470
1470
|
console.log(info("Stack installation cancelled."));
|
|
1471
1471
|
return;
|
|
1472
1472
|
}
|
|
@@ -1593,8 +1593,10 @@ Components (${ordered.length}):`));
|
|
|
1593
1593
|
console.log(info(`Post-install hook: ${installInfo.postInstallHook}`));
|
|
1594
1594
|
}
|
|
1595
1595
|
console.log();
|
|
1596
|
-
const
|
|
1597
|
-
|
|
1596
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
1597
|
+
const answer = await rl.question("Continue? (y/N) ");
|
|
1598
|
+
rl.close();
|
|
1599
|
+
if (answer.toLowerCase() !== "y") {
|
|
1598
1600
|
console.log(info("Installation cancelled."));
|
|
1599
1601
|
return;
|
|
1600
1602
|
}
|
|
@@ -1708,8 +1710,7 @@ Components (${ordered.length}):`));
|
|
|
1708
1710
|
}
|
|
1709
1711
|
|
|
1710
1712
|
// src/commands/init.ts
|
|
1711
|
-
import {
|
|
1712
|
-
import { createInterface } from "readline/promises";
|
|
1713
|
+
import { createInterface as createInterface2 } from "readline/promises";
|
|
1713
1714
|
import { stdin, stdout } from "process";
|
|
1714
1715
|
|
|
1715
1716
|
// src/auth.ts
|
|
@@ -1731,135 +1732,12 @@ function openBrowser(url) {
|
|
|
1731
1732
|
}
|
|
1732
1733
|
});
|
|
1733
1734
|
}
|
|
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
|
-
}
|
|
1850
1735
|
async function authenticate(apiUrl, port = 0) {
|
|
1851
1736
|
const state = randomBytes(16).toString("hex");
|
|
1852
|
-
let resolved = false;
|
|
1853
|
-
let listenPort = 0;
|
|
1854
1737
|
return new Promise((resolve3, reject) => {
|
|
1855
1738
|
const server = createServer((req, res) => {
|
|
1856
|
-
const
|
|
1857
|
-
|
|
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}`);
|
|
1739
|
+
const actualPort = server.address().port;
|
|
1740
|
+
const reqUrl = new URL2(req.url ?? "/", `http://localhost:${actualPort}`);
|
|
1863
1741
|
if (reqUrl.pathname !== "/callback") {
|
|
1864
1742
|
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
1865
1743
|
res.end("Not found");
|
|
@@ -1868,57 +1746,43 @@ async function authenticate(apiUrl, port = 0) {
|
|
|
1868
1746
|
const returnedState = reqUrl.searchParams.get("state");
|
|
1869
1747
|
if (returnedState !== state) {
|
|
1870
1748
|
res.writeHead(403, { "Content-Type": "text/html" });
|
|
1871
|
-
res.end(
|
|
1872
|
-
"Authentication
|
|
1873
|
-
|
|
1874
|
-
false
|
|
1875
|
-
));
|
|
1749
|
+
res.end(
|
|
1750
|
+
"<html><body><h2>Authentication failed</h2><p>Invalid state parameter (possible CSRF). You can close this tab.</p></body></html>"
|
|
1751
|
+
);
|
|
1876
1752
|
return;
|
|
1877
1753
|
}
|
|
1878
1754
|
const apiKeyParam = reqUrl.searchParams.get("api_key");
|
|
1879
1755
|
if (!apiKeyParam) {
|
|
1880
1756
|
res.writeHead(400, { "Content-Type": "text/html" });
|
|
1881
|
-
res.end(
|
|
1882
|
-
"Authentication
|
|
1883
|
-
|
|
1884
|
-
false
|
|
1885
|
-
));
|
|
1757
|
+
res.end(
|
|
1758
|
+
"<html><body><h2>Authentication failed</h2><p>No API key received. You can close this tab.</p></body></html>"
|
|
1759
|
+
);
|
|
1886
1760
|
cleanup();
|
|
1887
1761
|
reject(new Error("No API key received in callback"));
|
|
1888
1762
|
return;
|
|
1889
1763
|
}
|
|
1890
1764
|
setApiKey(apiKeyParam);
|
|
1891
1765
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
1892
|
-
res.end(
|
|
1893
|
-
"Authenticated
|
|
1894
|
-
|
|
1895
|
-
true
|
|
1896
|
-
));
|
|
1897
|
-
resolved = true;
|
|
1766
|
+
res.end(
|
|
1767
|
+
"<html><body><h2>Authenticated!</h2><p>You can close this tab and return to your terminal.</p></body></html>"
|
|
1768
|
+
);
|
|
1898
1769
|
cleanup();
|
|
1899
1770
|
resolve3(apiKeyParam);
|
|
1900
1771
|
});
|
|
1901
1772
|
const timeout = setTimeout(() => {
|
|
1902
1773
|
cleanup();
|
|
1903
|
-
|
|
1904
|
-
reject(new Error("Authentication timed out after 60 seconds"));
|
|
1905
|
-
}
|
|
1774
|
+
reject(new Error("Authentication timed out after 60 seconds"));
|
|
1906
1775
|
}, TIMEOUT_MS);
|
|
1907
1776
|
function cleanup() {
|
|
1908
1777
|
clearTimeout(timeout);
|
|
1909
1778
|
server.close();
|
|
1910
1779
|
}
|
|
1911
1780
|
server.listen(port, async () => {
|
|
1912
|
-
const
|
|
1913
|
-
|
|
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`;
|
|
1781
|
+
const actualPort = server.address().port;
|
|
1782
|
+
const callbackUrl = `http://localhost:${actualPort}/callback`;
|
|
1919
1783
|
const cliCallbackUrl = `${apiUrl}/api/auth/cli-callback?redirect=${encodeURIComponent(callbackUrl)}&state=${encodeURIComponent(state)}`;
|
|
1920
1784
|
const loginUrl = `${apiUrl}/cli-auth?continue=${encodeURIComponent(cliCallbackUrl)}`;
|
|
1921
|
-
console.log(info(`Listening on http://localhost:${
|
|
1785
|
+
console.log(info(`Listening on http://localhost:${actualPort} for callback...`));
|
|
1922
1786
|
const opened = await openBrowser(loginUrl);
|
|
1923
1787
|
if (opened) {
|
|
1924
1788
|
console.log(info("Browser opened. Complete sign-in to continue."));
|
|
@@ -1942,33 +1806,6 @@ async function authenticate(apiUrl, port = 0) {
|
|
|
1942
1806
|
}
|
|
1943
1807
|
|
|
1944
1808
|
// 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
|
-
}
|
|
1972
1809
|
function registerInitCommand(program2) {
|
|
1973
1810
|
program2.command("init").description("Configure the CAIK CLI").option("--no-auth", "Skip authentication, only configure API URL").addHelpText("after", `
|
|
1974
1811
|
Examples:
|
|
@@ -1993,12 +1830,10 @@ Examples:
|
|
|
1993
1830
|
console.log(info(`Config saved to ~/.caik/config.json`));
|
|
1994
1831
|
} catch (err) {
|
|
1995
1832
|
console.log(error(`Authentication failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
1996
|
-
return;
|
|
1997
1833
|
}
|
|
1998
|
-
await promptContributionLevel();
|
|
1999
1834
|
return;
|
|
2000
1835
|
}
|
|
2001
|
-
const rl =
|
|
1836
|
+
const rl = createInterface2({ input: stdin, output: stdout });
|
|
2002
1837
|
try {
|
|
2003
1838
|
const apiUrl = await rl.question(`API URL (${config.apiUrl}): `);
|
|
2004
1839
|
if (apiUrl.trim()) {
|
|
@@ -2047,7 +1882,6 @@ Examples:
|
|
|
2047
1882
|
} finally {
|
|
2048
1883
|
rl.close();
|
|
2049
1884
|
}
|
|
2050
|
-
await promptContributionLevel();
|
|
2051
1885
|
});
|
|
2052
1886
|
}
|
|
2053
1887
|
|
|
@@ -2390,7 +2224,7 @@ import { existsSync as existsSync10 } from "fs";
|
|
|
2390
2224
|
import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync7 } from "fs";
|
|
2391
2225
|
import { dirname as dirname4, resolve as resolve2 } from "path";
|
|
2392
2226
|
import { execSync as execSync4 } from "child_process";
|
|
2393
|
-
import {
|
|
2227
|
+
import { createInterface as createInterface3 } from "readline/promises";
|
|
2394
2228
|
function registerUpdateCommand(program2) {
|
|
2395
2229
|
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", `
|
|
2396
2230
|
Examples:
|
|
@@ -2495,8 +2329,10 @@ Examples:
|
|
|
2495
2329
|
console.log(renderTable(["Artifact", "Platform", "Installed", "Latest"], rows));
|
|
2496
2330
|
console.log(info(`${candidates.length} update(s) available.`));
|
|
2497
2331
|
if (!skipConfirm) {
|
|
2498
|
-
const
|
|
2499
|
-
|
|
2332
|
+
const rl = createInterface3({ input: process.stdin, output: process.stdout });
|
|
2333
|
+
const answer = await rl.question("\nUpdate all? (y/N) ");
|
|
2334
|
+
rl.close();
|
|
2335
|
+
if (answer.toLowerCase() !== "y") {
|
|
2500
2336
|
console.log(info("Update cancelled."));
|
|
2501
2337
|
return;
|
|
2502
2338
|
}
|
|
@@ -2550,8 +2386,10 @@ async function performUpdate(client, entry, skipConfirm, globalOpts) {
|
|
|
2550
2386
|
console.log(info(`Install command: ${installInfo.installCommand}`));
|
|
2551
2387
|
}
|
|
2552
2388
|
console.log();
|
|
2553
|
-
const
|
|
2554
|
-
|
|
2389
|
+
const rl = createInterface3({ input: process.stdin, output: process.stdout });
|
|
2390
|
+
const answer = await rl.question("Continue? (y/N) ");
|
|
2391
|
+
rl.close();
|
|
2392
|
+
if (answer.toLowerCase() !== "y") {
|
|
2555
2393
|
console.log(info("Update cancelled."));
|
|
2556
2394
|
return;
|
|
2557
2395
|
}
|
|
@@ -2605,7 +2443,7 @@ async function performUpdate(client, entry, skipConfirm, globalOpts) {
|
|
|
2605
2443
|
}
|
|
2606
2444
|
|
|
2607
2445
|
// src/commands/uninstall.ts
|
|
2608
|
-
import {
|
|
2446
|
+
import { createInterface as createInterface4 } from "readline/promises";
|
|
2609
2447
|
function registerUninstallCommand(program2) {
|
|
2610
2448
|
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", `
|
|
2611
2449
|
Examples:
|
|
@@ -2657,8 +2495,10 @@ Artifact: ${entry.slug} (${entry.artifactType})`));
|
|
|
2657
2495
|
}
|
|
2658
2496
|
}
|
|
2659
2497
|
if (!skipConfirm) {
|
|
2660
|
-
const
|
|
2661
|
-
|
|
2498
|
+
const rl = createInterface4({ input: process.stdin, output: process.stdout });
|
|
2499
|
+
const answer = await rl.question("\nUninstall? (y/N) ");
|
|
2500
|
+
rl.close();
|
|
2501
|
+
if (answer.toLowerCase() !== "y") {
|
|
2662
2502
|
console.log(info("Uninstall cancelled."));
|
|
2663
2503
|
return;
|
|
2664
2504
|
}
|
|
@@ -2745,12 +2585,57 @@ function registerKarmaCommand(program2) {
|
|
|
2745
2585
|
}
|
|
2746
2586
|
|
|
2747
2587
|
// src/commands/hook.ts
|
|
2748
|
-
import { readFileSync as readFileSync7, writeFileSync as writeFileSync8, mkdirSync as mkdirSync8, existsSync as existsSync11 } from "fs";
|
|
2588
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync8, mkdirSync as mkdirSync8, existsSync as existsSync11, appendFileSync } from "fs";
|
|
2749
2589
|
import { join as join7 } from "path";
|
|
2750
2590
|
import { homedir as homedir6 } from "os";
|
|
2751
|
-
var
|
|
2591
|
+
var CAIK_DIR = join7(homedir6(), ".caik");
|
|
2592
|
+
var PENDING_EVENTS_PATH = join7(CAIK_DIR, "pending-events.json");
|
|
2593
|
+
var AUDIT_LOG_PATH = join7(CAIK_DIR, "audit.log");
|
|
2752
2594
|
var FLUSH_THRESHOLD = 50;
|
|
2753
2595
|
var API_TIMEOUT_MS = 2e3;
|
|
2596
|
+
function readStdin() {
|
|
2597
|
+
return new Promise((resolve3) => {
|
|
2598
|
+
if (process.stdin.isTTY) {
|
|
2599
|
+
resolve3("");
|
|
2600
|
+
return;
|
|
2601
|
+
}
|
|
2602
|
+
let data = "";
|
|
2603
|
+
process.stdin.setEncoding("utf-8");
|
|
2604
|
+
process.stdin.on("data", (chunk) => {
|
|
2605
|
+
data += chunk;
|
|
2606
|
+
});
|
|
2607
|
+
process.stdin.on("end", () => resolve3(data));
|
|
2608
|
+
setTimeout(() => resolve3(data), 500);
|
|
2609
|
+
});
|
|
2610
|
+
}
|
|
2611
|
+
function parseStdin(raw) {
|
|
2612
|
+
if (!raw.trim()) return null;
|
|
2613
|
+
try {
|
|
2614
|
+
return JSON.parse(raw);
|
|
2615
|
+
} catch {
|
|
2616
|
+
return null;
|
|
2617
|
+
}
|
|
2618
|
+
}
|
|
2619
|
+
function shouldSendTelemetry() {
|
|
2620
|
+
const config = readConfig();
|
|
2621
|
+
const level = config.contributionLevel ?? "contributor";
|
|
2622
|
+
return level !== "none";
|
|
2623
|
+
}
|
|
2624
|
+
function shouldSendToolUse() {
|
|
2625
|
+
const config = readConfig();
|
|
2626
|
+
const level = config.contributionLevel ?? "contributor";
|
|
2627
|
+
return level === "contributor" || level === "collective";
|
|
2628
|
+
}
|
|
2629
|
+
function auditLog(event) {
|
|
2630
|
+
try {
|
|
2631
|
+
if (!existsSync11(CAIK_DIR)) {
|
|
2632
|
+
mkdirSync8(CAIK_DIR, { recursive: true, mode: 448 });
|
|
2633
|
+
}
|
|
2634
|
+
const line = JSON.stringify(event) + "\n";
|
|
2635
|
+
appendFileSync(AUDIT_LOG_PATH, line, "utf-8");
|
|
2636
|
+
} catch {
|
|
2637
|
+
}
|
|
2638
|
+
}
|
|
2754
2639
|
function readPendingEvents() {
|
|
2755
2640
|
try {
|
|
2756
2641
|
if (!existsSync11(PENDING_EVENTS_PATH)) return [];
|
|
@@ -2762,9 +2647,8 @@ function readPendingEvents() {
|
|
|
2762
2647
|
}
|
|
2763
2648
|
}
|
|
2764
2649
|
function writePendingEvents(events) {
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
mkdirSync8(dir, { recursive: true, mode: 448 });
|
|
2650
|
+
if (!existsSync11(CAIK_DIR)) {
|
|
2651
|
+
mkdirSync8(CAIK_DIR, { recursive: true, mode: 448 });
|
|
2768
2652
|
}
|
|
2769
2653
|
writeFileSync8(PENDING_EVENTS_PATH, JSON.stringify(events, null, 2) + "\n", "utf-8");
|
|
2770
2654
|
}
|
|
@@ -2814,12 +2698,20 @@ function registerHookCommand(program2) {
|
|
|
2814
2698
|
const hook = program2.command("hook").description("Platform hook callbacks (observation only, never gates agent actions)");
|
|
2815
2699
|
hook.command("session-start").description("Log session start event").option("--platform <name>", "Platform name", "claude-code").action(async (opts) => {
|
|
2816
2700
|
try {
|
|
2817
|
-
|
|
2701
|
+
if (!shouldSendTelemetry()) {
|
|
2702
|
+
process.exit(0);
|
|
2703
|
+
return;
|
|
2704
|
+
}
|
|
2705
|
+
const raw = await readStdin();
|
|
2706
|
+
const input = parseStdin(raw);
|
|
2818
2707
|
const event = {
|
|
2819
2708
|
type: "session_start",
|
|
2820
2709
|
platform: opts.platform ?? "claude-code",
|
|
2710
|
+
sessionId: input?.session_id,
|
|
2821
2711
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2822
2712
|
};
|
|
2713
|
+
auditLog(event);
|
|
2714
|
+
const client = createClient(program2);
|
|
2823
2715
|
await postSingleEventWithTimeout(client, event);
|
|
2824
2716
|
} catch {
|
|
2825
2717
|
}
|
|
@@ -2827,28 +2719,47 @@ function registerHookCommand(program2) {
|
|
|
2827
2719
|
});
|
|
2828
2720
|
hook.command("session-end").description("Flush pending events and log session end").option("--platform <name>", "Platform name", "claude-code").action(async (opts) => {
|
|
2829
2721
|
try {
|
|
2830
|
-
|
|
2722
|
+
if (!shouldSendTelemetry()) {
|
|
2723
|
+
clearPendingEvents();
|
|
2724
|
+
process.exit(0);
|
|
2725
|
+
return;
|
|
2726
|
+
}
|
|
2727
|
+
const raw = await readStdin();
|
|
2728
|
+
const input = parseStdin(raw);
|
|
2831
2729
|
const pending = readPendingEvents();
|
|
2832
2730
|
const endEvent = {
|
|
2833
2731
|
type: "session_end",
|
|
2834
2732
|
platform: opts.platform ?? "claude-code",
|
|
2733
|
+
sessionId: input?.session_id,
|
|
2835
2734
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2836
2735
|
};
|
|
2837
2736
|
pending.push(endEvent);
|
|
2737
|
+
auditLog(endEvent);
|
|
2738
|
+
const client = createClient(program2);
|
|
2838
2739
|
await postEventsWithTimeout(client, pending);
|
|
2839
2740
|
} catch {
|
|
2840
2741
|
}
|
|
2841
2742
|
process.exit(0);
|
|
2842
2743
|
});
|
|
2843
|
-
hook.command("post-tool-use").description("Buffer a tool-use event").option("--platform <name>", "Platform name", "claude-code").option("--tool <name>", "Tool name").option("--success <bool>", "
|
|
2744
|
+
hook.command("post-tool-use").description("Buffer a tool-use event").option("--platform <name>", "Platform name", "claude-code").option("--tool <name>", "Tool name (fallback if stdin unavailable)").option("--success <bool>", "Success flag (fallback if stdin unavailable)").action(async (opts) => {
|
|
2844
2745
|
try {
|
|
2746
|
+
if (!shouldSendToolUse()) {
|
|
2747
|
+
process.exit(0);
|
|
2748
|
+
return;
|
|
2749
|
+
}
|
|
2750
|
+
const raw = await readStdin();
|
|
2751
|
+
const input = parseStdin(raw);
|
|
2752
|
+
const toolName = input?.tool_name ?? opts.tool;
|
|
2753
|
+
const success2 = input?.tool_response?.success ?? opts.success === "true" ?? false;
|
|
2845
2754
|
const event = {
|
|
2846
2755
|
type: "tool_use",
|
|
2847
2756
|
platform: opts.platform ?? "claude-code",
|
|
2848
|
-
|
|
2849
|
-
|
|
2757
|
+
sessionId: input?.session_id,
|
|
2758
|
+
tool: toolName,
|
|
2759
|
+
success: Boolean(success2),
|
|
2850
2760
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2851
2761
|
};
|
|
2762
|
+
auditLog(event);
|
|
2852
2763
|
const events = bufferEvent(event);
|
|
2853
2764
|
if (events.length >= FLUSH_THRESHOLD) {
|
|
2854
2765
|
const client = createClient(program2);
|
|
@@ -2860,12 +2771,17 @@ function registerHookCommand(program2) {
|
|
|
2860
2771
|
});
|
|
2861
2772
|
hook.command("cursor-session-start").description("Log Cursor session start event").action(async () => {
|
|
2862
2773
|
try {
|
|
2863
|
-
|
|
2774
|
+
if (!shouldSendTelemetry()) {
|
|
2775
|
+
process.exit(0);
|
|
2776
|
+
return;
|
|
2777
|
+
}
|
|
2864
2778
|
const event = {
|
|
2865
2779
|
type: "session_start",
|
|
2866
2780
|
platform: "cursor",
|
|
2867
2781
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2868
2782
|
};
|
|
2783
|
+
auditLog(event);
|
|
2784
|
+
const client = createClient(program2);
|
|
2869
2785
|
await postSingleEventWithTimeout(client, event);
|
|
2870
2786
|
} catch {
|
|
2871
2787
|
}
|
|
@@ -2873,6 +2789,10 @@ function registerHookCommand(program2) {
|
|
|
2873
2789
|
});
|
|
2874
2790
|
hook.command("cursor-mcp-exec").description("Buffer a Cursor MCP tool execution event").option("--server <name>", "MCP server name").option("--tool <name>", "Tool name").action(async (opts) => {
|
|
2875
2791
|
try {
|
|
2792
|
+
if (!shouldSendToolUse()) {
|
|
2793
|
+
process.exit(0);
|
|
2794
|
+
return;
|
|
2795
|
+
}
|
|
2876
2796
|
const event = {
|
|
2877
2797
|
type: "mcp_exec",
|
|
2878
2798
|
platform: "cursor",
|
|
@@ -2880,6 +2800,7 @@ function registerHookCommand(program2) {
|
|
|
2880
2800
|
tool: opts.tool,
|
|
2881
2801
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2882
2802
|
};
|
|
2803
|
+
auditLog(event);
|
|
2883
2804
|
const events = bufferEvent(event);
|
|
2884
2805
|
if (events.length >= FLUSH_THRESHOLD) {
|
|
2885
2806
|
const client = createClient(program2);
|
|
@@ -2891,7 +2812,11 @@ function registerHookCommand(program2) {
|
|
|
2891
2812
|
});
|
|
2892
2813
|
hook.command("cursor-session-end").description("Flush pending events and log Cursor session end").action(async () => {
|
|
2893
2814
|
try {
|
|
2894
|
-
|
|
2815
|
+
if (!shouldSendTelemetry()) {
|
|
2816
|
+
clearPendingEvents();
|
|
2817
|
+
process.exit(0);
|
|
2818
|
+
return;
|
|
2819
|
+
}
|
|
2895
2820
|
const pending = readPendingEvents();
|
|
2896
2821
|
const endEvent = {
|
|
2897
2822
|
type: "session_end",
|
|
@@ -2899,6 +2824,8 @@ function registerHookCommand(program2) {
|
|
|
2899
2824
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2900
2825
|
};
|
|
2901
2826
|
pending.push(endEvent);
|
|
2827
|
+
auditLog(endEvent);
|
|
2828
|
+
const client = createClient(program2);
|
|
2902
2829
|
await postEventsWithTimeout(client, pending);
|
|
2903
2830
|
} catch {
|
|
2904
2831
|
}
|
|
@@ -2907,7 +2834,7 @@ function registerHookCommand(program2) {
|
|
|
2907
2834
|
}
|
|
2908
2835
|
|
|
2909
2836
|
// src/commands/setup.ts
|
|
2910
|
-
import {
|
|
2837
|
+
import { createInterface as createInterface5 } from "readline/promises";
|
|
2911
2838
|
import { existsSync as existsSync12 } from "fs";
|
|
2912
2839
|
|
|
2913
2840
|
// src/platform/templates/claude-code-skill.ts
|
|
@@ -3287,17 +3214,23 @@ Examples:
|
|
|
3287
3214
|
if (autoYes || detected.length === 1 || platformFlag) {
|
|
3288
3215
|
selected = detected;
|
|
3289
3216
|
} else {
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
if (
|
|
3299
|
-
|
|
3300
|
-
|
|
3217
|
+
const rl = createInterface5({ input: process.stdin, output: process.stdout });
|
|
3218
|
+
console.log(info("Which platforms would you like to configure?"));
|
|
3219
|
+
for (let i = 0; i < detected.length; i++) {
|
|
3220
|
+
console.log(` ${i + 1}. ${detected[i].name}`);
|
|
3221
|
+
}
|
|
3222
|
+
console.log(` a. All`);
|
|
3223
|
+
const answer = await rl.question("\nSelect (numbers separated by commas, or 'a' for all): ");
|
|
3224
|
+
rl.close();
|
|
3225
|
+
if (answer.toLowerCase() === "a" || answer.trim() === "") {
|
|
3226
|
+
selected = detected;
|
|
3227
|
+
} else {
|
|
3228
|
+
const indices = answer.split(",").map((s) => parseInt(s.trim(), 10) - 1);
|
|
3229
|
+
selected = indices.filter((i) => i >= 0 && i < detected.length).map((i) => detected[i]);
|
|
3230
|
+
if (selected.length === 0) {
|
|
3231
|
+
console.log(warn("No valid platforms selected. Exiting."));
|
|
3232
|
+
return;
|
|
3233
|
+
}
|
|
3301
3234
|
}
|
|
3302
3235
|
}
|
|
3303
3236
|
console.log();
|
|
@@ -3505,65 +3438,154 @@ function registerUpgradeCommand(program2) {
|
|
|
3505
3438
|
});
|
|
3506
3439
|
}
|
|
3507
3440
|
|
|
3508
|
-
// src/commands/
|
|
3509
|
-
|
|
3510
|
-
|
|
3441
|
+
// src/commands/audit.ts
|
|
3442
|
+
import { readFileSync as readFileSync9, existsSync as existsSync14, writeFileSync as writeFileSync10 } from "fs";
|
|
3443
|
+
import { join as join9 } from "path";
|
|
3444
|
+
import { homedir as homedir8 } from "os";
|
|
3445
|
+
var CAIK_DIR2 = join9(homedir8(), ".caik");
|
|
3446
|
+
var AUDIT_LOG_PATH2 = join9(CAIK_DIR2, "audit.log");
|
|
3447
|
+
var PENDING_EVENTS_PATH2 = join9(CAIK_DIR2, "pending-events.json");
|
|
3448
|
+
function registerAuditCommand(program2) {
|
|
3449
|
+
const cmd = program2.command("audit").description("See exactly what telemetry CAIK collects \u2014 full transparency");
|
|
3450
|
+
cmd.command("log").description("Show recent telemetry events (from local audit log)").option("-n, --lines <count>", "Number of recent events to show", "20").option("--all", "Show all events").action((opts) => {
|
|
3451
|
+
console.log(heading("\nCAIK Telemetry Audit Log"));
|
|
3452
|
+
console.log("\u2550".repeat(50));
|
|
3511
3453
|
const config = readConfig();
|
|
3512
|
-
|
|
3513
|
-
|
|
3454
|
+
const level = config.contributionLevel ?? "contributor";
|
|
3455
|
+
console.log(info(`Contribution level: ${level}`));
|
|
3456
|
+
console.log(dim(`Log path: ${AUDIT_LOG_PATH2}`));
|
|
3457
|
+
console.log();
|
|
3458
|
+
if (!existsSync14(AUDIT_LOG_PATH2)) {
|
|
3459
|
+
console.log(dim("No events logged yet. Events appear here after your next Claude Code session."));
|
|
3514
3460
|
return;
|
|
3515
3461
|
}
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
}
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3462
|
+
const raw = readFileSync9(AUDIT_LOG_PATH2, "utf-8").trim();
|
|
3463
|
+
if (!raw) {
|
|
3464
|
+
console.log(dim("Audit log is empty."));
|
|
3465
|
+
return;
|
|
3466
|
+
}
|
|
3467
|
+
const lines = raw.split("\n");
|
|
3468
|
+
const limit = opts.all ? lines.length : Math.min(parseInt(opts.lines, 10) || 20, lines.length);
|
|
3469
|
+
const recent = lines.slice(-limit);
|
|
3470
|
+
if (!opts.all && lines.length > limit) {
|
|
3471
|
+
console.log(dim(`Showing last ${limit} of ${lines.length} events. Use --all to see everything.
|
|
3472
|
+
`));
|
|
3473
|
+
}
|
|
3474
|
+
for (const line of recent) {
|
|
3475
|
+
try {
|
|
3476
|
+
const event = JSON.parse(line);
|
|
3477
|
+
const time = new Date(event.timestamp).toLocaleTimeString();
|
|
3478
|
+
const type = event.type.padEnd(14);
|
|
3479
|
+
const platform2 = (event.platform ?? "").padEnd(12);
|
|
3480
|
+
const tool = event.tool ? ` tool=${event.tool}` : "";
|
|
3481
|
+
const ok = event.success !== void 0 ? ` success=${event.success}` : "";
|
|
3482
|
+
const sid = event.sessionId ? ` sid=${event.sessionId.slice(0, 8)}\u2026` : "";
|
|
3483
|
+
console.log(` ${dim(time)} ${type} ${dim(platform2)}${tool}${ok}${sid}`);
|
|
3484
|
+
} catch {
|
|
3485
|
+
console.log(` ${dim(line)}`);
|
|
3486
|
+
}
|
|
3487
|
+
}
|
|
3535
3488
|
console.log();
|
|
3489
|
+
console.log(dim("This is everything CAIK sends. No prompts, files, or personal data \u2014 ever."));
|
|
3490
|
+
console.log(dim("Change your level: caik config contribution"));
|
|
3536
3491
|
});
|
|
3537
|
-
cmd.command("
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3492
|
+
cmd.command("pending").description("Show events buffered locally (not yet sent to API)").action(() => {
|
|
3493
|
+
console.log(heading("\nPending Events (buffered locally)"));
|
|
3494
|
+
console.log("\u2500".repeat(50));
|
|
3495
|
+
console.log(dim(`Path: ${PENDING_EVENTS_PATH2}
|
|
3496
|
+
`));
|
|
3497
|
+
if (!existsSync14(PENDING_EVENTS_PATH2)) {
|
|
3498
|
+
console.log(dim("No pending events."));
|
|
3499
|
+
return;
|
|
3500
|
+
}
|
|
3501
|
+
try {
|
|
3502
|
+
const raw = readFileSync9(PENDING_EVENTS_PATH2, "utf-8");
|
|
3503
|
+
const events = JSON.parse(raw);
|
|
3504
|
+
if (events.length === 0) {
|
|
3505
|
+
console.log(dim("No pending events."));
|
|
3544
3506
|
return;
|
|
3545
3507
|
}
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3508
|
+
console.log(info(`${events.length} event(s) buffered, waiting for session end to flush:
|
|
3509
|
+
`));
|
|
3510
|
+
const counts = /* @__PURE__ */ new Map();
|
|
3511
|
+
const tools = /* @__PURE__ */ new Map();
|
|
3512
|
+
let successCount = 0;
|
|
3513
|
+
let failCount = 0;
|
|
3514
|
+
for (const e of events) {
|
|
3515
|
+
counts.set(e.type, (counts.get(e.type) ?? 0) + 1);
|
|
3516
|
+
if (e.tool) tools.set(e.tool, (tools.get(e.tool) ?? 0) + 1);
|
|
3517
|
+
if (e.success === true) successCount++;
|
|
3518
|
+
if (e.success === false) failCount++;
|
|
3519
|
+
}
|
|
3520
|
+
for (const [type, count] of counts) {
|
|
3521
|
+
console.log(` ${type}: ${count}`);
|
|
3522
|
+
}
|
|
3523
|
+
if (tools.size > 0) {
|
|
3524
|
+
console.log();
|
|
3525
|
+
console.log(info("Tools used:"));
|
|
3526
|
+
const sorted = [...tools.entries()].sort((a, b) => b[1] - a[1]);
|
|
3527
|
+
for (const [tool, count] of sorted.slice(0, 10)) {
|
|
3528
|
+
console.log(` ${tool}: ${count}`);
|
|
3529
|
+
}
|
|
3530
|
+
if (sorted.length > 10) {
|
|
3531
|
+
console.log(dim(` \u2026 and ${sorted.length - 10} more`));
|
|
3532
|
+
}
|
|
3533
|
+
}
|
|
3534
|
+
if (successCount + failCount > 0) {
|
|
3535
|
+
console.log();
|
|
3536
|
+
console.log(` ${success(`${successCount} succeeded`)} / ${warn(`${failCount} failed`)}`);
|
|
3537
|
+
}
|
|
3538
|
+
} catch {
|
|
3539
|
+
console.log(warn("Could not parse pending events file."));
|
|
3550
3540
|
}
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
}
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3541
|
+
});
|
|
3542
|
+
cmd.command("clear").description("Clear the local audit log and pending events").action(() => {
|
|
3543
|
+
if (existsSync14(AUDIT_LOG_PATH2)) {
|
|
3544
|
+
writeFileSync10(AUDIT_LOG_PATH2, "", "utf-8");
|
|
3545
|
+
}
|
|
3546
|
+
if (existsSync14(PENDING_EVENTS_PATH2)) {
|
|
3547
|
+
writeFileSync10(PENDING_EVENTS_PATH2, "[]", "utf-8");
|
|
3548
|
+
}
|
|
3549
|
+
console.log(success("Audit log and pending events cleared."));
|
|
3550
|
+
});
|
|
3551
|
+
cmd.action(() => {
|
|
3552
|
+
const config = readConfig();
|
|
3553
|
+
const level = config.contributionLevel ?? "contributor";
|
|
3554
|
+
console.log(heading("\nCAIK Telemetry Transparency"));
|
|
3555
|
+
console.log("\u2550".repeat(50));
|
|
3556
|
+
console.log();
|
|
3557
|
+
console.log(` Contribution Level: ${level}`);
|
|
3558
|
+
let logCount = 0;
|
|
3559
|
+
if (existsSync14(AUDIT_LOG_PATH2)) {
|
|
3560
|
+
const raw = readFileSync9(AUDIT_LOG_PATH2, "utf-8").trim();
|
|
3561
|
+
if (raw) logCount = raw.split("\n").length;
|
|
3562
|
+
}
|
|
3563
|
+
console.log(` Events Logged: ${logCount}`);
|
|
3564
|
+
let pendingCount = 0;
|
|
3565
|
+
if (existsSync14(PENDING_EVENTS_PATH2)) {
|
|
3566
|
+
try {
|
|
3567
|
+
const parsed = JSON.parse(readFileSync9(PENDING_EVENTS_PATH2, "utf-8"));
|
|
3568
|
+
if (Array.isArray(parsed)) pendingCount = parsed.length;
|
|
3569
|
+
} catch {
|
|
3570
|
+
}
|
|
3566
3571
|
}
|
|
3572
|
+
console.log(` Pending (unsent): ${pendingCount}`);
|
|
3573
|
+
console.log(` Audit Log: ${dim(AUDIT_LOG_PATH2)}`);
|
|
3574
|
+
console.log();
|
|
3575
|
+
console.log(heading("What each level sends:"));
|
|
3576
|
+
console.log(` ${dim("none")} Nothing. Directory access only.`);
|
|
3577
|
+
console.log(` ${dim("minimal")} Install/uninstall events (artifact ID + timestamp).`);
|
|
3578
|
+
console.log(` ${dim("contributor")} + Tool-use signals (tool name, success/fail). No content.`);
|
|
3579
|
+
console.log(` ${dim("collective")} + Workflow patterns, stack signals. Anonymized.`);
|
|
3580
|
+
console.log();
|
|
3581
|
+
console.log(dim("NEVER sent: prompts, file contents, conversation text, file paths, personal data."));
|
|
3582
|
+
console.log();
|
|
3583
|
+
console.log(info("Commands:"));
|
|
3584
|
+
console.log(` ${dim("caik audit log")} Show recent events`);
|
|
3585
|
+
console.log(` ${dim("caik audit pending")} Show buffered events`);
|
|
3586
|
+
console.log(` ${dim("caik audit clear")} Clear all local telemetry data`);
|
|
3587
|
+
console.log(` ${dim("caik config contribution")} Change your contribution level`);
|
|
3588
|
+
console.log();
|
|
3567
3589
|
});
|
|
3568
3590
|
}
|
|
3569
3591
|
|
|
@@ -3572,8 +3594,8 @@ var __filename = fileURLToPath(import.meta.url);
|
|
|
3572
3594
|
var __dirname = dirname5(__filename);
|
|
3573
3595
|
var version = "0.0.1";
|
|
3574
3596
|
try {
|
|
3575
|
-
const pkgPath =
|
|
3576
|
-
const pkg = JSON.parse(
|
|
3597
|
+
const pkgPath = join10(__dirname, "..", "package.json");
|
|
3598
|
+
const pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
|
|
3577
3599
|
version = pkg.version;
|
|
3578
3600
|
} catch {
|
|
3579
3601
|
}
|
|
@@ -3581,8 +3603,6 @@ var program = new Command().name("caik").description("CAIK \u2014 Collective AI
|
|
|
3581
3603
|
registerSearchCommand(program);
|
|
3582
3604
|
registerInstallCommand(program);
|
|
3583
3605
|
registerInitCommand(program);
|
|
3584
|
-
registerLogoutCommand(program);
|
|
3585
|
-
registerConfigCommand(program);
|
|
3586
3606
|
registerStatusCommand(program);
|
|
3587
3607
|
registerStatsCommand(program);
|
|
3588
3608
|
registerPublishCommand(program);
|
|
@@ -3596,6 +3616,7 @@ registerKarmaCommand(program);
|
|
|
3596
3616
|
registerHookCommand(program);
|
|
3597
3617
|
registerSetupCommand(program);
|
|
3598
3618
|
registerUpgradeCommand(program);
|
|
3619
|
+
registerAuditCommand(program);
|
|
3599
3620
|
program.exitOverride();
|
|
3600
3621
|
async function main() {
|
|
3601
3622
|
const updateHint = printUpdateHint();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@caik.dev/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "CAIK CLI — Search, install, and publish AI artifacts from your terminal",
|
|
6
6
|
"keywords": [
|
|
@@ -34,7 +34,6 @@
|
|
|
34
34
|
"typecheck": "tsc --noEmit"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@inquirer/prompts": "^8.3.2",
|
|
38
37
|
"chalk": "^5.6.2",
|
|
39
38
|
"cli-table3": "^0.6.5",
|
|
40
39
|
"commander": "^14.0.3",
|