@prave/cli 1.4.8 → 1.4.9
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/index.js +14 -1
- package/dist/lib/nudge.js +35 -1
- 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/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);
|
|
@@ -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`).
|
package/dist/lib/nudge.js
CHANGED
|
@@ -4,6 +4,23 @@ import { CONFIG } from './config.js';
|
|
|
4
4
|
import { loadCredentials } from './credentials.js';
|
|
5
5
|
import { isAlwaysShow, NUDGE_FIRST_RUN, nudgeFor, } from './nudge-constants.js';
|
|
6
6
|
let alreadyNudged = false;
|
|
7
|
+
/**
|
|
8
|
+
* Auth snapshot captured at command START, used at command END.
|
|
9
|
+
*
|
|
10
|
+
* Without this, `prave login` (very common first-ever command) traps
|
|
11
|
+
* us: the postAction hook fires AFTER credentials are saved, so the
|
|
12
|
+
* auth check inside canNudge() reads "signed in" → first-run banner
|
|
13
|
+
* suppressed → `first_run: false` written → user never sees the
|
|
14
|
+
* welcome message on any future command. The snapshot freezes the
|
|
15
|
+
* pre-command auth state so the first-run welcome still fires for a
|
|
16
|
+
* user whose very first command is the login itself.
|
|
17
|
+
*/
|
|
18
|
+
let wasAnonymousAtStart = null;
|
|
19
|
+
export async function captureAuthSnapshot() {
|
|
20
|
+
if (wasAnonymousAtStart !== null)
|
|
21
|
+
return;
|
|
22
|
+
wasAnonymousAtStart = !(await isAuthenticated());
|
|
23
|
+
}
|
|
7
24
|
/* --------------------------------------------------------------------- */
|
|
8
25
|
/* Auth + state helpers */
|
|
9
26
|
/* --------------------------------------------------------------------- */
|
|
@@ -101,11 +118,28 @@ async function canNudge() {
|
|
|
101
118
|
* (no nudge_count yet AND first_run not yet set to false). Always strong,
|
|
102
119
|
* always bypasses the throttle.
|
|
103
120
|
*
|
|
121
|
+
* Uses the START-of-command auth snapshot, not live state. That way the
|
|
122
|
+
* banner still appears when the user's very first command is `prave
|
|
123
|
+
* login` itself — login completes, the postAction hook fires, and we
|
|
124
|
+
* still know they came in anonymous so the welcome is appropriate.
|
|
125
|
+
*
|
|
104
126
|
* Returns true when shown — call sites use this to skip the regular nudge
|
|
105
127
|
* on the same turn so we don't double-print.
|
|
106
128
|
*/
|
|
107
129
|
export async function nudgeFirstRun() {
|
|
108
|
-
if (
|
|
130
|
+
if (alreadyNudged)
|
|
131
|
+
return false;
|
|
132
|
+
if (!process.stdout.isTTY)
|
|
133
|
+
return false;
|
|
134
|
+
if (process.env.PRAVE_QUIET === '1')
|
|
135
|
+
return false;
|
|
136
|
+
if (process.env.PRAVE_TELEMETRY === '0')
|
|
137
|
+
return false;
|
|
138
|
+
// Honour the auth-at-start snapshot. If the user opened the session
|
|
139
|
+
// already authenticated, the welcome conversion banner doesn't fit —
|
|
140
|
+
// they don't need a "create free account" pitch.
|
|
141
|
+
const startedAnon = wasAnonymousAtStart ?? !(await isAuthenticated());
|
|
142
|
+
if (!startedAnon)
|
|
109
143
|
return false;
|
|
110
144
|
const cfg = await readConfig();
|
|
111
145
|
// first_run defaults to "yes, show it" unless we've already flipped
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prave/cli",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.9",
|
|
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.9"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
60
|
"@types/node": "^20.12.7",
|