@prave/cli 1.0.10 → 1.1.1
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/commands/conflicts.js +2 -0
- package/dist/commands/deploy.js +2 -0
- package/dist/commands/find.js +5 -0
- package/dist/commands/import.js +5 -0
- package/dist/commands/install.js +2 -0
- package/dist/commands/list.js +7 -0
- package/dist/commands/login.js +2 -0
- package/dist/commands/logout.js +2 -0
- package/dist/commands/optimize.js +6 -0
- package/dist/commands/overview.js +2 -0
- package/dist/commands/search.js +2 -0
- package/dist/commands/sync.js +2 -0
- package/dist/commands/uninstall.js +2 -0
- package/dist/commands/update.js +2 -0
- package/dist/commands/usage.js +5 -0
- package/dist/commands/whatdoes.js +2 -0
- package/dist/commands/whoami.js +2 -0
- package/dist/index.js +5 -0
- package/dist/lib/analytics.js +116 -0
- package/package.json +39 -4
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import ora from 'ora';
|
|
3
|
+
import { track } from '../lib/analytics.js';
|
|
3
4
|
import { api, ApiError } from '../lib/api.js';
|
|
4
5
|
import { requireAuth } from '../lib/credentials.js';
|
|
5
6
|
import { log } from '../utils/logger.js';
|
|
@@ -18,6 +19,7 @@ function describe(c) {
|
|
|
18
19
|
}
|
|
19
20
|
}
|
|
20
21
|
export async function conflictsCommand(opts = {}) {
|
|
22
|
+
track('cli_conflicts', { fix: !!opts.fix });
|
|
21
23
|
const _session = await requireAuth("prave conflicts");
|
|
22
24
|
if (!_session)
|
|
23
25
|
return;
|
package/dist/commands/deploy.js
CHANGED
|
@@ -4,6 +4,7 @@ import { join } from 'node:path';
|
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import ora from 'ora';
|
|
6
6
|
import { AGENT_REGISTRY } from '@prave/shared';
|
|
7
|
+
import { track } from '../lib/analytics.js';
|
|
7
8
|
import { api, ApiError } from '../lib/api.js';
|
|
8
9
|
import { requireAuth } from '../lib/credentials.js';
|
|
9
10
|
import { fetchMyPlan, formatUpgradeHint } from '../lib/plan.js';
|
|
@@ -71,6 +72,7 @@ function buildDestPath(agent, basePath, os, slug) {
|
|
|
71
72
|
};
|
|
72
73
|
}
|
|
73
74
|
export async function deployCommand(skillName, opts = {}) {
|
|
75
|
+
track('cli_deploy', { slug: skillName, agent: opts.agent ?? 'all', dry_run: !!opts.dryRun });
|
|
74
76
|
try {
|
|
75
77
|
assertSlug(skillName);
|
|
76
78
|
}
|
package/dist/commands/find.js
CHANGED
|
@@ -2,6 +2,7 @@ import { createInterface } from 'node:readline/promises';
|
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import ora from 'ora';
|
|
4
4
|
import { tokenTier } from '@prave/shared';
|
|
5
|
+
import { track } from '../lib/analytics.js';
|
|
5
6
|
import { api, ApiError } from '../lib/api.js';
|
|
6
7
|
import { log } from '../utils/logger.js';
|
|
7
8
|
const TIER_EMOJI = {
|
|
@@ -28,6 +29,10 @@ function renderResult(r, idx) {
|
|
|
28
29
|
log.dim(` ${r.description}`);
|
|
29
30
|
}
|
|
30
31
|
export async function findCommand(query, opts = {}) {
|
|
32
|
+
track('cli_find', {
|
|
33
|
+
length: query.length,
|
|
34
|
+
mode: opts.smart ? 'smart' : opts.local ? 'local' : opts.marketplace ? 'marketplace' : 'both',
|
|
35
|
+
});
|
|
31
36
|
const scope = opts.local
|
|
32
37
|
? 'local'
|
|
33
38
|
: opts.marketplace
|
package/dist/commands/import.js
CHANGED
|
@@ -2,6 +2,7 @@ import { readdir, readFile, stat } from 'node:fs/promises';
|
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import ora from 'ora';
|
|
5
|
+
import { track } from '../lib/analytics.js';
|
|
5
6
|
import { api } from '../lib/api.js';
|
|
6
7
|
import { CONFIG } from '../lib/config.js';
|
|
7
8
|
import { loadCredentials, requireAuth } from '../lib/credentials.js';
|
|
@@ -17,6 +18,10 @@ import { log } from '../utils/logger.js';
|
|
|
17
18
|
* accidentally publishing private notes to the registry.
|
|
18
19
|
*/
|
|
19
20
|
export async function importCommand(opts) {
|
|
21
|
+
track('cli_import', {
|
|
22
|
+
upload: !!opts.upload,
|
|
23
|
+
visibility: opts.public ? 'public' : opts.private ? 'private' : null,
|
|
24
|
+
});
|
|
20
25
|
// `prave import` (without --upload) only inspects local files and posts
|
|
21
26
|
// to /intelligence/analyze if logged in — uploads, however, must always
|
|
22
27
|
// be tracked, so we gate on auth whenever --upload is set.
|
package/dist/commands/install.js
CHANGED
|
@@ -3,6 +3,7 @@ import { join } from 'node:path';
|
|
|
3
3
|
import { createInterface } from 'node:readline/promises';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import ora from 'ora';
|
|
6
|
+
import { track } from '../lib/analytics.js';
|
|
6
7
|
import { api, ApiError } from '../lib/api.js';
|
|
7
8
|
import { CONFIG } from '../lib/config.js';
|
|
8
9
|
import { loadCredentials, requireAuth } from '../lib/credentials.js';
|
|
@@ -20,6 +21,7 @@ import { log } from '../utils/logger.js';
|
|
|
20
21
|
* instead of letting the API error bubble.
|
|
21
22
|
*/
|
|
22
23
|
export async function installCommand(slug, opts = {}) {
|
|
24
|
+
track('cli_install', { slug, no_deps: !!opts.noDeps, force: !!opts.force });
|
|
23
25
|
try {
|
|
24
26
|
assertSlug(slug);
|
|
25
27
|
}
|
package/dist/commands/list.js
CHANGED
|
@@ -2,6 +2,7 @@ import { readdir, stat } from 'node:fs/promises';
|
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import { tokenTier } from '@prave/shared';
|
|
5
|
+
import { track } from '../lib/analytics.js';
|
|
5
6
|
import { api } from '../lib/api.js';
|
|
6
7
|
import { CONFIG } from '../lib/config.js';
|
|
7
8
|
import { log } from '../utils/logger.js';
|
|
@@ -39,6 +40,12 @@ async function readLocalSlugs() {
|
|
|
39
40
|
}
|
|
40
41
|
}
|
|
41
42
|
export async function listCommand(opts = {}) {
|
|
43
|
+
track('cli_list', {
|
|
44
|
+
remote: !!opts.remote,
|
|
45
|
+
verbose: !!opts.verbose,
|
|
46
|
+
conflicts: !!opts.conflicts,
|
|
47
|
+
heavy: !!opts.heavy,
|
|
48
|
+
});
|
|
42
49
|
if (opts.remote) {
|
|
43
50
|
const { data: skills } = await api.get('/api/v1/skills?limit=50', true);
|
|
44
51
|
if (skills.length === 0) {
|
package/dist/commands/login.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { setTimeout as sleep } from 'node:timers/promises';
|
|
2
2
|
import open from 'open';
|
|
3
3
|
import ora from 'ora';
|
|
4
|
+
import { track } from '../lib/analytics.js';
|
|
4
5
|
import { api, ApiError } from '../lib/api.js';
|
|
5
6
|
import { CONFIG } from '../lib/config.js';
|
|
6
7
|
import { saveCredentials } from '../lib/credentials.js';
|
|
@@ -9,6 +10,7 @@ import { log } from '../utils/logger.js';
|
|
|
9
10
|
* `prave login` — device-code flow against the Prave API / Supabase session.
|
|
10
11
|
*/
|
|
11
12
|
export async function loginCommand() {
|
|
13
|
+
track('cli_login_started');
|
|
12
14
|
const { data: start } = await api.post('/api/v1/cli/login');
|
|
13
15
|
const url = `${CONFIG.webUrl}${start.verification_url}`;
|
|
14
16
|
log.info('Opening browser to authorize this device…');
|
package/dist/commands/logout.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { track } from '../lib/analytics.js';
|
|
1
2
|
import { clearCredentials } from '../lib/credentials.js';
|
|
2
3
|
import { log } from '../utils/logger.js';
|
|
3
4
|
export async function logoutCommand() {
|
|
5
|
+
track('cli_logout');
|
|
4
6
|
await clearCredentials();
|
|
5
7
|
log.success('Logged out.');
|
|
6
8
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import ora from 'ora';
|
|
3
3
|
import readline from 'node:readline/promises';
|
|
4
|
+
import { track } from '../lib/analytics.js';
|
|
4
5
|
import { api, ApiError } from '../lib/api.js';
|
|
5
6
|
import { requireAuth } from '../lib/credentials.js';
|
|
6
7
|
import { isValidSlug } from '../lib/slug.js';
|
|
@@ -50,6 +51,11 @@ async function confirmYesNo(question) {
|
|
|
50
51
|
}
|
|
51
52
|
}
|
|
52
53
|
export async function optimizeCommand(opts = {}) {
|
|
54
|
+
track('cli_optimize', {
|
|
55
|
+
apply: !!opts.apply,
|
|
56
|
+
remove_unused: !!opts.removeUnused,
|
|
57
|
+
yes: !!opts.yes,
|
|
58
|
+
});
|
|
53
59
|
const _session = await requireAuth("prave optimize");
|
|
54
60
|
if (!_session)
|
|
55
61
|
return;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import ora from 'ora';
|
|
3
|
+
import { track } from '../lib/analytics.js';
|
|
3
4
|
import { api, ApiError } from '../lib/api.js';
|
|
4
5
|
import { requireAuth } from '../lib/credentials.js';
|
|
5
6
|
import { log } from '../utils/logger.js';
|
|
@@ -14,6 +15,7 @@ function pad(s, width) {
|
|
|
14
15
|
return s + ' '.repeat(width - s.length);
|
|
15
16
|
}
|
|
16
17
|
export async function overviewCommand(opts = {}) {
|
|
18
|
+
track('cli_overview', { agent: opts.agent ?? null, json: !!opts.json });
|
|
17
19
|
const _session = await requireAuth("prave overview");
|
|
18
20
|
if (!_session)
|
|
19
21
|
return;
|
package/dist/commands/search.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
+
import { track } from '../lib/analytics.js';
|
|
2
3
|
import { api } from '../lib/api.js';
|
|
3
4
|
import { log } from '../utils/logger.js';
|
|
4
5
|
export async function searchCommand(query) {
|
|
6
|
+
track('cli_search', { length: query.length });
|
|
5
7
|
const { data: skills } = await api.get(`/api/v1/skills?q=${encodeURIComponent(query)}&limit=25`);
|
|
6
8
|
if (skills.length === 0) {
|
|
7
9
|
log.dim(`No skills match "${query}".`);
|
package/dist/commands/sync.js
CHANGED
|
@@ -3,6 +3,7 @@ import { join } from 'node:path';
|
|
|
3
3
|
import { createInterface } from 'node:readline/promises';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import ora from 'ora';
|
|
6
|
+
import { track } from '../lib/analytics.js';
|
|
6
7
|
import { CONFIG } from '../lib/config.js';
|
|
7
8
|
import { requireAuth } from '../lib/credentials.js';
|
|
8
9
|
import { fetchMyPlan, formatUpgradeHint } from '../lib/plan.js';
|
|
@@ -20,6 +21,7 @@ import { installCommand } from './install.js';
|
|
|
20
21
|
* single batched deploy at the end.
|
|
21
22
|
*/
|
|
22
23
|
export async function syncCommand() {
|
|
24
|
+
track('cli_sync');
|
|
23
25
|
// Auth gate — sync mutates the install ledger and intelligence cache.
|
|
24
26
|
const session = await requireAuth('prave sync');
|
|
25
27
|
if (!session)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { rm } from 'node:fs/promises';
|
|
2
2
|
import { join, resolve, sep } from 'node:path';
|
|
3
3
|
import ora from 'ora';
|
|
4
|
+
import { track } from '../lib/analytics.js';
|
|
4
5
|
import { CONFIG } from '../lib/config.js';
|
|
5
6
|
import { assertSlug, InvalidSlugError } from '../lib/slug.js';
|
|
6
7
|
/**
|
|
@@ -12,6 +13,7 @@ import { assertSlug, InvalidSlugError } from '../lib/slug.js';
|
|
|
12
13
|
* so a hostile arg like `../../etc` cannot escape the skills directory.
|
|
13
14
|
*/
|
|
14
15
|
export async function uninstallCommand(slug) {
|
|
16
|
+
track('cli_uninstall', { slug });
|
|
15
17
|
try {
|
|
16
18
|
assertSlug(slug);
|
|
17
19
|
}
|
package/dist/commands/update.js
CHANGED
|
@@ -3,6 +3,7 @@ import { join } from 'node:path';
|
|
|
3
3
|
import { createInterface } from 'node:readline/promises';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import ora from 'ora';
|
|
6
|
+
import { track } from '../lib/analytics.js';
|
|
6
7
|
import { api } from '../lib/api.js';
|
|
7
8
|
import { CONFIG } from '../lib/config.js';
|
|
8
9
|
import { requireAuth } from '../lib/credentials.js';
|
|
@@ -22,6 +23,7 @@ import { log } from '../utils/logger.js';
|
|
|
22
23
|
* changed: `markdown-pro v3 → v5 (last pulled 12 Apr · published 21 Apr)`.
|
|
23
24
|
*/
|
|
24
25
|
export async function updateCommand(slug, opts = {}) {
|
|
26
|
+
track('cli_update', { slug: slug ?? null, dry_run: !!opts.dryRun, yes: !!opts.yes });
|
|
25
27
|
const session = await requireAuth('prave update');
|
|
26
28
|
if (!session)
|
|
27
29
|
return;
|
package/dist/commands/usage.js
CHANGED
|
@@ -2,6 +2,7 @@ import { readdir, stat } from 'node:fs/promises';
|
|
|
2
2
|
import { basename, join } from 'node:path';
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import ora from 'ora';
|
|
5
|
+
import { track } from '../lib/analytics.js';
|
|
5
6
|
import { api, ApiError } from '../lib/api.js';
|
|
6
7
|
import { CONFIG } from '../lib/config.js';
|
|
7
8
|
import { requireAuth } from '../lib/credentials.js';
|
|
@@ -20,6 +21,7 @@ import { log } from '../utils/logger.js';
|
|
|
20
21
|
* used by `prave sync` to chain a scan without spamming the terminal.
|
|
21
22
|
*/
|
|
22
23
|
export async function usageScanCommand(opts) {
|
|
24
|
+
track('cli_usage_scan', { since: opts.since ?? null, quiet: !!opts.quiet });
|
|
23
25
|
const session = await requireAuth('prave usage scan');
|
|
24
26
|
if (!session)
|
|
25
27
|
return;
|
|
@@ -225,6 +227,7 @@ async function debugLog(line) {
|
|
|
225
227
|
}
|
|
226
228
|
}
|
|
227
229
|
export async function usageHookInstallCommand() {
|
|
230
|
+
track('cli_usage_hook_install');
|
|
228
231
|
const session = await requireAuth('prave usage hook install');
|
|
229
232
|
if (!session)
|
|
230
233
|
return;
|
|
@@ -237,6 +240,7 @@ export async function usageHookInstallCommand() {
|
|
|
237
240
|
printAgentResults(results, 'install');
|
|
238
241
|
}
|
|
239
242
|
export async function usageHookUninstallCommand() {
|
|
243
|
+
track('cli_usage_hook_uninstall');
|
|
240
244
|
const session = await requireAuth('prave usage hook uninstall');
|
|
241
245
|
if (!session)
|
|
242
246
|
return;
|
|
@@ -257,6 +261,7 @@ export async function usageHookUninstallCommand() {
|
|
|
257
261
|
* "unused for 30+ days" still shows up after running a Skill.
|
|
258
262
|
*/
|
|
259
263
|
export async function usageStatusCommand() {
|
|
264
|
+
track('cli_usage_status');
|
|
260
265
|
const session = await requireAuth('prave usage status');
|
|
261
266
|
if (!session)
|
|
262
267
|
return;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import ora from 'ora';
|
|
3
3
|
import { tokenTier } from '@prave/shared';
|
|
4
|
+
import { track } from '../lib/analytics.js';
|
|
4
5
|
import { api, ApiError } from '../lib/api.js';
|
|
5
6
|
import { log } from '../utils/logger.js';
|
|
6
7
|
const TIER_BADGE = {
|
|
@@ -15,6 +16,7 @@ function formatTokens(n) {
|
|
|
15
16
|
return `~${(n / 1000).toFixed(1)}k`;
|
|
16
17
|
}
|
|
17
18
|
export async function whatdoesCommand(skillName) {
|
|
19
|
+
track('cli_whatdoes', { slug: skillName });
|
|
18
20
|
const spinner = ora(`Looking up ${skillName}…`).start();
|
|
19
21
|
try {
|
|
20
22
|
const { data } = await api.get(`/api/v1/intelligence/whatdoes/${encodeURIComponent(skillName)}`, true);
|
package/dist/commands/whoami.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { track } from '../lib/analytics.js';
|
|
1
2
|
import { ApiError, api } from '../lib/api.js';
|
|
2
3
|
import { loadCredentials } from '../lib/credentials.js';
|
|
3
4
|
import { log } from '../utils/logger.js';
|
|
@@ -11,6 +12,7 @@ import { log } from '../utils/logger.js';
|
|
|
11
12
|
* locally cached email so the command stays useful in airplane mode.
|
|
12
13
|
*/
|
|
13
14
|
export async function whoamiCommand() {
|
|
15
|
+
track('cli_whoami');
|
|
14
16
|
const creds = await loadCredentials();
|
|
15
17
|
if (!creds) {
|
|
16
18
|
log.warn('Not logged in. Run `prave login`.');
|
package/dist/index.js
CHANGED
|
@@ -23,8 +23,10 @@ import { updateCommand } from './commands/update.js';
|
|
|
23
23
|
import { usageHookInstallCommand, usageHookUninstallCommand, usageReportCommand, usageScanCommand, usageStatusCommand, } from './commands/usage.js';
|
|
24
24
|
import { whatdoesCommand } from './commands/whatdoes.js';
|
|
25
25
|
import { whoamiCommand } from './commands/whoami.js';
|
|
26
|
+
import { initAnalytics } from './lib/analytics.js';
|
|
26
27
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
27
28
|
const pkg = JSON.parse(readFileSync(resolve(__dirname, '..', 'package.json'), 'utf8'));
|
|
29
|
+
initAnalytics(pkg.version);
|
|
28
30
|
const program = new Command()
|
|
29
31
|
.name('prave')
|
|
30
32
|
.description([
|
|
@@ -210,6 +212,9 @@ program
|
|
|
210
212
|
'Settings',
|
|
211
213
|
' prave settings # configure agents + paths',
|
|
212
214
|
'',
|
|
215
|
+
'Telemetry',
|
|
216
|
+
' PRAVE_TELEMETRY=0 # opt out of CLI usage analytics',
|
|
217
|
+
'',
|
|
213
218
|
'Docs: https://prave.app/docs',
|
|
214
219
|
].join('\n'));
|
|
215
220
|
});
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { homedir, platform, release } from 'node:os';
|
|
5
|
+
import { dirname, join, resolve } from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { request } from 'undici';
|
|
8
|
+
import { loadCredentials } from './credentials.js';
|
|
9
|
+
const DEFAULT_HOST = 'https://eu.i.posthog.com';
|
|
10
|
+
const ANON_ID_PATH = join(homedir(), '.prave', 'anon-id');
|
|
11
|
+
const isOptedOut = () => {
|
|
12
|
+
const v = process.env.PRAVE_TELEMETRY;
|
|
13
|
+
return v === '0' || v === 'false' || v === 'off' || v === 'no';
|
|
14
|
+
};
|
|
15
|
+
let cachedConfig = null;
|
|
16
|
+
const loadInjectedConfig = async () => {
|
|
17
|
+
try {
|
|
18
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
19
|
+
const configPath = resolve(__dirname, 'posthog-config.json');
|
|
20
|
+
if (!existsSync(configPath))
|
|
21
|
+
return {};
|
|
22
|
+
const raw = await readFile(configPath, 'utf8');
|
|
23
|
+
const parsed = JSON.parse(raw);
|
|
24
|
+
return { key: parsed.key ?? null, host: parsed.host ?? DEFAULT_HOST };
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return {};
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
const resolveConfig = async () => {
|
|
31
|
+
if (cachedConfig)
|
|
32
|
+
return cachedConfig;
|
|
33
|
+
const envKey = process.env.PRAVE_POSTHOG_KEY ?? null;
|
|
34
|
+
const envHost = process.env.PRAVE_POSTHOG_HOST ?? null;
|
|
35
|
+
if (envKey) {
|
|
36
|
+
cachedConfig = { key: envKey, host: envHost ?? DEFAULT_HOST };
|
|
37
|
+
return cachedConfig;
|
|
38
|
+
}
|
|
39
|
+
const injected = await loadInjectedConfig();
|
|
40
|
+
cachedConfig = {
|
|
41
|
+
key: injected.key ?? null,
|
|
42
|
+
host: envHost ?? injected.host ?? DEFAULT_HOST,
|
|
43
|
+
};
|
|
44
|
+
return cachedConfig;
|
|
45
|
+
};
|
|
46
|
+
let cachedDistinctId = null;
|
|
47
|
+
const loadAnonId = async () => {
|
|
48
|
+
try {
|
|
49
|
+
const raw = await readFile(ANON_ID_PATH, 'utf8');
|
|
50
|
+
const trimmed = raw.trim();
|
|
51
|
+
if (trimmed)
|
|
52
|
+
return trimmed;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
/* fall through to generation */
|
|
56
|
+
}
|
|
57
|
+
const fresh = randomUUID();
|
|
58
|
+
try {
|
|
59
|
+
await mkdir(join(homedir(), '.prave'), { recursive: true });
|
|
60
|
+
await writeFile(ANON_ID_PATH, fresh, 'utf8');
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
/* anonymous storage best-effort */
|
|
64
|
+
}
|
|
65
|
+
return fresh;
|
|
66
|
+
};
|
|
67
|
+
const resolveDistinctId = async () => {
|
|
68
|
+
if (cachedDistinctId)
|
|
69
|
+
return cachedDistinctId;
|
|
70
|
+
const creds = await loadCredentials();
|
|
71
|
+
cachedDistinctId = creds?.user_id ?? (await loadAnonId());
|
|
72
|
+
return cachedDistinctId;
|
|
73
|
+
};
|
|
74
|
+
let cliVersion = null;
|
|
75
|
+
const setCliVersion = (v) => {
|
|
76
|
+
cliVersion = v;
|
|
77
|
+
};
|
|
78
|
+
const baseProps = () => ({
|
|
79
|
+
$lib: 'prave-cli',
|
|
80
|
+
cli_version: cliVersion,
|
|
81
|
+
os: platform(),
|
|
82
|
+
os_release: release(),
|
|
83
|
+
node_version: process.version,
|
|
84
|
+
});
|
|
85
|
+
export const initAnalytics = (version) => {
|
|
86
|
+
setCliVersion(version);
|
|
87
|
+
};
|
|
88
|
+
export const track = (event, properties) => {
|
|
89
|
+
if (isOptedOut())
|
|
90
|
+
return;
|
|
91
|
+
// Fire and forget — never await, never throw.
|
|
92
|
+
void (async () => {
|
|
93
|
+
try {
|
|
94
|
+
const { key, host } = await resolveConfig();
|
|
95
|
+
if (!key)
|
|
96
|
+
return;
|
|
97
|
+
const distinctId = await resolveDistinctId();
|
|
98
|
+
await request(`${host}/capture/`, {
|
|
99
|
+
method: 'POST',
|
|
100
|
+
headers: { 'content-type': 'application/json' },
|
|
101
|
+
body: JSON.stringify({
|
|
102
|
+
api_key: key,
|
|
103
|
+
event,
|
|
104
|
+
distinct_id: distinctId,
|
|
105
|
+
properties: { ...baseProps(), ...properties },
|
|
106
|
+
timestamp: new Date().toISOString(),
|
|
107
|
+
}),
|
|
108
|
+
bodyTimeout: 3_000,
|
|
109
|
+
headersTimeout: 3_000,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
/* swallow */
|
|
114
|
+
}
|
|
115
|
+
})();
|
|
116
|
+
};
|
package/package.json
CHANGED
|
@@ -1,8 +1,43 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prave/cli",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Prave CLI —
|
|
3
|
+
"version": "1.1.1",
|
|
4
|
+
"description": "Prave CLI — discover, install, version, test, and ship Claude Skills. The developer platform for the complete Skill lifecycle.",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"claude",
|
|
8
|
+
"claude-code",
|
|
9
|
+
"claude-skills",
|
|
10
|
+
"skills",
|
|
11
|
+
"anthropic",
|
|
12
|
+
"ai",
|
|
13
|
+
"llm",
|
|
14
|
+
"agent",
|
|
15
|
+
"agents",
|
|
16
|
+
"ai-agent",
|
|
17
|
+
"agentic",
|
|
18
|
+
"cli",
|
|
19
|
+
"developer-tools",
|
|
20
|
+
"prompt-engineering",
|
|
21
|
+
"code-generation",
|
|
22
|
+
"skill-marketplace",
|
|
23
|
+
"skill-registry",
|
|
24
|
+
"prave"
|
|
25
|
+
],
|
|
26
|
+
"homepage": "https://prave.app",
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/eppstudio/prave/issues",
|
|
29
|
+
"email": "info@epplab-studio.de"
|
|
30
|
+
},
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "git+https://github.com/eppstudio/prave.git",
|
|
34
|
+
"directory": "apps/cli"
|
|
35
|
+
},
|
|
36
|
+
"author": "EppLab Studio <info@epplab-studio.de> (https://epplab-studio.de)",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=18"
|
|
40
|
+
},
|
|
6
41
|
"bin": {
|
|
7
42
|
"prave": "dist/index.js"
|
|
8
43
|
},
|
|
@@ -16,7 +51,7 @@
|
|
|
16
51
|
"open": "^10.1.0",
|
|
17
52
|
"ora": "^8.0.1",
|
|
18
53
|
"undici": "^6.18.0",
|
|
19
|
-
"@prave/shared": "1.
|
|
54
|
+
"@prave/shared": "1.1.1"
|
|
20
55
|
},
|
|
21
56
|
"devDependencies": {
|
|
22
57
|
"@types/node": "^20.12.7",
|
|
@@ -29,7 +64,7 @@
|
|
|
29
64
|
"scripts": {
|
|
30
65
|
"dev": "tsx src/index.ts --help",
|
|
31
66
|
"cli": "tsx src/index.ts",
|
|
32
|
-
"build": "tsc -p tsconfig.json",
|
|
67
|
+
"build": "tsc -p tsconfig.json && node scripts/inject-config.mjs",
|
|
33
68
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
34
69
|
"lint": "tsc -p tsconfig.json --noEmit"
|
|
35
70
|
}
|