@lpm-registry/cli 0.7.0 → 0.8.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/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [0.8.0] - 2026-04-01
6
+
7
+ ### Changed
8
+
9
+ - **Rust binary v0.8.0** — Install hash fast-exit (82ms → 26ms up-to-date), NDJSON streaming batch metadata, resolver carries tarball URLs (eliminates double metadata fetch), up-to-date benchmark added.
10
+ - **Scoped registry default** — `lpm setup` and `lpm npmrc` now write scoped config (`@lpm.dev:registry=`) by default. npm packages go direct to npmjs.org (faster, $0 proxy cost). Use `--proxy` to opt into full proxy mode (Pro/Org feature).
11
+ - **Global config defaults** — `lpm config set allowNew true`, `lpm config set autoBuild true`, etc. CLI flags merge with `~/.lpm/config.toml` defaults.
12
+ - **Migrate fix** — Corrected stale registry URL in `lpm migrate` (.npmrc now writes `/api/registry/` instead of `/api/packages/`).
13
+ - Version bump to stay in sync with Rust binary releases.
14
+
5
15
  ## [0.7.0] - 2026-04-01
6
16
 
7
17
  ### Changed
package/bin/lpm-bin ADDED
@@ -0,0 +1,347 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * LPM CLI Entry Point — Minimal fallback wrapper.
5
+ *
6
+ * In most cases, this file has been replaced by a hard link to the native
7
+ * Rust binary during postinstall (zero Node.js overhead). This JS wrapper
8
+ * only runs when:
9
+ *
10
+ * 1. Hard-link failed (cross-device mount, permissions)
11
+ * 2. npm rebuild recreated the symlink
12
+ * 3. Binary download failed during postinstall
13
+ *
14
+ * Resolution order:
15
+ * 1. Try platform package binary (optionalDependencies)
16
+ * 2. Try lpm-bin in bin/ directory (GitHub Releases download)
17
+ * 3. Fall through to JS CLI implementation
18
+ */
19
+
20
+ import { execFileSync } from "node:child_process"
21
+ import fs from "node:fs"
22
+ import { createRequire } from "node:module"
23
+ import os from "node:os"
24
+ import path from "node:path"
25
+ import { fileURLToPath } from "node:url"
26
+
27
+ const __dirname = path.dirname(fileURLToPath(import.meta.url))
28
+ const require = createRequire(import.meta.url)
29
+
30
+ // ─── Try native binary (Tier 1: platform package) ──────────────────
31
+
32
+ const PLATFORMS = {
33
+ "darwin-arm64": { pkg: "@lpm-registry/cli-darwin-arm64", binary: "lpm" },
34
+ "darwin-x64": { pkg: "@lpm-registry/cli-darwin-x64", binary: "lpm" },
35
+ "linux-x64": { pkg: "@lpm-registry/cli-linux-x64", binary: "lpm" },
36
+ "linux-arm64": { pkg: "@lpm-registry/cli-linux-arm64", binary: "lpm" },
37
+ "win32-x64": { pkg: "@lpm-registry/cli-win32-x64", binary: "lpm.exe" },
38
+ }
39
+
40
+ // Allow override via environment variable (for debugging / custom builds)
41
+ const envBinary = process.env.LPM_BINARY_PATH
42
+ if (envBinary && fs.existsSync(envBinary)) {
43
+ runBinary(envBinary)
44
+ }
45
+
46
+ // Try platform package from optionalDependencies
47
+ const platform = `${process.platform}-${os.arch()}`
48
+ const platformInfo = PLATFORMS[platform]
49
+
50
+ if (platformInfo) {
51
+ try {
52
+ const pkgJsonPath = require.resolve(`${platformInfo.pkg}/package.json`)
53
+ const binaryPath = path.join(path.dirname(pkgJsonPath), platformInfo.binary)
54
+ if (fs.existsSync(binaryPath)) {
55
+ runBinary(binaryPath)
56
+ }
57
+ } catch {
58
+ // Package not installed
59
+ }
60
+ }
61
+
62
+ // ─── Try native binary (Tier 2: downloaded by postinstall) ─────────
63
+
64
+ const legacyBinaryName =
65
+ process.platform === "win32" ? "lpm-bin.exe" : "lpm-bin"
66
+ const legacyBinaryPath = path.join(__dirname, legacyBinaryName)
67
+
68
+ if (fs.existsSync(legacyBinaryPath)) {
69
+ runBinary(legacyBinaryPath)
70
+ }
71
+
72
+ // ─── JS CLI fallback (Tier 3) ──────────────────────────────────────
73
+
74
+ import { Command } from "commander"
75
+ import updateNotifier from "update-notifier"
76
+ import { add } from "../lib/commands/add.js"
77
+ import { audit } from "../lib/commands/audit.js"
78
+ import { cache } from "../lib/commands/cache.js"
79
+ import { checkName } from "../lib/commands/check-name.js"
80
+ import { config } from "../lib/commands/config.js"
81
+ import { doctor } from "../lib/commands/doctor.js"
82
+ import { info } from "../lib/commands/info.js"
83
+ import { init } from "../lib/commands/init.js"
84
+ import { install } from "../lib/commands/install.js"
85
+ import { login } from "../lib/commands/login.js"
86
+ import { logout } from "../lib/commands/logout.js"
87
+ import { marketplaceCompare } from "../lib/commands/marketplace-compare.js"
88
+ import { marketplaceEarnings } from "../lib/commands/marketplace-earnings.js"
89
+ import { mcpRemove, mcpSetup, mcpStatus } from "../lib/commands/mcp-setup.js"
90
+ import { npmrc } from "../lib/commands/npmrc.js"
91
+ import { openDashboard } from "../lib/commands/open.js"
92
+ import { outdated } from "../lib/commands/outdated.js"
93
+ import { poolStats } from "../lib/commands/pool-stats.js"
94
+ import { publish } from "../lib/commands/publish.js"
95
+ import { quality } from "../lib/commands/quality.js"
96
+ import { remove } from "../lib/commands/remove.js"
97
+ import { run } from "../lib/commands/run.js"
98
+ import { search } from "../lib/commands/search.js"
99
+ import { setup } from "../lib/commands/setup.js"
100
+ import {
101
+ skillsClean,
102
+ skillsInstall,
103
+ skillsList,
104
+ skillsValidate,
105
+ } from "../lib/commands/skills.js"
106
+ import { rotateToken } from "../lib/commands/token-rotate.js"
107
+ import { uninstall } from "../lib/commands/uninstall.js"
108
+ import { whoami } from "../lib/commands/whoami.js"
109
+
110
+ // Load package.json
111
+ const pkg = JSON.parse(
112
+ fs.readFileSync(path.join(__dirname, "../package.json"), "utf-8"),
113
+ )
114
+
115
+ // Check for updates
116
+ updateNotifier({ pkg }).notify()
117
+
118
+ const program = new Command()
119
+
120
+ program
121
+ .name("lpm")
122
+ .description("CLI for Licensed Package Manager")
123
+ .version(pkg.version)
124
+
125
+ // Authentication
126
+ program
127
+ .command("login")
128
+ .alias("l")
129
+ .description("Authenticate with the registry")
130
+ .action(login)
131
+ program
132
+ .command("logout")
133
+ .alias("lo")
134
+ .description("Clear stored authentication token")
135
+ .option("--revoke", "Also revoke the token on the server")
136
+ .option("--clear-cache", "Clear local package cache")
137
+ .action(logout)
138
+ program
139
+ .command("whoami")
140
+ .description("Check current authenticated user")
141
+ .option("--json", "Output in JSON format")
142
+ .action(whoami)
143
+
144
+ // Package Management
145
+ program
146
+ .command("init")
147
+ .description("Interactively create a package.json for LPM")
148
+ .action(init)
149
+ program
150
+ .command("install [packages...]")
151
+ .alias("i")
152
+ .description("Install packages")
153
+ .option("--json", "Machine-readable JSON output")
154
+ .option("--no-skills", "Skip fetching Agent Skills")
155
+ .option("--pm <manager>", "Package manager to use")
156
+ .action(install)
157
+ program
158
+ .command("uninstall <packages...>")
159
+ .aliases(["un", "unlink"])
160
+ .description("Uninstall packages")
161
+ .option("--pm <manager>", "Package manager to use")
162
+ .action(uninstall)
163
+ program
164
+ .command("publish")
165
+ .alias("p")
166
+ .description("Publish a package to the registry")
167
+ .option("--check", "Quality check only")
168
+ .option("--min-score <score>", "Minimum quality score")
169
+ .option("--provenance", "Force OIDC provenance")
170
+ .option("--dry-run", "Preview without publishing")
171
+ .action(publish)
172
+ program
173
+ .command("add <package>")
174
+ .description("Extract package source code")
175
+ .option("-p, --path <path>", "Target directory")
176
+ .option("-f, --force", "Overwrite existing files")
177
+ .option("-y, --yes", "Accept defaults")
178
+ .option("--alias <alias>", "Import alias prefix")
179
+ .option("--target <name>", "Swift SPM target")
180
+ .option("--json", "JSON output")
181
+ .option("--dry-run", "Preview only")
182
+ .action(add)
183
+ program
184
+ .command("remove <package>")
185
+ .alias("rm")
186
+ .description("Remove a previously added package")
187
+ .action(remove)
188
+
189
+ // Discovery
190
+ program
191
+ .command("search <query>")
192
+ .description("Search packages")
193
+ .option("--limit <n>", "Max results", "20")
194
+ .option("--json", "JSON output")
195
+ .action((q, o) => search(q, { ...o, limit: parseInt(o.limit, 10) }))
196
+ program
197
+ .command("info <package>")
198
+ .description("Package info")
199
+ .option("--json", "JSON output")
200
+ .option("-a, --all-versions", "Show all versions")
201
+ .action(info)
202
+ program
203
+ .command("check-name <name>")
204
+ .description("Check name availability")
205
+ .option("--json", "JSON output")
206
+ .action(checkName)
207
+ program
208
+ .command("quality <package>")
209
+ .description("Quality report")
210
+ .option("--json", "JSON output")
211
+ .action(quality)
212
+
213
+ // Maintenance
214
+ program
215
+ .command("audit [action]")
216
+ .description("Security audit")
217
+ .option("--json", "JSON output")
218
+ .option("--level <level>", "Minimum severity")
219
+ .action(audit)
220
+ program
221
+ .command("outdated")
222
+ .description("Check outdated deps")
223
+ .option("--json", "JSON output")
224
+ .option("--all", "Show all deps")
225
+ .action(outdated)
226
+ program.command("doctor").description("Health check").action(doctor)
227
+
228
+ // Configuration
229
+ program
230
+ .command("setup")
231
+ .description("Configure .npmrc")
232
+ .option("-r, --registry <url>", "Custom registry URL")
233
+ .option("--oidc", "Exchange OIDC token")
234
+ .option("--scoped", "Scoped registry only")
235
+ .action(setup)
236
+ program
237
+ .command("npmrc")
238
+ .description("Generate read-only .npmrc token")
239
+ .option("-d, --days <number>", "Token expiry days")
240
+ .option("--scoped", "Scoped registry only")
241
+ .action(npmrc)
242
+ program
243
+ .command("config [action] [key] [value]")
244
+ .description("Manage CLI config")
245
+ .action(config)
246
+ program
247
+ .command("set <key> <value>")
248
+ .description('Shortcut for "lpm config set"')
249
+ .action((k, v) => config("set", k, v))
250
+ program
251
+ .command("cache <action>")
252
+ .description("Manage local cache")
253
+ .action(cache)
254
+
255
+ // Utility
256
+ program
257
+ .command("open")
258
+ .description("Open dashboard in browser")
259
+ .action(openDashboard)
260
+ program
261
+ .command("run <script>")
262
+ .description("Run npm scripts")
263
+ .allowUnknownOption()
264
+ .action(run)
265
+
266
+ // Subcommands
267
+ const token = program.command("token").description("Token management")
268
+ token.command("rotate").description("Rotate token").action(rotateToken)
269
+
270
+ const pool = program.command("pool").description("Pool revenue")
271
+ pool
272
+ .command("stats")
273
+ .description("Pool earnings")
274
+ .option("--json", "JSON output")
275
+ .action(poolStats)
276
+
277
+ const mcp = program.command("mcp").description("MCP server")
278
+ mcp
279
+ .command("setup")
280
+ .description("Configure MCP server")
281
+ .option("--project", "Project-level config")
282
+ .action(mcpSetup)
283
+ mcp
284
+ .command("remove")
285
+ .description("Remove MCP server")
286
+ .option("--project", "Project-level only")
287
+ .action(mcpRemove)
288
+ mcp
289
+ .command("status")
290
+ .description("MCP server status")
291
+ .option("--verbose", "Show diagnostics")
292
+ .action(mcpStatus)
293
+
294
+ const skills = program.command("skills").description("Agent Skills")
295
+ skills
296
+ .command("validate")
297
+ .description("Validate skills files")
298
+ .option("--json", "JSON output")
299
+ .action(skillsValidate)
300
+ skills
301
+ .command("install [package]")
302
+ .description("Install skills")
303
+ .option("--json", "JSON output")
304
+ .action(skillsInstall)
305
+ skills
306
+ .command("list")
307
+ .description("List available skills")
308
+ .option("--json", "JSON output")
309
+ .action(skillsList)
310
+ skills
311
+ .command("clean")
312
+ .description("Remove installed skills")
313
+ .option("--json", "JSON output")
314
+ .action(skillsClean)
315
+
316
+ const marketplace = program.command("marketplace").description("Marketplace")
317
+ marketplace
318
+ .command("compare <input>")
319
+ .description("Find comparable packages")
320
+ .option("--json", "JSON output")
321
+ .option("--category <category>", "Filter by category")
322
+ .option("--limit <n>", "Max results")
323
+ .action(marketplaceCompare)
324
+ marketplace
325
+ .command("earnings")
326
+ .description("Revenue summary")
327
+ .option("--json", "JSON output")
328
+ .action(marketplaceEarnings)
329
+
330
+ program.parse()
331
+
332
+ // ─── Helper ────────────────────────────────────────────────────────
333
+
334
+ function runBinary(binaryPath) {
335
+ try {
336
+ execFileSync(binaryPath, process.argv.slice(2), {
337
+ stdio: "inherit",
338
+ env: process.env,
339
+ })
340
+ process.exit(0)
341
+ } catch (err) {
342
+ if (err.status != null) {
343
+ process.exit(err.status)
344
+ }
345
+ // Binary failed to execute — fall through to JS CLI
346
+ }
347
+ }
package/bin/lpm.js.bak ADDED
@@ -0,0 +1,347 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * LPM CLI Entry Point — Minimal fallback wrapper.
5
+ *
6
+ * In most cases, this file has been replaced by a hard link to the native
7
+ * Rust binary during postinstall (zero Node.js overhead). This JS wrapper
8
+ * only runs when:
9
+ *
10
+ * 1. Hard-link failed (cross-device mount, permissions)
11
+ * 2. npm rebuild recreated the symlink
12
+ * 3. Binary download failed during postinstall
13
+ *
14
+ * Resolution order:
15
+ * 1. Try platform package binary (optionalDependencies)
16
+ * 2. Try lpm-bin in bin/ directory (GitHub Releases download)
17
+ * 3. Fall through to JS CLI implementation
18
+ */
19
+
20
+ import { execFileSync } from "node:child_process"
21
+ import fs from "node:fs"
22
+ import { createRequire } from "node:module"
23
+ import os from "node:os"
24
+ import path from "node:path"
25
+ import { fileURLToPath } from "node:url"
26
+
27
+ const __dirname = path.dirname(fileURLToPath(import.meta.url))
28
+ const require = createRequire(import.meta.url)
29
+
30
+ // ─── Try native binary (Tier 1: platform package) ──────────────────
31
+
32
+ const PLATFORMS = {
33
+ "darwin-arm64": { pkg: "@lpm-registry/cli-darwin-arm64", binary: "lpm" },
34
+ "darwin-x64": { pkg: "@lpm-registry/cli-darwin-x64", binary: "lpm" },
35
+ "linux-x64": { pkg: "@lpm-registry/cli-linux-x64", binary: "lpm" },
36
+ "linux-arm64": { pkg: "@lpm-registry/cli-linux-arm64", binary: "lpm" },
37
+ "win32-x64": { pkg: "@lpm-registry/cli-win32-x64", binary: "lpm.exe" },
38
+ }
39
+
40
+ // Allow override via environment variable (for debugging / custom builds)
41
+ const envBinary = process.env.LPM_BINARY_PATH
42
+ if (envBinary && fs.existsSync(envBinary)) {
43
+ runBinary(envBinary)
44
+ }
45
+
46
+ // Try platform package from optionalDependencies
47
+ const platform = `${process.platform}-${os.arch()}`
48
+ const platformInfo = PLATFORMS[platform]
49
+
50
+ if (platformInfo) {
51
+ try {
52
+ const pkgJsonPath = require.resolve(`${platformInfo.pkg}/package.json`)
53
+ const binaryPath = path.join(path.dirname(pkgJsonPath), platformInfo.binary)
54
+ if (fs.existsSync(binaryPath)) {
55
+ runBinary(binaryPath)
56
+ }
57
+ } catch {
58
+ // Package not installed
59
+ }
60
+ }
61
+
62
+ // ─── Try native binary (Tier 2: downloaded by postinstall) ─────────
63
+
64
+ const legacyBinaryName =
65
+ process.platform === "win32" ? "lpm-bin.exe" : "lpm-bin"
66
+ const legacyBinaryPath = path.join(__dirname, legacyBinaryName)
67
+
68
+ if (fs.existsSync(legacyBinaryPath)) {
69
+ runBinary(legacyBinaryPath)
70
+ }
71
+
72
+ // ─── JS CLI fallback (Tier 3) ──────────────────────────────────────
73
+
74
+ import { Command } from "commander"
75
+ import updateNotifier from "update-notifier"
76
+ import { add } from "../lib/commands/add.js"
77
+ import { audit } from "../lib/commands/audit.js"
78
+ import { cache } from "../lib/commands/cache.js"
79
+ import { checkName } from "../lib/commands/check-name.js"
80
+ import { config } from "../lib/commands/config.js"
81
+ import { doctor } from "../lib/commands/doctor.js"
82
+ import { info } from "../lib/commands/info.js"
83
+ import { init } from "../lib/commands/init.js"
84
+ import { install } from "../lib/commands/install.js"
85
+ import { login } from "../lib/commands/login.js"
86
+ import { logout } from "../lib/commands/logout.js"
87
+ import { marketplaceCompare } from "../lib/commands/marketplace-compare.js"
88
+ import { marketplaceEarnings } from "../lib/commands/marketplace-earnings.js"
89
+ import { mcpRemove, mcpSetup, mcpStatus } from "../lib/commands/mcp-setup.js"
90
+ import { npmrc } from "../lib/commands/npmrc.js"
91
+ import { openDashboard } from "../lib/commands/open.js"
92
+ import { outdated } from "../lib/commands/outdated.js"
93
+ import { poolStats } from "../lib/commands/pool-stats.js"
94
+ import { publish } from "../lib/commands/publish.js"
95
+ import { quality } from "../lib/commands/quality.js"
96
+ import { remove } from "../lib/commands/remove.js"
97
+ import { run } from "../lib/commands/run.js"
98
+ import { search } from "../lib/commands/search.js"
99
+ import { setup } from "../lib/commands/setup.js"
100
+ import {
101
+ skillsClean,
102
+ skillsInstall,
103
+ skillsList,
104
+ skillsValidate,
105
+ } from "../lib/commands/skills.js"
106
+ import { rotateToken } from "../lib/commands/token-rotate.js"
107
+ import { uninstall } from "../lib/commands/uninstall.js"
108
+ import { whoami } from "../lib/commands/whoami.js"
109
+
110
+ // Load package.json
111
+ const pkg = JSON.parse(
112
+ fs.readFileSync(path.join(__dirname, "../package.json"), "utf-8"),
113
+ )
114
+
115
+ // Check for updates
116
+ updateNotifier({ pkg }).notify()
117
+
118
+ const program = new Command()
119
+
120
+ program
121
+ .name("lpm")
122
+ .description("CLI for Licensed Package Manager")
123
+ .version(pkg.version)
124
+
125
+ // Authentication
126
+ program
127
+ .command("login")
128
+ .alias("l")
129
+ .description("Authenticate with the registry")
130
+ .action(login)
131
+ program
132
+ .command("logout")
133
+ .alias("lo")
134
+ .description("Clear stored authentication token")
135
+ .option("--revoke", "Also revoke the token on the server")
136
+ .option("--clear-cache", "Clear local package cache")
137
+ .action(logout)
138
+ program
139
+ .command("whoami")
140
+ .description("Check current authenticated user")
141
+ .option("--json", "Output in JSON format")
142
+ .action(whoami)
143
+
144
+ // Package Management
145
+ program
146
+ .command("init")
147
+ .description("Interactively create a package.json for LPM")
148
+ .action(init)
149
+ program
150
+ .command("install [packages...]")
151
+ .alias("i")
152
+ .description("Install packages")
153
+ .option("--json", "Machine-readable JSON output")
154
+ .option("--no-skills", "Skip fetching Agent Skills")
155
+ .option("--pm <manager>", "Package manager to use")
156
+ .action(install)
157
+ program
158
+ .command("uninstall <packages...>")
159
+ .aliases(["un", "unlink"])
160
+ .description("Uninstall packages")
161
+ .option("--pm <manager>", "Package manager to use")
162
+ .action(uninstall)
163
+ program
164
+ .command("publish")
165
+ .alias("p")
166
+ .description("Publish a package to the registry")
167
+ .option("--check", "Quality check only")
168
+ .option("--min-score <score>", "Minimum quality score")
169
+ .option("--provenance", "Force OIDC provenance")
170
+ .option("--dry-run", "Preview without publishing")
171
+ .action(publish)
172
+ program
173
+ .command("add <package>")
174
+ .description("Extract package source code")
175
+ .option("-p, --path <path>", "Target directory")
176
+ .option("-f, --force", "Overwrite existing files")
177
+ .option("-y, --yes", "Accept defaults")
178
+ .option("--alias <alias>", "Import alias prefix")
179
+ .option("--target <name>", "Swift SPM target")
180
+ .option("--json", "JSON output")
181
+ .option("--dry-run", "Preview only")
182
+ .action(add)
183
+ program
184
+ .command("remove <package>")
185
+ .alias("rm")
186
+ .description("Remove a previously added package")
187
+ .action(remove)
188
+
189
+ // Discovery
190
+ program
191
+ .command("search <query>")
192
+ .description("Search packages")
193
+ .option("--limit <n>", "Max results", "20")
194
+ .option("--json", "JSON output")
195
+ .action((q, o) => search(q, { ...o, limit: parseInt(o.limit, 10) }))
196
+ program
197
+ .command("info <package>")
198
+ .description("Package info")
199
+ .option("--json", "JSON output")
200
+ .option("-a, --all-versions", "Show all versions")
201
+ .action(info)
202
+ program
203
+ .command("check-name <name>")
204
+ .description("Check name availability")
205
+ .option("--json", "JSON output")
206
+ .action(checkName)
207
+ program
208
+ .command("quality <package>")
209
+ .description("Quality report")
210
+ .option("--json", "JSON output")
211
+ .action(quality)
212
+
213
+ // Maintenance
214
+ program
215
+ .command("audit [action]")
216
+ .description("Security audit")
217
+ .option("--json", "JSON output")
218
+ .option("--level <level>", "Minimum severity")
219
+ .action(audit)
220
+ program
221
+ .command("outdated")
222
+ .description("Check outdated deps")
223
+ .option("--json", "JSON output")
224
+ .option("--all", "Show all deps")
225
+ .action(outdated)
226
+ program.command("doctor").description("Health check").action(doctor)
227
+
228
+ // Configuration
229
+ program
230
+ .command("setup")
231
+ .description("Configure .npmrc")
232
+ .option("-r, --registry <url>", "Custom registry URL")
233
+ .option("--oidc", "Exchange OIDC token")
234
+ .option("--scoped", "Scoped registry only")
235
+ .action(setup)
236
+ program
237
+ .command("npmrc")
238
+ .description("Generate read-only .npmrc token")
239
+ .option("-d, --days <number>", "Token expiry days")
240
+ .option("--scoped", "Scoped registry only")
241
+ .action(npmrc)
242
+ program
243
+ .command("config [action] [key] [value]")
244
+ .description("Manage CLI config")
245
+ .action(config)
246
+ program
247
+ .command("set <key> <value>")
248
+ .description('Shortcut for "lpm config set"')
249
+ .action((k, v) => config("set", k, v))
250
+ program
251
+ .command("cache <action>")
252
+ .description("Manage local cache")
253
+ .action(cache)
254
+
255
+ // Utility
256
+ program
257
+ .command("open")
258
+ .description("Open dashboard in browser")
259
+ .action(openDashboard)
260
+ program
261
+ .command("run <script>")
262
+ .description("Run npm scripts")
263
+ .allowUnknownOption()
264
+ .action(run)
265
+
266
+ // Subcommands
267
+ const token = program.command("token").description("Token management")
268
+ token.command("rotate").description("Rotate token").action(rotateToken)
269
+
270
+ const pool = program.command("pool").description("Pool revenue")
271
+ pool
272
+ .command("stats")
273
+ .description("Pool earnings")
274
+ .option("--json", "JSON output")
275
+ .action(poolStats)
276
+
277
+ const mcp = program.command("mcp").description("MCP server")
278
+ mcp
279
+ .command("setup")
280
+ .description("Configure MCP server")
281
+ .option("--project", "Project-level config")
282
+ .action(mcpSetup)
283
+ mcp
284
+ .command("remove")
285
+ .description("Remove MCP server")
286
+ .option("--project", "Project-level only")
287
+ .action(mcpRemove)
288
+ mcp
289
+ .command("status")
290
+ .description("MCP server status")
291
+ .option("--verbose", "Show diagnostics")
292
+ .action(mcpStatus)
293
+
294
+ const skills = program.command("skills").description("Agent Skills")
295
+ skills
296
+ .command("validate")
297
+ .description("Validate skills files")
298
+ .option("--json", "JSON output")
299
+ .action(skillsValidate)
300
+ skills
301
+ .command("install [package]")
302
+ .description("Install skills")
303
+ .option("--json", "JSON output")
304
+ .action(skillsInstall)
305
+ skills
306
+ .command("list")
307
+ .description("List available skills")
308
+ .option("--json", "JSON output")
309
+ .action(skillsList)
310
+ skills
311
+ .command("clean")
312
+ .description("Remove installed skills")
313
+ .option("--json", "JSON output")
314
+ .action(skillsClean)
315
+
316
+ const marketplace = program.command("marketplace").description("Marketplace")
317
+ marketplace
318
+ .command("compare <input>")
319
+ .description("Find comparable packages")
320
+ .option("--json", "JSON output")
321
+ .option("--category <category>", "Filter by category")
322
+ .option("--limit <n>", "Max results")
323
+ .action(marketplaceCompare)
324
+ marketplace
325
+ .command("earnings")
326
+ .description("Revenue summary")
327
+ .option("--json", "JSON output")
328
+ .action(marketplaceEarnings)
329
+
330
+ program.parse()
331
+
332
+ // ─── Helper ────────────────────────────────────────────────────────
333
+
334
+ function runBinary(binaryPath) {
335
+ try {
336
+ execFileSync(binaryPath, process.argv.slice(2), {
337
+ stdio: "inherit",
338
+ env: process.env,
339
+ })
340
+ process.exit(0)
341
+ } catch (err) {
342
+ if (err.status != null) {
343
+ process.exit(err.status)
344
+ }
345
+ // Binary failed to execute — fall through to JS CLI
346
+ }
347
+ }
@@ -82,8 +82,9 @@ export async function npmrc(options) {
82
82
  : `${registryUrl}/api/registry`
83
83
  const registryHost = fullRegistryUrl.replace(/^https?:/, "")
84
84
 
85
- // Determine proxy vs scoped mode
86
- let useScoped = !!options?.scoped
85
+ // Default: scoped (only @lpm.dev packages through lpm.dev).
86
+ // --proxy: route all npm traffic through lpm.dev (Pro/Org feature).
87
+ let useScoped = !options?.proxy
87
88
 
88
89
  // Read existing .npmrc and check for custom default registry
89
90
  let npmrcContent = ""
@@ -75,8 +75,9 @@ export async function setup(options) {
75
75
  : `${registryUrl}/api/registry`
76
76
  const registryHost = fullRegistryUrl.replace(/^https?:/, "")
77
77
 
78
- // Determine proxy vs scoped mode
79
- let useScoped = !!options?.scoped
78
+ // Default: scoped (only @lpm.dev packages through lpm.dev).
79
+ // --proxy: route all npm traffic through lpm.dev (Pro/Org feature).
80
+ let useScoped = !options?.proxy
80
81
 
81
82
  // ── OIDC mode: exchange CI token for a real short-lived install token ──
82
83
  if (options?.oidc) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lpm-registry/cli",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "CLI for Licensed Package Manager",
5
5
  "author": "LPM <hello@lpm.dev> (https://lpm.dev)",
6
6
  "repository": {
@@ -61,11 +61,11 @@
61
61
  "xcode": "^3.0.1"
62
62
  },
63
63
  "optionalDependencies": {
64
- "@lpm-registry/cli-darwin-arm64": "0.7.0",
65
- "@lpm-registry/cli-darwin-x64": "0.7.0",
66
- "@lpm-registry/cli-linux-x64": "0.7.0",
67
- "@lpm-registry/cli-linux-arm64": "0.7.0",
68
- "@lpm-registry/cli-win32-x64": "0.7.0",
64
+ "@lpm-registry/cli-darwin-arm64": "0.8.0",
65
+ "@lpm-registry/cli-darwin-x64": "0.8.0",
66
+ "@lpm-registry/cli-linux-x64": "0.8.0",
67
+ "@lpm-registry/cli-linux-arm64": "0.8.0",
68
+ "@lpm-registry/cli-win32-x64": "0.8.0",
69
69
  "keytar": "^7.9.0"
70
70
  },
71
71
  "type": "module",