@prave/cli 1.4.8 → 1.4.10
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/install.js +14 -2
- package/dist/commands/login.js +17 -5
- package/dist/commands/settings.js +8 -15
- package/dist/commands/usage.js +3 -3
- package/dist/index.js +21 -8
- package/dist/lib/local-config.js +44 -0
- package/dist/lib/nudge-constants.js +1 -1
- package/dist/lib/nudge.js +60 -25
- package/package.json +2 -2
package/dist/commands/install.js
CHANGED
|
@@ -89,14 +89,26 @@ export async function installCommand(slug, opts = {}) {
|
|
|
89
89
|
process.exitCode = 1;
|
|
90
90
|
return;
|
|
91
91
|
}
|
|
92
|
-
// Best-effort analyze pass on the freshly written files.
|
|
92
|
+
// Best-effort analyze pass on the freshly written files. Silently
|
|
93
|
+
// catching all errors here used to hide a real failure mode: when the
|
|
94
|
+
// user's CLI token had expired, every analyze call returned 401, the
|
|
95
|
+
// install ledger filled up, but skill_metadata stayed empty — so the
|
|
96
|
+
// web dashboard rendered honest zeros and looked broken. We still
|
|
97
|
+
// don't bail on transient errors (the install itself succeeded), but
|
|
98
|
+
// we DO surface auth failures once so the user knows to re-login.
|
|
99
|
+
let authWarned = false;
|
|
93
100
|
for (const s of installedSlugs) {
|
|
94
101
|
const path = join(CONFIG.skillsDir, s, 'SKILL.md');
|
|
95
102
|
try {
|
|
96
103
|
const content = await readFile(path, 'utf8');
|
|
97
104
|
await api
|
|
98
105
|
.post('/api/v1/intelligence/analyze', { content, file_path: path, agent_type: 'claude' }, true)
|
|
99
|
-
.catch(() => {
|
|
106
|
+
.catch((err) => {
|
|
107
|
+
if (!authWarned && err instanceof ApiError && err.status === 401) {
|
|
108
|
+
authWarned = true;
|
|
109
|
+
log.warn('Your CLI session expired — Skill intelligence will be out of sync until you run `prave login`.');
|
|
110
|
+
}
|
|
111
|
+
});
|
|
100
112
|
}
|
|
101
113
|
catch {
|
|
102
114
|
/* file unreadable — skip */
|
package/dist/commands/login.js
CHANGED
|
@@ -5,6 +5,7 @@ import { track } from '../lib/analytics.js';
|
|
|
5
5
|
import { api, ApiError } from '../lib/api.js';
|
|
6
6
|
import { CONFIG } from '../lib/config.js';
|
|
7
7
|
import { saveCredentials } from '../lib/credentials.js';
|
|
8
|
+
import { readLocalConfig, writeLocalConfigPatch } from '../lib/local-config.js';
|
|
8
9
|
import { log } from '../utils/logger.js';
|
|
9
10
|
/**
|
|
10
11
|
* `prave login` — device-code flow against the Prave API / Supabase session.
|
|
@@ -51,12 +52,23 @@ export async function loginCommand() {
|
|
|
51
52
|
catch (flushErr) {
|
|
52
53
|
log.dim(`Telemetry sync skipped: ${flushErr.message}`);
|
|
53
54
|
}
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
//
|
|
55
|
+
// First-login onboarding only. The agent picker + hook installer
|
|
56
|
+
// used to fire on EVERY login, which was annoying for users who
|
|
57
|
+
// re-login often (CI environments, multi-machine setups, after a
|
|
58
|
+
// token expiry). Now we gate on a persisted flag in
|
|
59
|
+
// ~/.prave/config.json — once they've completed the picker once,
|
|
60
|
+
// it never auto-fires again. Manual re-run available via
|
|
61
|
+
// `prave settings agent`.
|
|
57
62
|
try {
|
|
58
|
-
const
|
|
59
|
-
|
|
63
|
+
const cfg = await readLocalConfig();
|
|
64
|
+
if (cfg.agent_onboarding_done !== true) {
|
|
65
|
+
const { runAgentOnboarding } = await import('../lib/agent-onboarding.js');
|
|
66
|
+
await runAgentOnboarding();
|
|
67
|
+
await writeLocalConfigPatch({ agent_onboarding_done: true });
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
log.dim('Welcome back — run `prave settings agent` to change your agent setup.');
|
|
71
|
+
}
|
|
60
72
|
}
|
|
61
73
|
catch (onboardErr) {
|
|
62
74
|
log.dim(`Agent onboarding skipped: ${onboardErr.message}`);
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
1
|
import { createInterface } from 'node:readline/promises';
|
|
3
2
|
import chalk from 'chalk';
|
|
4
3
|
import { AGENT_REGISTRY } from '@prave/shared';
|
|
5
4
|
import { api, ApiError } from '../lib/api.js';
|
|
6
5
|
import { requireAuth } from '../lib/credentials.js';
|
|
7
|
-
import {
|
|
6
|
+
import { writeLocalConfigPatch } from '../lib/local-config.js';
|
|
8
7
|
import { log } from '../utils/logger.js';
|
|
9
8
|
function detectOs() {
|
|
10
9
|
if (process.platform === 'darwin')
|
|
@@ -13,20 +12,14 @@ function detectOs() {
|
|
|
13
12
|
return 'windows';
|
|
14
13
|
return 'linux';
|
|
15
14
|
}
|
|
16
|
-
async function loadLocalConfig() {
|
|
17
|
-
try {
|
|
18
|
-
const raw = await readFile(CONFIG.configPath, 'utf8');
|
|
19
|
-
return JSON.parse(raw);
|
|
20
|
-
}
|
|
21
|
-
catch {
|
|
22
|
-
return {};
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
15
|
async function saveLocalConfig(settings) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
await
|
|
16
|
+
// Mark onboarding done as a side effect — running `prave settings
|
|
17
|
+
// agent` manually counts as completing the picker, so the user won't
|
|
18
|
+
// get auto-prompted again on the next `prave login`.
|
|
19
|
+
await writeLocalConfigPatch({
|
|
20
|
+
agentSettings: settings,
|
|
21
|
+
agent_onboarding_done: true,
|
|
22
|
+
});
|
|
30
23
|
}
|
|
31
24
|
async function fetchSettings() {
|
|
32
25
|
const { data } = await api.get('/api/v1/settings/agents', true);
|
package/dist/commands/usage.js
CHANGED
|
@@ -432,8 +432,8 @@ export async function usageStatusCommand() {
|
|
|
432
432
|
const checkmark = (ok) => (ok ? chalk.green('✓') : chalk.red('✗'));
|
|
433
433
|
log.info(chalk.bold('Usage tracking status'));
|
|
434
434
|
console.log();
|
|
435
|
-
console.log(` ${checkmark(toolHookInstalled)}
|
|
436
|
-
console.log(` ${checkmark(promptHookInstalled)}
|
|
435
|
+
console.log(` ${checkmark(toolHookInstalled)} Skill invocation tracking: ${toolHookInstalled ? chalk.green('installed') : chalk.yellow('missing — `prave usage hook install`')}`);
|
|
436
|
+
console.log(` ${checkmark(promptHookInstalled)} Slash-command tracking (e.g. /graphify): ${promptHookInstalled ? chalk.green('installed') : chalk.yellow('missing — `prave usage hook install`')}`);
|
|
437
437
|
console.log(` ${checkmark(apiReachable)} API reachable + auth valid: ${apiReachable ? chalk.green('yes') : chalk.red(apiMessage || 'no')}`);
|
|
438
438
|
console.log(` ${checkmark(Boolean(lastScanAt))} Transcript scanner watermark: ${lastScanAt ?? chalk.dim('never run — `prave sync` includes it')}`);
|
|
439
439
|
console.log(` ${checkmark(recent7 > 0)} Events in last 7 days: ${chalk.cyan(String(recent7))}`);
|
|
@@ -470,7 +470,7 @@ export async function usageStatusCommand() {
|
|
|
470
470
|
console.log();
|
|
471
471
|
log.warn('Telemetry may be incomplete. Suggested fixes:');
|
|
472
472
|
if (!toolHookInstalled || !promptHookInstalled) {
|
|
473
|
-
log.dim(' • Run `prave usage hook install` to
|
|
473
|
+
log.dim(' • Run `prave usage hook install` to enable both Skill-fire and slash-command tracking.');
|
|
474
474
|
}
|
|
475
475
|
if (!apiReachable) {
|
|
476
476
|
log.dim(' • Run `prave login` — your access token may have expired (silently 401-ing).');
|
package/dist/index.js
CHANGED
|
@@ -24,7 +24,7 @@ import { usageHookInstallCommand, usageHookUninstallCommand, usageReportCommand,
|
|
|
24
24
|
import { whatdoesCommand } from './commands/whatdoes.js';
|
|
25
25
|
import { whoamiCommand } from './commands/whoami.js';
|
|
26
26
|
import { initAnalytics } from './lib/analytics.js';
|
|
27
|
-
import { nudgeFirstRun } from './lib/nudge.js';
|
|
27
|
+
import { captureAuthSnapshot, nudgeFirstRun } from './lib/nudge.js';
|
|
28
28
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
29
29
|
const pkg = JSON.parse(readFileSync(resolve(__dirname, '..', 'package.json'), 'utf8'));
|
|
30
30
|
initAnalytics(pkg.version);
|
|
@@ -49,7 +49,7 @@ const program = new Command()
|
|
|
49
49
|
.addHelpText('after', '\nRun `prave <cmd> --help` for command-specific options.');
|
|
50
50
|
program
|
|
51
51
|
.command('login')
|
|
52
|
-
.description('
|
|
52
|
+
.description('Sign this machine in (browser opens, no password typed). Credentials are stored securely on disk and refreshed automatically.')
|
|
53
53
|
.action(loginCommand);
|
|
54
54
|
program
|
|
55
55
|
.command('logout')
|
|
@@ -130,17 +130,17 @@ const usage = program
|
|
|
130
130
|
.description('Track which Skills you actually use (powers the optimiser)');
|
|
131
131
|
usage
|
|
132
132
|
.command('report')
|
|
133
|
-
.description('Internal: invoked by the
|
|
134
|
-
.option('--source <kind>', '
|
|
133
|
+
.description('Internal: invoked by the agent when a Skill fires (reads payload from stdin)')
|
|
134
|
+
.option('--source <kind>', 'event channel that fired this report', 'tool')
|
|
135
135
|
.action((opts) => usageReportCommand(opts));
|
|
136
|
-
const hook = usage.command('hook').description('
|
|
136
|
+
const hook = usage.command('hook').description('Enable / disable real-time Skill invocation tracking');
|
|
137
137
|
hook
|
|
138
138
|
.command('install')
|
|
139
|
-
.description('
|
|
139
|
+
.description('Enable real-time invocation tracking for your installed Skills')
|
|
140
140
|
.action(usageHookInstallCommand);
|
|
141
141
|
hook
|
|
142
142
|
.command('uninstall')
|
|
143
|
-
.description('
|
|
143
|
+
.description('Disable real-time invocation tracking')
|
|
144
144
|
.action(usageHookUninstallCommand);
|
|
145
145
|
program
|
|
146
146
|
.command('mcp-server')
|
|
@@ -188,7 +188,7 @@ program
|
|
|
188
188
|
' prave optimize --remove-unused # delete 30d-silent skills from disk',
|
|
189
189
|
'',
|
|
190
190
|
'Usage tracking (Pro+)',
|
|
191
|
-
' prave usage hook install # real-time
|
|
191
|
+
' prave usage hook install # enable real-time invocation tracking',
|
|
192
192
|
' prave usage hook uninstall',
|
|
193
193
|
'',
|
|
194
194
|
'Settings',
|
|
@@ -204,6 +204,19 @@ program
|
|
|
204
204
|
'Docs: https://prave.app/docs',
|
|
205
205
|
].join('\n'));
|
|
206
206
|
});
|
|
207
|
+
// Capture auth state BEFORE the command runs. Critical for the
|
|
208
|
+
// first-run welcome banner — if the user's very first command is
|
|
209
|
+
// `prave login`, the postAction hook fires AFTER credentials are
|
|
210
|
+
// saved, so a live auth check would read "signed in" and suppress
|
|
211
|
+
// the welcome. The preAction snapshot freezes the pre-command state.
|
|
212
|
+
program.hook('preAction', async () => {
|
|
213
|
+
try {
|
|
214
|
+
await captureAuthSnapshot();
|
|
215
|
+
}
|
|
216
|
+
catch {
|
|
217
|
+
/* never block the command on nudge bookkeeping */
|
|
218
|
+
}
|
|
219
|
+
});
|
|
207
220
|
// Global first-run banner. Fires once on the user's very first command
|
|
208
221
|
// regardless of which one it was — catches commands that don't have a
|
|
209
222
|
// per-action nudge wired in (e.g. `prave docs`, `prave conflicts`).
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { CONFIG } from './config.js';
|
|
3
|
+
/**
|
|
4
|
+
* Shared read / write for `~/.prave/config.json`.
|
|
5
|
+
*
|
|
6
|
+
* The same file holds three classes of state, all merged into one
|
|
7
|
+
* JSON object so callers can patch one key without clobbering the
|
|
8
|
+
* others:
|
|
9
|
+
*
|
|
10
|
+
* • `agentSettings` — written by `prave settings`
|
|
11
|
+
* • Nudge bookkeeping (`first_run`, `nudge_count`) — written by
|
|
12
|
+
* the conversion-nudge module
|
|
13
|
+
* • Onboarding flags (`agent_onboarding_done`) — written by
|
|
14
|
+
* `prave login` so we only walk the user through the agent
|
|
15
|
+
* picker once
|
|
16
|
+
*
|
|
17
|
+
* Previously each consumer reimplemented the same readFile / merge /
|
|
18
|
+
* writeFile dance — three copies in three files. Centralising here
|
|
19
|
+
* means a missing key in one consumer no longer wipes the keys
|
|
20
|
+
* another consumer just wrote.
|
|
21
|
+
*/
|
|
22
|
+
export async function readLocalConfig() {
|
|
23
|
+
try {
|
|
24
|
+
const raw = await readFile(CONFIG.configPath, 'utf8');
|
|
25
|
+
const parsed = JSON.parse(raw);
|
|
26
|
+
if (parsed && typeof parsed === 'object')
|
|
27
|
+
return parsed;
|
|
28
|
+
return {};
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return {};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Merge-write: reads the current config, shallow-merges `patch`, and
|
|
36
|
+
* writes the result. Creates `~/.prave/` with restrictive mode (0700)
|
|
37
|
+
* if it doesn't exist yet.
|
|
38
|
+
*/
|
|
39
|
+
export async function writeLocalConfigPatch(patch) {
|
|
40
|
+
const existing = await readLocalConfig();
|
|
41
|
+
const next = { ...existing, ...patch };
|
|
42
|
+
await mkdir(CONFIG.praveDir, { recursive: true, mode: 0o700 });
|
|
43
|
+
await writeFile(CONFIG.configPath, JSON.stringify(next, null, 2), 'utf8');
|
|
44
|
+
}
|
|
@@ -47,7 +47,7 @@ export const NUDGE_DEEP = {
|
|
|
47
47
|
bullets: [
|
|
48
48
|
'AI-generated descriptions for all your Skills',
|
|
49
49
|
'Conflict detection across your library',
|
|
50
|
-
'30-day
|
|
50
|
+
'30-day Skill invocation history',
|
|
51
51
|
'Cross-machine sync',
|
|
52
52
|
],
|
|
53
53
|
cta: 'prave.app/signup · free forever · 10 seconds',
|
package/dist/lib/nudge.js
CHANGED
|
@@ -1,9 +1,45 @@
|
|
|
1
|
-
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
1
|
import chalk from 'chalk';
|
|
3
|
-
import { CONFIG } from './config.js';
|
|
4
2
|
import { loadCredentials } from './credentials.js';
|
|
3
|
+
import { readLocalConfig, writeLocalConfigPatch } from './local-config.js';
|
|
5
4
|
import { isAlwaysShow, NUDGE_FIRST_RUN, nudgeFor, } from './nudge-constants.js';
|
|
5
|
+
/**
|
|
6
|
+
* Conversion nudges for anonymous CLI users.
|
|
7
|
+
*
|
|
8
|
+
* 4,300 npm-installs, 1 signed-in account. The CLI works for anonymous
|
|
9
|
+
* users by design (lower friction = more installs) but the handoff to
|
|
10
|
+
* the dashboard was missing. These nudges fix that.
|
|
11
|
+
*
|
|
12
|
+
* Rules baked in here, not in the call sites:
|
|
13
|
+
* • Silent for signed-in users. Always.
|
|
14
|
+
* • Soft nudges throttled to ~1 in every 3 commands via a counter
|
|
15
|
+
* persisted to ~/.prave/config.json (`nudge_count`).
|
|
16
|
+
* • Strong nudges (overview/whatdoes/first-run) bypass the throttle —
|
|
17
|
+
* they're the highest-intent moments and worth a fuller pitch.
|
|
18
|
+
* • First-run banner shows once on the user's very first command;
|
|
19
|
+
* `first_run: false` then locks it down forever.
|
|
20
|
+
* • One nudge per process. Multiple commands chained in a wrapper
|
|
21
|
+
* script don't spam.
|
|
22
|
+
* • Skipped when stdout isn't a TTY (piped output, CI) and when
|
|
23
|
+
* PRAVE_QUIET=1 / PRAVE_TELEMETRY=0.
|
|
24
|
+
*/
|
|
6
25
|
let alreadyNudged = false;
|
|
26
|
+
/**
|
|
27
|
+
* Auth snapshot captured at command START, used at command END.
|
|
28
|
+
*
|
|
29
|
+
* Without this, `prave login` (very common first-ever command) traps
|
|
30
|
+
* us: the postAction hook fires AFTER credentials are saved, so the
|
|
31
|
+
* auth check inside canNudge() reads "signed in" → first-run banner
|
|
32
|
+
* suppressed → `first_run: false` written → user never sees the
|
|
33
|
+
* welcome message on any future command. The snapshot freezes the
|
|
34
|
+
* pre-command auth state so the first-run welcome still fires for a
|
|
35
|
+
* user whose very first command is the login itself.
|
|
36
|
+
*/
|
|
37
|
+
let wasAnonymousAtStart = null;
|
|
38
|
+
export async function captureAuthSnapshot() {
|
|
39
|
+
if (wasAnonymousAtStart !== null)
|
|
40
|
+
return;
|
|
41
|
+
wasAnonymousAtStart = !(await isAuthenticated());
|
|
42
|
+
}
|
|
7
43
|
/* --------------------------------------------------------------------- */
|
|
8
44
|
/* Auth + state helpers */
|
|
9
45
|
/* --------------------------------------------------------------------- */
|
|
@@ -18,24 +54,6 @@ export async function isAuthenticated() {
|
|
|
18
54
|
}
|
|
19
55
|
return true;
|
|
20
56
|
}
|
|
21
|
-
async function readConfig() {
|
|
22
|
-
try {
|
|
23
|
-
const raw = await readFile(CONFIG.configPath, 'utf8');
|
|
24
|
-
const parsed = JSON.parse(raw);
|
|
25
|
-
if (parsed && typeof parsed === 'object')
|
|
26
|
-
return parsed;
|
|
27
|
-
return {};
|
|
28
|
-
}
|
|
29
|
-
catch {
|
|
30
|
-
return {};
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
async function writeConfigPatch(patch) {
|
|
34
|
-
const existing = await readConfig();
|
|
35
|
-
const next = { ...existing, ...patch };
|
|
36
|
-
await mkdir(CONFIG.praveDir, { recursive: true, mode: 0o700 });
|
|
37
|
-
await writeFile(CONFIG.configPath, JSON.stringify(next, null, 2), 'utf8');
|
|
38
|
-
}
|
|
39
57
|
/**
|
|
40
58
|
* Counter-based throttle for soft nudges. Reads the current count,
|
|
41
59
|
* increments, persists, and returns true when (count % 3 === 0) — so
|
|
@@ -43,10 +61,10 @@ async function writeConfigPatch(patch) {
|
|
|
43
61
|
* we'd rather skip than be loud on the user's first real command.
|
|
44
62
|
*/
|
|
45
63
|
export async function shouldShowNudge() {
|
|
46
|
-
const cfg = await
|
|
64
|
+
const cfg = await readLocalConfig();
|
|
47
65
|
const current = typeof cfg.nudge_count === 'number' ? cfg.nudge_count : 0;
|
|
48
66
|
const next = current + 1;
|
|
49
|
-
await
|
|
67
|
+
await writeLocalConfigPatch({ nudge_count: next });
|
|
50
68
|
return next % 3 === 0;
|
|
51
69
|
}
|
|
52
70
|
/* --------------------------------------------------------------------- */
|
|
@@ -101,13 +119,30 @@ async function canNudge() {
|
|
|
101
119
|
* (no nudge_count yet AND first_run not yet set to false). Always strong,
|
|
102
120
|
* always bypasses the throttle.
|
|
103
121
|
*
|
|
122
|
+
* Uses the START-of-command auth snapshot, not live state. That way the
|
|
123
|
+
* banner still appears when the user's very first command is `prave
|
|
124
|
+
* login` itself — login completes, the postAction hook fires, and we
|
|
125
|
+
* still know they came in anonymous so the welcome is appropriate.
|
|
126
|
+
*
|
|
104
127
|
* Returns true when shown — call sites use this to skip the regular nudge
|
|
105
128
|
* on the same turn so we don't double-print.
|
|
106
129
|
*/
|
|
107
130
|
export async function nudgeFirstRun() {
|
|
108
|
-
if (
|
|
131
|
+
if (alreadyNudged)
|
|
132
|
+
return false;
|
|
133
|
+
if (!process.stdout.isTTY)
|
|
134
|
+
return false;
|
|
135
|
+
if (process.env.PRAVE_QUIET === '1')
|
|
136
|
+
return false;
|
|
137
|
+
if (process.env.PRAVE_TELEMETRY === '0')
|
|
138
|
+
return false;
|
|
139
|
+
// Honour the auth-at-start snapshot. If the user opened the session
|
|
140
|
+
// already authenticated, the welcome conversion banner doesn't fit —
|
|
141
|
+
// they don't need a "create free account" pitch.
|
|
142
|
+
const startedAnon = wasAnonymousAtStart ?? !(await isAuthenticated());
|
|
143
|
+
if (!startedAnon)
|
|
109
144
|
return false;
|
|
110
|
-
const cfg = await
|
|
145
|
+
const cfg = await readLocalConfig();
|
|
111
146
|
// first_run defaults to "yes, show it" unless we've already flipped
|
|
112
147
|
// the flag. A missing config file → first run.
|
|
113
148
|
const alreadyShown = cfg.first_run === false;
|
|
@@ -115,7 +150,7 @@ export async function nudgeFirstRun() {
|
|
|
115
150
|
return false;
|
|
116
151
|
alreadyNudged = true;
|
|
117
152
|
showNudge(NUDGE_FIRST_RUN);
|
|
118
|
-
await
|
|
153
|
+
await writeLocalConfigPatch({ first_run: false });
|
|
119
154
|
return true;
|
|
120
155
|
}
|
|
121
156
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prave/cli",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.10",
|
|
4
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
6
|
"keywords": [
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"ora": "^8.0.1",
|
|
55
55
|
"tar": "^7.4.3",
|
|
56
56
|
"undici": "^6.18.0",
|
|
57
|
-
"@prave/shared": "1.4.
|
|
57
|
+
"@prave/shared": "1.4.10"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
60
|
"@types/node": "^20.12.7",
|