@lpm-registry/cli 0.6.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 +18 -0
- package/bin/lpm-bin +347 -0
- package/bin/lpm.js.bak +347 -0
- package/lib/commands/npmrc.js +3 -2
- package/lib/commands/setup.js +3 -2
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
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
|
+
|
|
15
|
+
## [0.7.0] - 2026-04-01
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- **Rust binary v0.7.0** — Cold install 15.8s → 2.1s (7.5x faster). Abbreviated npm packuments, deep server-side transitive resolution, edge npm metadata proxy, connection pool sharing, hash-during-download.
|
|
20
|
+
- **Unpublished package handling** — On tarball 404, metadata cache is invalidated and lockfile cleared so the next install re-resolves with fresh metadata.
|
|
21
|
+
- Version bump to stay in sync with Rust binary releases.
|
|
22
|
+
|
|
5
23
|
## [0.6.0] - 2026-04-01
|
|
6
24
|
|
|
7
25
|
### Added
|
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
|
+
}
|
package/lib/commands/npmrc.js
CHANGED
|
@@ -82,8 +82,9 @@ export async function npmrc(options) {
|
|
|
82
82
|
: `${registryUrl}/api/registry`
|
|
83
83
|
const registryHost = fullRegistryUrl.replace(/^https?:/, "")
|
|
84
84
|
|
|
85
|
-
//
|
|
86
|
-
|
|
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 = ""
|
package/lib/commands/setup.js
CHANGED
|
@@ -75,8 +75,9 @@ export async function setup(options) {
|
|
|
75
75
|
: `${registryUrl}/api/registry`
|
|
76
76
|
const registryHost = fullRegistryUrl.replace(/^https?:/, "")
|
|
77
77
|
|
|
78
|
-
//
|
|
79
|
-
|
|
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.
|
|
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.
|
|
65
|
-
"@lpm-registry/cli-darwin-x64": "0.
|
|
66
|
-
"@lpm-registry/cli-linux-x64": "0.
|
|
67
|
-
"@lpm-registry/cli-linux-arm64": "0.
|
|
68
|
-
"@lpm-registry/cli-win32-x64": "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",
|