skillrepo 4.3.0 → 4.5.0
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/README.md +160 -3
- package/bin/skillrepo.mjs +45 -0
- package/package.json +3 -2
- package/src/commands/init.mjs +60 -2
- package/src/commands/list.mjs +328 -56
- package/src/lib/config.mjs +6 -0
- package/src/lib/crypto-shas.mjs +131 -0
- package/src/lib/drift.mjs +175 -0
- package/src/lib/file-write.mjs +16 -1
- package/src/lib/npm-update-check.mjs +366 -0
- package/src/lib/paths.mjs +10 -0
- package/src/lib/placement-walk.mjs +285 -0
- package/src/lib/sync.mjs +163 -17
- package/src/lib/telemetry.mjs +201 -0
- package/src/test/commands/init.test.mjs +85 -0
- package/src/test/commands/list.test.mjs +510 -2
- package/src/test/lib/config.test.mjs +33 -0
- package/src/test/lib/crypto-shas.test.mjs +172 -0
- package/src/test/lib/drift.test.mjs +289 -0
- package/src/test/lib/npm-update-check.test.mjs +670 -0
- package/src/test/lib/placement-walk.test.mjs +453 -0
- package/src/test/lib/sync.test.mjs +409 -1
- package/src/test/lib/telemetry.test.mjs +289 -0
package/README.md
CHANGED
|
@@ -179,14 +179,48 @@ One-shot fetch. Does NOT mutate your library or the server — just reads
|
|
|
179
179
|
`GET /api/v1/skills/{owner}/{name}` and writes the skill to disk. Use
|
|
180
180
|
this to preview or pin a specific skill without adding it to your library.
|
|
181
181
|
|
|
182
|
-
### `list` — show what's in your library
|
|
182
|
+
### `list` — show what's in your library and what needs syncing
|
|
183
183
|
|
|
184
184
|
```sh
|
|
185
185
|
skillrepo list [--json]
|
|
186
186
|
```
|
|
187
187
|
|
|
188
|
-
Renders your library as a table
|
|
189
|
-
|
|
188
|
+
Renders your library as a table with a per-row `Local` column showing
|
|
189
|
+
on-disk drift state for each detected vendor:
|
|
190
|
+
|
|
191
|
+
- `OK` — local copy matches the last sync.
|
|
192
|
+
- `STALE` — library has a newer version than what's on disk.
|
|
193
|
+
- `MISS` — library has the skill but no on-disk placement (or no sync
|
|
194
|
+
history yet — run `skillrepo update` to establish a baseline).
|
|
195
|
+
- `EDIT` — local files have been modified since the last sync (different
|
|
196
|
+
SHA than what was persisted).
|
|
197
|
+
|
|
198
|
+
When multiple vendors are detected, the column shows a worst-state-wins
|
|
199
|
+
rollup (`missing > edited > stale > current`). The `--json` output
|
|
200
|
+
includes a `placements[]` array per item with per-vendor states for
|
|
201
|
+
scripts that want the full breakdown.
|
|
202
|
+
|
|
203
|
+
A footer reports library-level sync state:
|
|
204
|
+
|
|
205
|
+
- `library in sync — local skills up to date` — everything is current.
|
|
206
|
+
- `library in sync — but N skills show local drift` — library hasn't
|
|
207
|
+
changed but some local placements need attention.
|
|
208
|
+
- `library has changed since last sync` — registry has new content; run
|
|
209
|
+
`skillrepo update`.
|
|
210
|
+
- `No sync history on this machine` — fresh install or
|
|
211
|
+
baseline-less state; run `skillrepo update`.
|
|
212
|
+
|
|
213
|
+
Glyphs (`✓` / `⚠`) are used in TTY contexts; ASCII fallbacks (`OK` /
|
|
214
|
+
`[!]` / `STALE` / `MISS` / `EDIT`) appear when stdout is not a TTY or
|
|
215
|
+
`NO_COLOR` is set, so piped output stays clean.
|
|
216
|
+
|
|
217
|
+
`--json` is a bare array of skill objects with the additional fields
|
|
218
|
+
`state` (rollup) and `placements[]`. Existing scripts that consume
|
|
219
|
+
the pre-#1555 `--json` shape keep working — the additions are purely
|
|
220
|
+
per-item, no top-level wrapper.
|
|
221
|
+
|
|
222
|
+
Uses the same cached ETag as `update` for the library-level footer
|
|
223
|
+
state.
|
|
190
224
|
|
|
191
225
|
### `search` — explore the registry
|
|
192
226
|
|
|
@@ -219,6 +253,109 @@ DELETEs from `/api/v1/library` and deletes the local directory. Requires
|
|
|
219
253
|
a write-scoped access key. The local delete is immediate and does not
|
|
220
254
|
wait for a follow-up sync.
|
|
221
255
|
|
|
256
|
+
### `push` — upload a local skill directory to your account
|
|
257
|
+
|
|
258
|
+
```sh
|
|
259
|
+
skillrepo push <path> [--idempotency-key <key>] [--key <key>] [--url <url>] [--json]
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Multipart `POST` to `/api/v1/library`. Walks `<path>`, packages
|
|
263
|
+
`SKILL.md` plus every supporting file under `scripts/`, `references/`,
|
|
264
|
+
and `assets/`, and uploads them as a single request. The server picks
|
|
265
|
+
the outcome by SKILL.md frontmatter `name`:
|
|
266
|
+
|
|
267
|
+
- **First push** of this name → creates a private skill and returns
|
|
268
|
+
`action: "created"`.
|
|
269
|
+
- **Subsequent push with changed content** → releases a new version.
|
|
270
|
+
The server classifies the bump as major (if `description`,
|
|
271
|
+
`allowed-tools`, or `compatibility` changed) or minor otherwise, and
|
|
272
|
+
returns `action: "updated"` with the bump kind.
|
|
273
|
+
- **Identical content** → no-op (SHA-matched). Returns
|
|
274
|
+
`action: "unchanged"`.
|
|
275
|
+
|
|
276
|
+
`push` is the only CLI command that uploads local content; it does not
|
|
277
|
+
write anything back to disk. Use `update` to pull canonical skills
|
|
278
|
+
from the server to your local library.
|
|
279
|
+
|
|
280
|
+
Limits: total multipart body ≤ 4.5 MB, per-file path depth ≤ 5
|
|
281
|
+
segments, executable/archive extensions blocked (full list in
|
|
282
|
+
`src/lib/skills/constants.ts`). Anti-abuse rate limit: 5/min and
|
|
283
|
+
30/hr on Publisher; 30/min and 500/hr on Team.
|
|
284
|
+
|
|
285
|
+
Flags:
|
|
286
|
+
|
|
287
|
+
- `--idempotency-key <key>` — explicit key for safe retries. By default
|
|
288
|
+
the CLI generates a fresh UUID per invocation and uses it for the
|
|
289
|
+
in-process retry loop (transient 5xx/429 get up to 3 attempts with
|
|
290
|
+
exponential backoff and jitter). Pass an explicit key to share it
|
|
291
|
+
across separate shell invocations (CI step retries, manual reruns)
|
|
292
|
+
and replay the cached response. Cached responses live for 24 hours.
|
|
293
|
+
- `--json` — emit a structured object (`action`, `bump`, `owner`,
|
|
294
|
+
`name`, `version`, `filesUploaded`).
|
|
295
|
+
- `--key`, `--url` — standard auth / endpoint flags.
|
|
296
|
+
|
|
297
|
+
Exit codes: `5` (validation — bad SKILL.md, blocked path, payload too
|
|
298
|
+
large, `plan_limit`), `4` (scope — read-only key), `2` (auth), `1`
|
|
299
|
+
(network/5xx after retries).
|
|
300
|
+
|
|
301
|
+
### `publish` — make one of your skills visible in the public catalog
|
|
302
|
+
|
|
303
|
+
```sh
|
|
304
|
+
skillrepo publish <@owner/name> [--key <key>] [--url <url>] [--json]
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
`POST`s to `/api/v1/library/{owner}/{name}/publish` to flip the
|
|
308
|
+
skill's visibility from `private` to `global`. Idempotent: calling
|
|
309
|
+
`publish` on an already-global skill returns `200` with
|
|
310
|
+
`action: "unchanged"` (the CLI prints "Already published").
|
|
311
|
+
Requires a write-scoped access key.
|
|
312
|
+
|
|
313
|
+
Permission model: admin+ members can always publish. Non-admin members
|
|
314
|
+
can publish if their account-membership has `canPublish: true` (or the
|
|
315
|
+
account-wide `memberCanPublish` default is enabled). Without either,
|
|
316
|
+
the CLI exits `4 / scope` with `code: publish_not_permitted`. The same
|
|
317
|
+
`canPublish` capability gates `unpublish` and `delete` symmetrically.
|
|
318
|
+
|
|
319
|
+
Publish-only preconditions that surface as exit `5 / validation`:
|
|
320
|
+
|
|
321
|
+
- `namespace_unset` — the account's name still equals its
|
|
322
|
+
auto-generated slug; customize the namespace first.
|
|
323
|
+
- `analysis_pending` — safety analysis hasn't completed (only fires
|
|
324
|
+
where analysis is enabled).
|
|
325
|
+
- `safety_grade_too_low` — the skill's safety grade is `F`.
|
|
326
|
+
|
|
327
|
+
Flags:
|
|
328
|
+
|
|
329
|
+
- `--json` — emit `{ action, owner, name }`. The CLI exits non-zero on error, so the presence of stdout JSON already implies success — there is no `ok` field.
|
|
330
|
+
- `--key`, `--url` — standard auth / endpoint flags.
|
|
331
|
+
|
|
332
|
+
### `unpublish` — remove one of your skills from the public catalog
|
|
333
|
+
|
|
334
|
+
```sh
|
|
335
|
+
skillrepo unpublish <@owner/name> [--key <key>] [--url <url>] [--json]
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
`POST`s to `/api/v1/library/{owner}/{name}/unpublish` to flip the
|
|
339
|
+
skill's visibility from `global` to `private`. Pair to `publish`:
|
|
340
|
+
same auth, same scope, same flag surface.
|
|
341
|
+
|
|
342
|
+
**Subscribers keep their copy.** Accounts that already had your skill
|
|
343
|
+
in their library retain the version they pulled — they just stop
|
|
344
|
+
receiving future updates unless you republish. The CLI surfaces a
|
|
345
|
+
one-line summary (e.g. "Notified 12 subscribers") so you know how
|
|
346
|
+
many accounts the unpublish reached.
|
|
347
|
+
|
|
348
|
+
Each affected subscriber account's owner-role member(s) receive a
|
|
349
|
+
one-time notification email, debounced 24h per `(skill, account)`
|
|
350
|
+
pair so a fast unpublish/republish/unpublish cycle doesn't spam the
|
|
351
|
+
same recipient. The publisher's own account is excluded.
|
|
352
|
+
Already-private skills (`action: "unchanged"`) trigger no emails.
|
|
353
|
+
|
|
354
|
+
Flags:
|
|
355
|
+
|
|
356
|
+
- `--json` — emit `{ action, owner, name, notifiedSubscriberCount }`. `notifiedSubscriberCount` is `0` when `action === "unchanged"`. No `ok` field — exit code carries success/failure.
|
|
357
|
+
- `--key`, `--url` — standard auth / endpoint flags.
|
|
358
|
+
|
|
222
359
|
### `session-sync` — auto-sync on Claude Code session start
|
|
223
360
|
|
|
224
361
|
```sh
|
|
@@ -371,8 +508,28 @@ Two scenarios worth calling out:
|
|
|
371
508
|
| `SKILLREPO_ACCESS_KEY` | Access key for any command. Takes precedence over the config file but not CLI flags. |
|
|
372
509
|
| `SKILLREPO_URL` | Server URL. Same precedence as above. |
|
|
373
510
|
| `SKILLREPO_TIMEOUT_MS` | Per-request fetch timeout in milliseconds (default 30000). Set to `0` to disable. |
|
|
511
|
+
| `SKILLREPO_NO_UPDATE_CHECK` | Set to any non-empty truthy value (`1`, `yes`, `true`) to disable the post-command npm-registry self-staleness check. The check otherwise runs at most once per 24 hours, hits `registry.npmjs.org/skillrepo/latest`, and prints a one-line upgrade hint to stderr if a newer version is available. Auto-disabled when `CI=true`. |
|
|
374
512
|
| `NO_COLOR` | Set any non-empty value to disable ANSI color in CLI output. |
|
|
375
513
|
|
|
514
|
+
### Update nudge
|
|
515
|
+
|
|
516
|
+
After every command that isn't `--json`, the CLI does a best-effort
|
|
517
|
+
check against `https://registry.npmjs.org/skillrepo/latest` and prints
|
|
518
|
+
a one-line hint on stderr when a newer version is available:
|
|
519
|
+
|
|
520
|
+
```
|
|
521
|
+
A newer skillrepo is available: 4.3.0 → 4.5.0
|
|
522
|
+
Upgrade: npm install -g skillrepo@latest
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
The check is cached at `~/.claude/skillrepo/.npm-version-check` for
|
|
526
|
+
24 hours on success and 1 hour on failure, has a 2-second fetch
|
|
527
|
+
timeout, and is fire-and-forget — every failure mode (network error,
|
|
528
|
+
non-2xx, parse failure, read-only FS) is swallowed silently. Set
|
|
529
|
+
`SKILLREPO_NO_UPDATE_CHECK=1` to disable. `CI=true` auto-disables.
|
|
530
|
+
Output is suppressed entirely when `--json` is on the parent command,
|
|
531
|
+
so structured pipelines aren't disturbed.
|
|
532
|
+
|
|
376
533
|
### Skill placement
|
|
377
534
|
|
|
378
535
|
Skills land at one of two project paths, depending on the agent:
|
package/bin/skillrepo.mjs
CHANGED
|
@@ -35,6 +35,8 @@ import { runSearch } from "../src/commands/search.mjs";
|
|
|
35
35
|
import { runUninstall } from "../src/commands/uninstall.mjs";
|
|
36
36
|
import { runSessionSync } from "../src/commands/session-sync.mjs";
|
|
37
37
|
import { CliError, EXIT_OK, EXIT_VALIDATION } from "../src/lib/errors.mjs";
|
|
38
|
+
import { checkForCliUpdate } from "../src/lib/npm-update-check.mjs";
|
|
39
|
+
import { getCliVersion } from "../src/lib/cli-version.mjs";
|
|
38
40
|
|
|
39
41
|
// ── Command registry ────────────────────────────────────────────────────
|
|
40
42
|
|
|
@@ -151,6 +153,49 @@ async function main(command, fullArgv) {
|
|
|
151
153
|
}
|
|
152
154
|
|
|
153
155
|
await COMMANDS[command].run(rest);
|
|
156
|
+
|
|
157
|
+
// After the primary command completes, do a best-effort npm-registry
|
|
158
|
+
// staleness check (#1554). Never blocks exit beyond a single tick:
|
|
159
|
+
// `Promise.race` against `setTimeout(0)` means if the fetch hasn't
|
|
160
|
+
// completed yet, we drop it and the user gets the nudge on the next
|
|
161
|
+
// invocation (when the cache file is more likely to be fresh).
|
|
162
|
+
//
|
|
163
|
+
// Suppressed entirely when the parent argv carries `--json` so we
|
|
164
|
+
// never inject text into a structured stream — not even on stderr,
|
|
165
|
+
// because some pipelines tee both streams.
|
|
166
|
+
if (!rest.includes("--json")) {
|
|
167
|
+
await runUpdateCheck();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Best-effort update check. On a CACHE HIT this resolves synchronously
|
|
173
|
+
* (within a microtask) and we emit the nudge before the 0ms timer
|
|
174
|
+
* fires — that's the steady-state behavior after the first invocation.
|
|
175
|
+
*
|
|
176
|
+
* On a cache miss we race against `setTimeout(0)` so the user's primary
|
|
177
|
+
* command exit isn't held up by the nudge logic when they don't have
|
|
178
|
+
* a cached answer yet. The in-flight fetch is INTENTIONALLY left
|
|
179
|
+
* running after the race resolves: it has its own 2s `AbortController`
|
|
180
|
+
* (inside `checkForCliUpdate`) and is silent on failure, so the worst
|
|
181
|
+
* case is the process appearing to take slightly longer on its very
|
|
182
|
+
* first invocation while the cache warms. Every subsequent invocation
|
|
183
|
+
* benefits from the 24h positive cache and exits immediately.
|
|
184
|
+
*
|
|
185
|
+
* Errors are swallowed at the source by `checkForCliUpdate` itself; the
|
|
186
|
+
* outer `.catch` is belt-and-braces for the rare case where loading
|
|
187
|
+
* the module synchronously throws.
|
|
188
|
+
*/
|
|
189
|
+
async function runUpdateCheck() {
|
|
190
|
+
let currentVersion;
|
|
191
|
+
try {
|
|
192
|
+
currentVersion = getCliVersion();
|
|
193
|
+
} catch {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
const checker = checkForCliUpdate({ currentVersion }).catch(() => {});
|
|
197
|
+
const yieldOnce = new Promise((resolve) => setTimeout(resolve, 0));
|
|
198
|
+
await Promise.race([checker, yieldOnce]);
|
|
154
199
|
}
|
|
155
200
|
|
|
156
201
|
// ── Help printing ───────────────────────────────────────────────────────
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skillrepo",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.5.0",
|
|
4
4
|
"description": "Pull-based CLI for agent skills — init, sync, search, add, remove your library from any IDE",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"license": "SEE LICENSE IN LICENSE",
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"cli-table3": "^0.6.5",
|
|
29
|
-
"gray-matter": "^4.0.3"
|
|
29
|
+
"gray-matter": "^4.0.3",
|
|
30
|
+
"semver": "^7.6.3"
|
|
30
31
|
}
|
|
31
32
|
}
|
package/src/commands/init.mjs
CHANGED
|
@@ -87,7 +87,7 @@ import {
|
|
|
87
87
|
claudeSkillsProjectRoot,
|
|
88
88
|
agentsSkillsProjectRoot,
|
|
89
89
|
} from "../lib/paths.mjs";
|
|
90
|
-
import { promptWithBrowserOpen } from "../lib/prompt.mjs";
|
|
90
|
+
import { promptWithBrowserOpen, confirm } from "../lib/prompt.mjs";
|
|
91
91
|
import { promptMultiSelect } from "../lib/prompt-multiselect.mjs";
|
|
92
92
|
import {
|
|
93
93
|
CliError,
|
|
@@ -96,6 +96,10 @@ import {
|
|
|
96
96
|
EXIT_AUTH,
|
|
97
97
|
} from "../lib/errors.mjs";
|
|
98
98
|
import { cliAuthUrl } from "../lib/constants.mjs";
|
|
99
|
+
import {
|
|
100
|
+
reportInitFailure,
|
|
101
|
+
telemetryDisabledByEnv,
|
|
102
|
+
} from "../lib/telemetry.mjs";
|
|
99
103
|
|
|
100
104
|
/**
|
|
101
105
|
* Format the user-visible "configured X, Y" line for the init step-4
|
|
@@ -288,6 +292,38 @@ export async function runInit(argv, io = {}, deps = {}) {
|
|
|
288
292
|
|
|
289
293
|
p.blank();
|
|
290
294
|
|
|
295
|
+
// Determine the telemetry preference for THIS init run (#1539).
|
|
296
|
+
// Priority: SKILLREPO_NO_TELEMETRY env var (always wins) → existing
|
|
297
|
+
// config flag (if set explicitly) → opt-out default of `true`
|
|
298
|
+
// (enabled). The env-var check is the only opt-out path that fires
|
|
299
|
+
// BEFORE the very first user interaction; everything else assumes
|
|
300
|
+
// the user is willing to receive the prompt below.
|
|
301
|
+
let telemetryEnabledForRun;
|
|
302
|
+
if (telemetryDisabledByEnv()) {
|
|
303
|
+
telemetryEnabledForRun = false;
|
|
304
|
+
} else if (
|
|
305
|
+
existingConfig &&
|
|
306
|
+
typeof existingConfig.telemetry === "boolean"
|
|
307
|
+
) {
|
|
308
|
+
telemetryEnabledForRun = existingConfig.telemetry;
|
|
309
|
+
} else if (yes || !process.stdin.isTTY) {
|
|
310
|
+
// Non-interactive: take the opt-out-friendly default. Users in
|
|
311
|
+
// CI / scripts can pin `SKILLREPO_NO_TELEMETRY=1` to override.
|
|
312
|
+
// The `!isTTY` check protects existing CI patterns like
|
|
313
|
+
// `init --key sk_live_...` (no --yes) that worked before this
|
|
314
|
+
// prompt was added — they would hang on `readline.question()`
|
|
315
|
+
// waiting for stdin that never arrives.
|
|
316
|
+
telemetryEnabledForRun = true;
|
|
317
|
+
} else {
|
|
318
|
+
// First-init prompt — only fires when no preference is recorded,
|
|
319
|
+
// the env var didn't already opt out, AND stdin is a TTY. Y/n
|
|
320
|
+
// with Y default, so a bare Enter keeps telemetry enabled.
|
|
321
|
+
telemetryEnabledForRun = await confirm(
|
|
322
|
+
"Send anonymous error reports to help improve setup?",
|
|
323
|
+
true,
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
|
|
291
327
|
// ── Step 2: Validate against the server ──────────────────────
|
|
292
328
|
p.step(2, 7, "Validating key");
|
|
293
329
|
let accountCtx;
|
|
@@ -315,8 +351,27 @@ export async function runInit(argv, io = {}, deps = {}) {
|
|
|
315
351
|
if (!apiKey || !apiKey.startsWith("sk_live_")) {
|
|
316
352
|
throw validationError("Invalid access key format.");
|
|
317
353
|
}
|
|
318
|
-
|
|
354
|
+
try {
|
|
355
|
+
accountCtx = await validateAccessKey(serverUrl, apiKey, "init");
|
|
356
|
+
} catch (retryErr) {
|
|
357
|
+
// The user re-pasted and validate still failed. This is the
|
|
358
|
+
// failure mode the diagnostic exercise surfaced — exactly the
|
|
359
|
+
// case telemetry exists for. Fire-and-forget; never throws.
|
|
360
|
+
void reportInitFailure({
|
|
361
|
+
serverUrl,
|
|
362
|
+
config: telemetryEnabledForRun ? { telemetry: true } : { telemetry: false },
|
|
363
|
+
stage: "post_paste_validate",
|
|
364
|
+
errorCode: retryErr instanceof CliError ? retryErr.exitCode : EXIT_AUTH,
|
|
365
|
+
});
|
|
366
|
+
throw retryErr;
|
|
367
|
+
}
|
|
319
368
|
} else {
|
|
369
|
+
void reportInitFailure({
|
|
370
|
+
serverUrl,
|
|
371
|
+
config: telemetryEnabledForRun ? { telemetry: true } : { telemetry: false },
|
|
372
|
+
stage: "post_paste_validate",
|
|
373
|
+
errorCode: err instanceof CliError ? err.exitCode : EXIT_AUTH,
|
|
374
|
+
});
|
|
320
375
|
throw err;
|
|
321
376
|
}
|
|
322
377
|
}
|
|
@@ -325,12 +380,15 @@ export async function runInit(argv, io = {}, deps = {}) {
|
|
|
325
380
|
|
|
326
381
|
// ── Step 3: Write global config ──────────────────────────────
|
|
327
382
|
p.step(3, 7, "Writing config");
|
|
383
|
+
// Persist the telemetry preference alongside the credentials so
|
|
384
|
+
// subsequent inits skip the prompt and honor the same choice (#1539).
|
|
328
385
|
const configAction = writeConfig({
|
|
329
386
|
apiKey,
|
|
330
387
|
serverUrl,
|
|
331
388
|
accountSlug: accountCtx.accountSlug,
|
|
332
389
|
accountId: accountCtx.accountId,
|
|
333
390
|
userId: accountCtx.userId,
|
|
391
|
+
telemetry: telemetryEnabledForRun,
|
|
334
392
|
});
|
|
335
393
|
p.success(`~/.claude/skillrepo/config.json ${configAction}`);
|
|
336
394
|
|