@lpm-registry/cli 0.2.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 +36 -0
- package/LICENSE +15 -0
- package/README.md +406 -0
- package/bin/lpm.js +334 -0
- package/index.d.ts +131 -0
- package/index.js +31 -0
- package/lib/api.js +324 -0
- package/lib/commands/add.js +1217 -0
- package/lib/commands/audit.js +283 -0
- package/lib/commands/cache.js +209 -0
- package/lib/commands/check-name.js +112 -0
- package/lib/commands/config.js +174 -0
- package/lib/commands/doctor.js +142 -0
- package/lib/commands/info.js +215 -0
- package/lib/commands/init.js +146 -0
- package/lib/commands/install.js +217 -0
- package/lib/commands/login.js +547 -0
- package/lib/commands/logout.js +94 -0
- package/lib/commands/marketplace-compare.js +164 -0
- package/lib/commands/marketplace-earnings.js +89 -0
- package/lib/commands/mcp-setup.js +363 -0
- package/lib/commands/open.js +82 -0
- package/lib/commands/outdated.js +291 -0
- package/lib/commands/pool-stats.js +100 -0
- package/lib/commands/publish.js +707 -0
- package/lib/commands/quality.js +211 -0
- package/lib/commands/remove.js +82 -0
- package/lib/commands/run.js +14 -0
- package/lib/commands/search.js +143 -0
- package/lib/commands/setup.js +92 -0
- package/lib/commands/skills.js +863 -0
- package/lib/commands/token-rotate.js +25 -0
- package/lib/commands/whoami.js +129 -0
- package/lib/config.js +240 -0
- package/lib/constants.js +190 -0
- package/lib/ecosystem.js +501 -0
- package/lib/editors.js +215 -0
- package/lib/import-rewriter.js +364 -0
- package/lib/install-targets/mcp-server.js +245 -0
- package/lib/install-targets/vscode-extension.js +178 -0
- package/lib/install-targets.js +82 -0
- package/lib/integrity.js +179 -0
- package/lib/lpm-config-prompts.js +102 -0
- package/lib/lpm-config.js +408 -0
- package/lib/project-utils.js +152 -0
- package/lib/quality/checks.js +654 -0
- package/lib/quality/display.js +139 -0
- package/lib/quality/score.js +115 -0
- package/lib/quality/swift-checks.js +447 -0
- package/lib/safe-path.js +180 -0
- package/lib/secure-store.js +288 -0
- package/lib/swift-project.js +637 -0
- package/lib/ui.js +40 -0
- package/package.json +74 -0
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { spawn } from "node:child_process"
|
|
2
|
+
import fs from "node:fs"
|
|
3
|
+
import path from "node:path"
|
|
4
|
+
import { getRegistryUrl, getToken } from "../config.js"
|
|
5
|
+
import { createSpinner, log, printHeader } from "../ui.js"
|
|
6
|
+
import { skillsInstall } from "./skills.js"
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Check if a package name is an LPM package
|
|
10
|
+
* LPM packages use the @lpm.dev scope
|
|
11
|
+
*/
|
|
12
|
+
function isLpmPackage(pkgName) {
|
|
13
|
+
return pkgName.startsWith("@lpm.dev/")
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function install(packages, options) {
|
|
17
|
+
const isJson = options?.json
|
|
18
|
+
|
|
19
|
+
if (!isJson) printHeader()
|
|
20
|
+
|
|
21
|
+
const token = await getToken()
|
|
22
|
+
if (!token) {
|
|
23
|
+
if (isJson) {
|
|
24
|
+
process.stdout.write(
|
|
25
|
+
`${JSON.stringify(
|
|
26
|
+
{
|
|
27
|
+
success: false,
|
|
28
|
+
packages: [],
|
|
29
|
+
npmOutput: "",
|
|
30
|
+
warnings: [],
|
|
31
|
+
errors: [
|
|
32
|
+
'You must be logged in to install packages. Run "lpm login" first.',
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
null,
|
|
36
|
+
2,
|
|
37
|
+
)}\n`,
|
|
38
|
+
)
|
|
39
|
+
} else {
|
|
40
|
+
log.error(
|
|
41
|
+
'You must be logged in to install packages. Run "lpm login" first.',
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
process.exit(1)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!packages || packages.length === 0) {
|
|
48
|
+
// No packages specified - read from package.json
|
|
49
|
+
const packageJsonPath = path.resolve(process.cwd(), "package.json")
|
|
50
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
51
|
+
if (isJson) {
|
|
52
|
+
process.stdout.write(
|
|
53
|
+
`${JSON.stringify(
|
|
54
|
+
{
|
|
55
|
+
success: false,
|
|
56
|
+
packages: [],
|
|
57
|
+
npmOutput: "",
|
|
58
|
+
warnings: [],
|
|
59
|
+
errors: ["No packages specified and no package.json found."],
|
|
60
|
+
},
|
|
61
|
+
null,
|
|
62
|
+
2,
|
|
63
|
+
)}\n`,
|
|
64
|
+
)
|
|
65
|
+
} else {
|
|
66
|
+
log.error("No packages specified and no package.json found.")
|
|
67
|
+
}
|
|
68
|
+
process.exit(1)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"))
|
|
72
|
+
const allDeps = {
|
|
73
|
+
...pkg.dependencies,
|
|
74
|
+
...pkg.devDependencies,
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Filter to LPM packages only (@lpm.dev scope)
|
|
78
|
+
packages = Object.keys(allDeps).filter(isLpmPackage)
|
|
79
|
+
|
|
80
|
+
if (packages.length === 0) {
|
|
81
|
+
if (isJson) {
|
|
82
|
+
process.stdout.write(
|
|
83
|
+
`${JSON.stringify(
|
|
84
|
+
{
|
|
85
|
+
success: true,
|
|
86
|
+
packages: [],
|
|
87
|
+
npmOutput: "",
|
|
88
|
+
warnings: ["No LPM packages (@lpm.dev/*) found in package.json."],
|
|
89
|
+
errors: [],
|
|
90
|
+
},
|
|
91
|
+
null,
|
|
92
|
+
2,
|
|
93
|
+
)}\n`,
|
|
94
|
+
)
|
|
95
|
+
} else {
|
|
96
|
+
log.info("No LPM packages (@lpm.dev/*) found in package.json.")
|
|
97
|
+
}
|
|
98
|
+
process.exit(0)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (!isJson) {
|
|
102
|
+
log.info(
|
|
103
|
+
`Installing ${packages.length} LPM packages from package.json...`,
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
let spinner
|
|
109
|
+
if (!isJson) {
|
|
110
|
+
spinner = createSpinner(
|
|
111
|
+
`Preparing to install ${packages.join(", ")}...`,
|
|
112
|
+
).start()
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const baseRegistryUrl = getRegistryUrl()
|
|
116
|
+
// Ensure we have the full registry path for npm
|
|
117
|
+
const registryUrl = baseRegistryUrl.endsWith("/api/registry")
|
|
118
|
+
? baseRegistryUrl
|
|
119
|
+
: `${baseRegistryUrl}/api/registry`
|
|
120
|
+
// Remove protocol for auth token config (e.g. https://registry.com/ -> //registry.com/)
|
|
121
|
+
const registryHost = registryUrl.replace(/^https?:/, "")
|
|
122
|
+
|
|
123
|
+
// Create temporary .npmrc content
|
|
124
|
+
// Simple configuration - all LPM packages use @lpm.dev scope
|
|
125
|
+
const npmrcContent = `${registryHost}/:_authToken=${token}
|
|
126
|
+
@lpm.dev:registry=${registryUrl}
|
|
127
|
+
`
|
|
128
|
+
|
|
129
|
+
// Write to temp file
|
|
130
|
+
const tempNpmrcPath = path.resolve(process.cwd(), `.npmrc.lpm-${Date.now()}`)
|
|
131
|
+
fs.writeFileSync(tempNpmrcPath, npmrcContent)
|
|
132
|
+
|
|
133
|
+
if (!isJson) {
|
|
134
|
+
spinner.succeed("Configuration generated. Running npm install...")
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Run npm install
|
|
138
|
+
const npmArgs = ["install", ...packages, "--userconfig", tempNpmrcPath]
|
|
139
|
+
|
|
140
|
+
// In JSON mode, capture stdout/stderr instead of inheriting
|
|
141
|
+
const child = spawn("npm", npmArgs, {
|
|
142
|
+
stdio: isJson ? "pipe" : "inherit",
|
|
143
|
+
env: { ...process.env, LPM_TOKEN: token },
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
const cleanup = () => {
|
|
147
|
+
if (fs.existsSync(tempNpmrcPath)) {
|
|
148
|
+
fs.unlinkSync(tempNpmrcPath)
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const fetchSkills = options?.skills !== false
|
|
153
|
+
|
|
154
|
+
if (isJson) {
|
|
155
|
+
let stdout = ""
|
|
156
|
+
let stderr = ""
|
|
157
|
+
child.stdout.on("data", data => {
|
|
158
|
+
stdout += data.toString()
|
|
159
|
+
})
|
|
160
|
+
child.stderr.on("data", data => {
|
|
161
|
+
stderr += data.toString()
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
child.on("close", async code => {
|
|
165
|
+
cleanup()
|
|
166
|
+
const output = {
|
|
167
|
+
success: code === 0,
|
|
168
|
+
packages: packages.map(p => ({ name: p })),
|
|
169
|
+
npmOutput: (stdout + stderr).trim(),
|
|
170
|
+
warnings: [],
|
|
171
|
+
errors: code !== 0 ? [`npm install failed with code ${code}`] : [],
|
|
172
|
+
}
|
|
173
|
+
process.stdout.write(`${JSON.stringify(output, null, 2)}\n`)
|
|
174
|
+
if (code !== 0) process.exit(code)
|
|
175
|
+
if (fetchSkills) await skillsInstall(null, { json: true })
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
child.on("error", err => {
|
|
179
|
+
cleanup()
|
|
180
|
+
const output = {
|
|
181
|
+
success: false,
|
|
182
|
+
packages: packages.map(p => ({ name: p })),
|
|
183
|
+
npmOutput: "",
|
|
184
|
+
warnings: [],
|
|
185
|
+
errors: [`Failed to start npm: ${err.message}`],
|
|
186
|
+
}
|
|
187
|
+
process.stdout.write(`${JSON.stringify(output, null, 2)}\n`)
|
|
188
|
+
process.exit(1)
|
|
189
|
+
})
|
|
190
|
+
} else {
|
|
191
|
+
child.on("close", async code => {
|
|
192
|
+
cleanup()
|
|
193
|
+
if (code !== 0) {
|
|
194
|
+
log.error(`npm install failed with code ${code}`)
|
|
195
|
+
process.exit(code)
|
|
196
|
+
} else {
|
|
197
|
+
log.success("Packages installed successfully.")
|
|
198
|
+
if (fetchSkills) {
|
|
199
|
+
console.log("")
|
|
200
|
+
await skillsInstall(null)
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
child.on("error", err => {
|
|
206
|
+
log.error(`Failed to start npm: ${err.message}`)
|
|
207
|
+
cleanup()
|
|
208
|
+
process.exit(1)
|
|
209
|
+
})
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Handle interrupt to cleanup
|
|
213
|
+
process.on("SIGINT", () => {
|
|
214
|
+
cleanup()
|
|
215
|
+
process.exit()
|
|
216
|
+
})
|
|
217
|
+
}
|