@lpm-registry/cli 0.5.0 → 0.6.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 +16 -0
- package/bin/lpm.js +157 -213
- package/index.d.ts +2 -2
- package/lib/commands/quality.js +3 -3
- package/lib/quality/checks.js +37 -37
- package/lib/quality/display.js +4 -4
- package/lib/quality/score.js +5 -5
- package/lib/quality/swift-checks.js +18 -18
- package/package.json +6 -1
- package/scripts/install-binary.js +178 -37
package/lib/quality/checks.js
CHANGED
|
@@ -18,7 +18,7 @@ const hasReadme = {
|
|
|
18
18
|
id: "has-readme",
|
|
19
19
|
category: "documentation",
|
|
20
20
|
label: "Has README",
|
|
21
|
-
|
|
21
|
+
max_points: 8,
|
|
22
22
|
run: ({ readme }) => ({
|
|
23
23
|
passed: !!readme && readme.length > 100,
|
|
24
24
|
detail: readme
|
|
@@ -31,7 +31,7 @@ const readmeHasInstall = {
|
|
|
31
31
|
id: "readme-install",
|
|
32
32
|
category: "documentation",
|
|
33
33
|
label: "README has install section",
|
|
34
|
-
|
|
34
|
+
max_points: 3,
|
|
35
35
|
run: ({ readme }) => {
|
|
36
36
|
if (!readme) return { passed: false, detail: "No README" }
|
|
37
37
|
const lower = readme.toLowerCase()
|
|
@@ -55,7 +55,7 @@ const readmeHasUsage = {
|
|
|
55
55
|
id: "readme-usage",
|
|
56
56
|
category: "documentation",
|
|
57
57
|
label: "README has usage examples",
|
|
58
|
-
|
|
58
|
+
max_points: 3,
|
|
59
59
|
run: ({ readme }) => {
|
|
60
60
|
if (!readme) return { passed: false, detail: "No README" }
|
|
61
61
|
const lower = readme.toLowerCase()
|
|
@@ -77,7 +77,7 @@ const readmeHasApi = {
|
|
|
77
77
|
id: "readme-api",
|
|
78
78
|
category: "documentation",
|
|
79
79
|
label: "README has API docs",
|
|
80
|
-
|
|
80
|
+
max_points: 2,
|
|
81
81
|
run: ({ readme }) => {
|
|
82
82
|
if (!readme) return { passed: false, detail: "No README" }
|
|
83
83
|
const lower = readme.toLowerCase()
|
|
@@ -100,7 +100,7 @@ const hasChangelog = {
|
|
|
100
100
|
id: "has-changelog",
|
|
101
101
|
category: "documentation",
|
|
102
102
|
label: "Has CHANGELOG",
|
|
103
|
-
|
|
103
|
+
max_points: 3,
|
|
104
104
|
run: ({ files }) => {
|
|
105
105
|
const changelogFiles = files.filter(f => {
|
|
106
106
|
const name = (f.path || f).toLowerCase()
|
|
@@ -120,7 +120,7 @@ const hasLicense = {
|
|
|
120
120
|
id: "has-license",
|
|
121
121
|
category: "documentation",
|
|
122
122
|
label: "Has LICENSE file",
|
|
123
|
-
|
|
123
|
+
max_points: 3,
|
|
124
124
|
run: ({ files, packageJson }) => {
|
|
125
125
|
const licenseFiles = files.filter(f => {
|
|
126
126
|
const name = (f.path || f).toLowerCase()
|
|
@@ -146,7 +146,7 @@ const hasTypes = {
|
|
|
146
146
|
id: "has-types",
|
|
147
147
|
category: "code",
|
|
148
148
|
label: "Has TypeScript types",
|
|
149
|
-
|
|
149
|
+
max_points: 8,
|
|
150
150
|
run: ({ packageJson, files }) => {
|
|
151
151
|
const hasTypesField = !!(packageJson.types || packageJson.typings)
|
|
152
152
|
const hasDtsFiles = files.some(f => {
|
|
@@ -169,7 +169,7 @@ const intellisenseCoverage = {
|
|
|
169
169
|
id: "intellisense-coverage",
|
|
170
170
|
category: "code",
|
|
171
171
|
label: "Intellisense coverage",
|
|
172
|
-
|
|
172
|
+
max_points: 4,
|
|
173
173
|
run: ({ packageJson, files }) => {
|
|
174
174
|
// Full points if .d.ts files exist (complete intellisense)
|
|
175
175
|
const hasTypesField = !!(packageJson.types || packageJson.typings)
|
|
@@ -188,7 +188,7 @@ const intellisenseCoverage = {
|
|
|
188
188
|
return {
|
|
189
189
|
passed: false,
|
|
190
190
|
detail: "No .d.ts files or JSDoc detected for intellisense",
|
|
191
|
-
|
|
191
|
+
server_only: true,
|
|
192
192
|
}
|
|
193
193
|
},
|
|
194
194
|
}
|
|
@@ -197,7 +197,7 @@ const hasEsm = {
|
|
|
197
197
|
id: "esm-exports",
|
|
198
198
|
category: "code",
|
|
199
199
|
label: "ESM exports",
|
|
200
|
-
|
|
200
|
+
max_points: 3,
|
|
201
201
|
run: ({ packageJson }) => {
|
|
202
202
|
const isModule = packageJson.type === "module"
|
|
203
203
|
const hasModuleField = !!packageJson.module
|
|
@@ -220,7 +220,7 @@ const treeShakable = {
|
|
|
220
220
|
id: "tree-shakable",
|
|
221
221
|
category: "code",
|
|
222
222
|
label: "Tree-shakable",
|
|
223
|
-
|
|
223
|
+
max_points: 3,
|
|
224
224
|
run: ({ packageJson }) => {
|
|
225
225
|
const hasSideEffects = packageJson.sideEffects === false
|
|
226
226
|
const hasExportsField = !!packageJson.exports
|
|
@@ -242,14 +242,14 @@ const noEval = {
|
|
|
242
242
|
id: "no-eval",
|
|
243
243
|
category: "code",
|
|
244
244
|
label: "No eval/Function() patterns",
|
|
245
|
-
|
|
245
|
+
max_points: 3,
|
|
246
246
|
run: () => {
|
|
247
247
|
// This check runs server-side from tarball contents.
|
|
248
248
|
// CLI assumes pass; server overrides if eval detected.
|
|
249
249
|
return {
|
|
250
250
|
passed: true,
|
|
251
251
|
detail: "Full check runs server-side",
|
|
252
|
-
|
|
252
|
+
server_only: true,
|
|
253
253
|
}
|
|
254
254
|
},
|
|
255
255
|
}
|
|
@@ -258,7 +258,7 @@ const noLifecycleScripts = {
|
|
|
258
258
|
id: "no-lifecycle-scripts",
|
|
259
259
|
category: "health",
|
|
260
260
|
label: "No lifecycle scripts",
|
|
261
|
-
|
|
261
|
+
max_points: 2,
|
|
262
262
|
run: ({ packageJson }) => {
|
|
263
263
|
const lifecycleNames = [
|
|
264
264
|
"preinstall",
|
|
@@ -287,7 +287,7 @@ const hasEngines = {
|
|
|
287
287
|
id: "has-engines",
|
|
288
288
|
category: "code",
|
|
289
289
|
label: 'Has "engines" field',
|
|
290
|
-
|
|
290
|
+
max_points: 1,
|
|
291
291
|
run: ({ packageJson }) => {
|
|
292
292
|
const hasField = !!packageJson.engines?.node
|
|
293
293
|
return {
|
|
@@ -303,7 +303,7 @@ const hasExportsMap = {
|
|
|
303
303
|
id: "has-exports-map",
|
|
304
304
|
category: "code",
|
|
305
305
|
label: 'Has "exports" map',
|
|
306
|
-
|
|
306
|
+
max_points: 3,
|
|
307
307
|
run: ({ packageJson }) => {
|
|
308
308
|
const hasField = !!packageJson.exports
|
|
309
309
|
return {
|
|
@@ -319,7 +319,7 @@ const smallDeps = {
|
|
|
319
319
|
id: "small-deps",
|
|
320
320
|
category: "code",
|
|
321
321
|
label: "Small dependency footprint",
|
|
322
|
-
|
|
322
|
+
max_points: 3,
|
|
323
323
|
run: ({ packageJson }) => {
|
|
324
324
|
const deps = packageJson.dependencies
|
|
325
325
|
? Object.keys(packageJson.dependencies).length
|
|
@@ -341,7 +341,7 @@ const sourceMaps = {
|
|
|
341
341
|
id: "source-maps",
|
|
342
342
|
category: "code",
|
|
343
343
|
label: "Source maps included",
|
|
344
|
-
|
|
344
|
+
max_points: 1,
|
|
345
345
|
run: ({ files }) => {
|
|
346
346
|
const mapFiles = files.filter(f => {
|
|
347
347
|
const name = f.path || f
|
|
@@ -363,7 +363,7 @@ const hasTestFiles = {
|
|
|
363
363
|
id: "has-test-files",
|
|
364
364
|
category: "testing",
|
|
365
365
|
label: "Has test files",
|
|
366
|
-
|
|
366
|
+
max_points: 7,
|
|
367
367
|
run: ({ projectFiles, files }) => {
|
|
368
368
|
// Prefer projectFiles (local project scan) over files (tarball)
|
|
369
369
|
// so authors don't need to ship test files in the package
|
|
@@ -392,7 +392,7 @@ const hasTestScript = {
|
|
|
392
392
|
id: "has-test-script",
|
|
393
393
|
category: "testing",
|
|
394
394
|
label: "Has test script",
|
|
395
|
-
|
|
395
|
+
max_points: 4,
|
|
396
396
|
run: ({ packageJson }) => {
|
|
397
397
|
const testScript = packageJson.scripts?.test
|
|
398
398
|
const hasScript = !!testScript && !testScript.includes(DEFAULT_TEST_SCRIPT)
|
|
@@ -411,7 +411,7 @@ const hasDescription = {
|
|
|
411
411
|
id: "has-description",
|
|
412
412
|
category: "health",
|
|
413
413
|
label: "Has description",
|
|
414
|
-
|
|
414
|
+
max_points: 3,
|
|
415
415
|
run: ({ packageJson }) => {
|
|
416
416
|
const desc = packageJson.description
|
|
417
417
|
const passed = !!desc && desc.length > 10
|
|
@@ -428,7 +428,7 @@ const hasKeywords = {
|
|
|
428
428
|
id: "has-keywords",
|
|
429
429
|
category: "health",
|
|
430
430
|
label: "Has keywords",
|
|
431
|
-
|
|
431
|
+
max_points: 1,
|
|
432
432
|
run: ({ packageJson }) => {
|
|
433
433
|
const keywords = packageJson.keywords
|
|
434
434
|
const passed = Array.isArray(keywords) && keywords.length > 0
|
|
@@ -445,7 +445,7 @@ const hasRepository = {
|
|
|
445
445
|
id: "has-repository",
|
|
446
446
|
category: "health",
|
|
447
447
|
label: "Has repository URL",
|
|
448
|
-
|
|
448
|
+
max_points: 2,
|
|
449
449
|
run: ({ packageJson }) => {
|
|
450
450
|
const repo = packageJson.repository
|
|
451
451
|
const hasRepo = !!(
|
|
@@ -465,7 +465,7 @@ const hasHomepage = {
|
|
|
465
465
|
id: "has-homepage",
|
|
466
466
|
category: "health",
|
|
467
467
|
label: "Has homepage",
|
|
468
|
-
|
|
468
|
+
max_points: 1,
|
|
469
469
|
run: ({ packageJson }) => {
|
|
470
470
|
const passed = !!packageJson.homepage
|
|
471
471
|
return {
|
|
@@ -481,7 +481,7 @@ const reasonableSize = {
|
|
|
481
481
|
id: "reasonable-size",
|
|
482
482
|
category: "health",
|
|
483
483
|
label: "Reasonable bundle size",
|
|
484
|
-
|
|
484
|
+
max_points: 3,
|
|
485
485
|
run: ({ unpackedSize }) => {
|
|
486
486
|
if (!unpackedSize)
|
|
487
487
|
return { passed: true, points: 3, detail: "Size unknown" }
|
|
@@ -506,14 +506,14 @@ const noVulnerabilities = {
|
|
|
506
506
|
id: "no-vulnerabilities",
|
|
507
507
|
category: "health",
|
|
508
508
|
label: "No known vulnerabilities",
|
|
509
|
-
|
|
509
|
+
max_points: 5,
|
|
510
510
|
run: () => {
|
|
511
511
|
// This check runs server-side with OSV scan results.
|
|
512
512
|
// CLI assumes pass; server overrides with actual results.
|
|
513
513
|
return {
|
|
514
514
|
passed: true,
|
|
515
515
|
detail: "Full check runs server-side",
|
|
516
|
-
|
|
516
|
+
server_only: true,
|
|
517
517
|
}
|
|
518
518
|
},
|
|
519
519
|
}
|
|
@@ -522,14 +522,14 @@ const maintenanceHealth = {
|
|
|
522
522
|
id: "maintenance-health",
|
|
523
523
|
category: "health",
|
|
524
524
|
label: "Active maintenance",
|
|
525
|
-
|
|
525
|
+
max_points: 4,
|
|
526
526
|
run: () => {
|
|
527
527
|
// Server-only: checks if last version was published within 90 days.
|
|
528
528
|
// CLI cannot know this — assumes pass.
|
|
529
529
|
return {
|
|
530
530
|
passed: true,
|
|
531
531
|
detail: "Full check runs server-side",
|
|
532
|
-
|
|
532
|
+
server_only: true,
|
|
533
533
|
}
|
|
534
534
|
},
|
|
535
535
|
}
|
|
@@ -538,7 +538,7 @@ const semverConsistency = {
|
|
|
538
538
|
id: "semver-consistency",
|
|
539
539
|
category: "health",
|
|
540
540
|
label: "SemVer consistency",
|
|
541
|
-
|
|
541
|
+
max_points: 4,
|
|
542
542
|
run: ({ packageJson }) => {
|
|
543
543
|
// CLI can check if the current version is valid semver
|
|
544
544
|
const version = packageJson.version
|
|
@@ -552,7 +552,7 @@ const semverConsistency = {
|
|
|
552
552
|
detail: isValid
|
|
553
553
|
? `Valid semver: ${version}`
|
|
554
554
|
: `Invalid semver format: ${version}`,
|
|
555
|
-
|
|
555
|
+
server_only: !isValid ? undefined : true,
|
|
556
556
|
}
|
|
557
557
|
},
|
|
558
558
|
}
|
|
@@ -561,14 +561,14 @@ const authorVerified = {
|
|
|
561
561
|
id: "author-verified",
|
|
562
562
|
category: "health",
|
|
563
563
|
label: "Verified author",
|
|
564
|
-
|
|
564
|
+
max_points: 3,
|
|
565
565
|
run: () => {
|
|
566
566
|
// Server-only: checks if the author has linked social accounts.
|
|
567
567
|
// CLI cannot know this — assumes pass.
|
|
568
568
|
return {
|
|
569
569
|
passed: true,
|
|
570
570
|
detail: "Full check runs server-side",
|
|
571
|
-
|
|
571
|
+
server_only: true,
|
|
572
572
|
}
|
|
573
573
|
},
|
|
574
574
|
}
|
|
@@ -579,14 +579,14 @@ const hasSkills = {
|
|
|
579
579
|
id: "has-skills",
|
|
580
580
|
category: "health",
|
|
581
581
|
label: "Has Agent Skills",
|
|
582
|
-
|
|
582
|
+
max_points: 7,
|
|
583
583
|
run: () => {
|
|
584
584
|
// Server-only: checks if package has approved skills.
|
|
585
585
|
// CLI cannot determine this — assumes fail.
|
|
586
586
|
return {
|
|
587
587
|
passed: false,
|
|
588
588
|
detail: "Full check runs server-side",
|
|
589
|
-
|
|
589
|
+
server_only: true,
|
|
590
590
|
}
|
|
591
591
|
},
|
|
592
592
|
}
|
|
@@ -595,14 +595,14 @@ const skillsComprehensive = {
|
|
|
595
595
|
id: "skills-comprehensive",
|
|
596
596
|
category: "health",
|
|
597
597
|
label: "Comprehensive Agent Skills",
|
|
598
|
-
|
|
598
|
+
max_points: 3,
|
|
599
599
|
run: () => {
|
|
600
600
|
// Server-only: checks if package has 3+ approved skills.
|
|
601
601
|
// CLI cannot determine this — assumes fail.
|
|
602
602
|
return {
|
|
603
603
|
passed: false,
|
|
604
604
|
detail: "Full check runs server-side",
|
|
605
|
-
|
|
605
|
+
server_only: true,
|
|
606
606
|
}
|
|
607
607
|
},
|
|
608
608
|
}
|
package/lib/quality/display.js
CHANGED
|
@@ -44,13 +44,13 @@ export function displayQualityReport({ score, checks, meta, warnings }) {
|
|
|
44
44
|
const tierColor = TIER_COLORS[meta.tier] || chalk.white
|
|
45
45
|
const tierLabel = TIER_LABELS[meta.tier] || meta.tier
|
|
46
46
|
|
|
47
|
-
const hasServerOnly = checks.some(c => c.
|
|
47
|
+
const hasServerOnly = checks.some(c => c.server_only)
|
|
48
48
|
|
|
49
49
|
console.log("")
|
|
50
50
|
|
|
51
51
|
// Individual checks first
|
|
52
52
|
for (const check of checks) {
|
|
53
|
-
if (check.
|
|
53
|
+
if (check.server_only) {
|
|
54
54
|
// Show server-only checks dimmed with ~ icon
|
|
55
55
|
const icon = chalk.dim("~")
|
|
56
56
|
const label = chalk.dim(check.label)
|
|
@@ -65,13 +65,13 @@ export function displayQualityReport({ score, checks, meta, warnings }) {
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
// Tips for failed checks (exclude server-only)
|
|
68
|
-
const failed = checks.filter(c => !c.passed && !c.
|
|
68
|
+
const failed = checks.filter(c => !c.passed && !c.server_only)
|
|
69
69
|
if (failed.length > 0) {
|
|
70
70
|
console.log("")
|
|
71
71
|
const tips = failed.slice(0, 3)
|
|
72
72
|
for (const check of tips) {
|
|
73
73
|
console.log(
|
|
74
|
-
chalk.dim(` Tip: ${getTip(check.id)} (+${check.
|
|
74
|
+
chalk.dim(` Tip: ${getTip(check.id)} (+${check.max_points} points)`),
|
|
75
75
|
)
|
|
76
76
|
}
|
|
77
77
|
}
|
package/lib/quality/score.js
CHANGED
|
@@ -72,7 +72,7 @@ export function runQualityChecks({
|
|
|
72
72
|
const points = result.passed
|
|
73
73
|
? result.points !== undefined
|
|
74
74
|
? result.points
|
|
75
|
-
: check.
|
|
75
|
+
: check.max_points
|
|
76
76
|
: 0
|
|
77
77
|
return {
|
|
78
78
|
id: check.id,
|
|
@@ -80,20 +80,20 @@ export function runQualityChecks({
|
|
|
80
80
|
label: check.label,
|
|
81
81
|
passed: result.passed,
|
|
82
82
|
points,
|
|
83
|
-
|
|
83
|
+
max_points: check.max_points,
|
|
84
84
|
detail: result.detail,
|
|
85
|
-
...(result.
|
|
85
|
+
...(result.server_only && { server_only: true }),
|
|
86
86
|
}
|
|
87
87
|
})
|
|
88
88
|
|
|
89
|
-
// Compute category scores dynamically from actual check
|
|
89
|
+
// Compute category scores dynamically from actual check max_points
|
|
90
90
|
const categories = {}
|
|
91
91
|
for (const result of results) {
|
|
92
92
|
if (!categories[result.category]) {
|
|
93
93
|
categories[result.category] = { score: 0, max: 0 }
|
|
94
94
|
}
|
|
95
95
|
categories[result.category].score += result.points
|
|
96
|
-
categories[result.category].max += result.
|
|
96
|
+
categories[result.category].max += result.max_points
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
const totalScore = Object.values(categories).reduce(
|
|
@@ -18,7 +18,7 @@ export const swiftReadmeHasInstall = {
|
|
|
18
18
|
id: "readme-install",
|
|
19
19
|
category: "documentation",
|
|
20
20
|
label: "README has install section",
|
|
21
|
-
|
|
21
|
+
max_points: 3,
|
|
22
22
|
run: ({ readme }) => {
|
|
23
23
|
if (!readme) return { passed: false, detail: "No README" }
|
|
24
24
|
const lower = readme.toLowerCase()
|
|
@@ -47,7 +47,7 @@ export const hasPlatformDeclarations = {
|
|
|
47
47
|
id: "has-platforms",
|
|
48
48
|
category: "code",
|
|
49
49
|
label: "Has platform declarations",
|
|
50
|
-
|
|
50
|
+
max_points: 6,
|
|
51
51
|
run: ({ swiftManifest }) => {
|
|
52
52
|
if (!swiftManifest)
|
|
53
53
|
return { passed: false, detail: "No Swift manifest data" }
|
|
@@ -71,7 +71,7 @@ export const recentToolsVersion = {
|
|
|
71
71
|
id: "recent-tools-version",
|
|
72
72
|
category: "code",
|
|
73
73
|
label: "Uses recent swift-tools-version",
|
|
74
|
-
|
|
74
|
+
max_points: 5,
|
|
75
75
|
run: ({ swiftManifest }) => {
|
|
76
76
|
if (!swiftManifest)
|
|
77
77
|
return { passed: false, detail: "No Swift manifest data" }
|
|
@@ -101,7 +101,7 @@ export const supportsMultiplePlatforms = {
|
|
|
101
101
|
id: "multi-platform",
|
|
102
102
|
category: "code",
|
|
103
103
|
label: "Supports multiple platforms",
|
|
104
|
-
|
|
104
|
+
max_points: 4,
|
|
105
105
|
run: ({ swiftManifest }) => {
|
|
106
106
|
if (!swiftManifest)
|
|
107
107
|
return { passed: false, detail: "No Swift manifest data" }
|
|
@@ -127,7 +127,7 @@ export const hasPublicAPI = {
|
|
|
127
127
|
id: "has-public-api",
|
|
128
128
|
category: "code",
|
|
129
129
|
label: "Has public API surface",
|
|
130
|
-
|
|
130
|
+
max_points: 5,
|
|
131
131
|
run: ({ files }) => {
|
|
132
132
|
// Check if any .swift source files exist (exclude manifest and tests)
|
|
133
133
|
const swiftFiles = files.filter(f => {
|
|
@@ -146,7 +146,7 @@ export const hasPublicAPI = {
|
|
|
146
146
|
return {
|
|
147
147
|
passed: true,
|
|
148
148
|
detail: `${swiftFiles.length} Swift source file${swiftFiles.length !== 1 ? "s" : ""} found`,
|
|
149
|
-
|
|
149
|
+
server_only: true,
|
|
150
150
|
}
|
|
151
151
|
},
|
|
152
152
|
}
|
|
@@ -155,14 +155,14 @@ export const hasDocComments = {
|
|
|
155
155
|
id: "has-doc-comments",
|
|
156
156
|
category: "code",
|
|
157
157
|
label: "Has DocC documentation",
|
|
158
|
-
|
|
158
|
+
max_points: 7,
|
|
159
159
|
run: () => {
|
|
160
160
|
// Full check runs server-side from tarball contents.
|
|
161
161
|
// CLI assumes pass; server overrides if no documentation found.
|
|
162
162
|
return {
|
|
163
163
|
passed: true,
|
|
164
164
|
detail: "Full check runs server-side",
|
|
165
|
-
|
|
165
|
+
server_only: true,
|
|
166
166
|
}
|
|
167
167
|
},
|
|
168
168
|
}
|
|
@@ -171,7 +171,7 @@ export const smallDepsSwift = {
|
|
|
171
171
|
id: "small-deps",
|
|
172
172
|
category: "code",
|
|
173
173
|
label: "Small dependency footprint",
|
|
174
|
-
|
|
174
|
+
max_points: 4,
|
|
175
175
|
run: ({ swiftManifest }) => {
|
|
176
176
|
if (!swiftManifest)
|
|
177
177
|
return { passed: true, points: 4, detail: "No manifest data" }
|
|
@@ -196,7 +196,7 @@ export const swiftHasTestTargets = {
|
|
|
196
196
|
id: "has-test-files",
|
|
197
197
|
category: "testing",
|
|
198
198
|
label: "Has test targets",
|
|
199
|
-
|
|
199
|
+
max_points: 7,
|
|
200
200
|
run: ({ swiftManifest, files }) => {
|
|
201
201
|
// Check Swift manifest for test targets
|
|
202
202
|
const testTargets = (swiftManifest?.targets || []).filter(
|
|
@@ -227,7 +227,7 @@ export const swiftHasTestScript = {
|
|
|
227
227
|
id: "has-test-script",
|
|
228
228
|
category: "testing",
|
|
229
229
|
label: "Has test configuration",
|
|
230
|
-
|
|
230
|
+
max_points: 4,
|
|
231
231
|
run: ({ swiftManifest }) => {
|
|
232
232
|
// For Swift, having test targets in the manifest is the equivalent
|
|
233
233
|
const testTargets = (swiftManifest?.targets || []).filter(
|
|
@@ -249,7 +249,7 @@ export const xcfHasValidPlist = {
|
|
|
249
249
|
id: "xcf-valid-plist",
|
|
250
250
|
category: "code",
|
|
251
251
|
label: "Valid Info.plist",
|
|
252
|
-
|
|
252
|
+
max_points: 10,
|
|
253
253
|
run: ({ xcframeworkMeta }) => {
|
|
254
254
|
if (!xcframeworkMeta)
|
|
255
255
|
return { passed: false, detail: "No XCFramework metadata" }
|
|
@@ -270,7 +270,7 @@ export const xcfMultipleSlices = {
|
|
|
270
270
|
id: "xcf-multi-slice",
|
|
271
271
|
category: "code",
|
|
272
272
|
label: "Supports multiple platform slices",
|
|
273
|
-
|
|
273
|
+
max_points: 15,
|
|
274
274
|
run: ({ xcframeworkMeta }) => {
|
|
275
275
|
if (!xcframeworkMeta)
|
|
276
276
|
return { passed: false, detail: "No XCFramework metadata" }
|
|
@@ -301,7 +301,7 @@ export const xcfReasonableSize = {
|
|
|
301
301
|
id: "xcf-size",
|
|
302
302
|
category: "code",
|
|
303
303
|
label: "Reasonable framework size",
|
|
304
|
-
|
|
304
|
+
max_points: 5,
|
|
305
305
|
run: ({ unpackedSize }) => {
|
|
306
306
|
if (!unpackedSize)
|
|
307
307
|
return { passed: true, points: 5, detail: "No size data" }
|
|
@@ -324,7 +324,7 @@ export const xcfHasArchitectures = {
|
|
|
324
324
|
id: "xcf-architectures",
|
|
325
325
|
category: "code",
|
|
326
326
|
label: "Supports arm64 architecture",
|
|
327
|
-
|
|
327
|
+
max_points: 10,
|
|
328
328
|
run: ({ xcframeworkMeta }) => {
|
|
329
329
|
if (!xcframeworkMeta)
|
|
330
330
|
return { passed: false, detail: "No XCFramework metadata" }
|
|
@@ -347,7 +347,7 @@ export const xcfHealthReasonableSize = {
|
|
|
347
347
|
id: "reasonable-size",
|
|
348
348
|
category: "health",
|
|
349
349
|
label: "Reasonable framework size",
|
|
350
|
-
|
|
350
|
+
max_points: 3,
|
|
351
351
|
run: ({ unpackedSize }) => {
|
|
352
352
|
if (!unpackedSize)
|
|
353
353
|
return { passed: true, points: 3, detail: "Size unknown" }
|
|
@@ -439,9 +439,9 @@ export const xcframeworkChecks = [
|
|
|
439
439
|
hasHomepage,
|
|
440
440
|
xcfHealthReasonableSize,
|
|
441
441
|
noVulnerabilities,
|
|
442
|
-
{ ...maintenanceHealth,
|
|
442
|
+
{ ...maintenanceHealth, max_points: 5 },
|
|
443
443
|
semverConsistency,
|
|
444
|
-
{ ...authorVerified,
|
|
444
|
+
{ ...authorVerified, max_points: 4 },
|
|
445
445
|
hasSkills,
|
|
446
446
|
skillsComprehensive,
|
|
447
447
|
]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lpm-registry/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "CLI for Licensed Package Manager",
|
|
5
5
|
"author": "LPM <hello@lpm.dev> (https://lpm.dev)",
|
|
6
6
|
"repository": {
|
|
@@ -61,6 +61,11 @@
|
|
|
61
61
|
"xcode": "^3.0.1"
|
|
62
62
|
},
|
|
63
63
|
"optionalDependencies": {
|
|
64
|
+
"@lpm-registry/cli-darwin-arm64": "0.6.0",
|
|
65
|
+
"@lpm-registry/cli-darwin-x64": "0.6.0",
|
|
66
|
+
"@lpm-registry/cli-linux-x64": "0.6.0",
|
|
67
|
+
"@lpm-registry/cli-linux-arm64": "0.6.0",
|
|
68
|
+
"@lpm-registry/cli-win32-x64": "0.6.0",
|
|
64
69
|
"keytar": "^7.9.0"
|
|
65
70
|
},
|
|
66
71
|
"type": "module",
|