@open-mercato/cli 0.6.6-develop.5654.1.ca21e35f26 → 0.6.6-develop.5675.1.d585628349
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/dist/agentic/shared/AGENTS.md.template +1 -1
- package/dist/agentic/shared/ai/skills/om-code-review/SKILL.md +9 -45
- package/dist/agentic/shared/ai/skills/om-code-review/references/review-checklist.md +1 -1
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/naming-conventions.md +4 -14
- package/dist/agentic/shared/ai/skills/om-troubleshooter/SKILL.md +10 -6
- package/dist/lib/module-install-args.js +9 -1
- package/dist/lib/module-install-args.js.map +2 -2
- package/dist/lib/module-install.js +22 -11
- package/dist/lib/module-install.js.map +2 -2
- package/dist/lib/module-package.js +2 -2
- package/dist/lib/module-package.js.map +2 -2
- package/dist/mercato.js +8 -8
- package/dist/mercato.js.map +2 -2
- package/package.json +5 -5
- package/src/lib/__tests__/module-install-args.test.ts +23 -0
- package/src/lib/__tests__/module-install.test.ts +66 -1
- package/src/lib/__tests__/module-package.test.ts +27 -0
- package/src/lib/module-install-args.ts +12 -1
- package/src/lib/module-install.ts +25 -9
- package/src/lib/module-package.ts +2 -2
- package/src/mercato.ts +8 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/cli",
|
|
3
|
-
"version": "0.6.6-develop.
|
|
3
|
+
"version": "0.6.6-develop.5675.1.d585628349",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -59,8 +59,8 @@
|
|
|
59
59
|
"@mikro-orm/decorators": "^7.1.4",
|
|
60
60
|
"@mikro-orm/migrations": "^7.1.4",
|
|
61
61
|
"@mikro-orm/postgresql": "^7.1.4",
|
|
62
|
-
"@open-mercato/queue": "0.6.6-develop.
|
|
63
|
-
"@open-mercato/shared": "0.6.6-develop.
|
|
62
|
+
"@open-mercato/queue": "0.6.6-develop.5675.1.d585628349",
|
|
63
|
+
"@open-mercato/shared": "0.6.6-develop.5675.1.d585628349",
|
|
64
64
|
"cross-spawn": "^7.0.6",
|
|
65
65
|
"pg": "8.21.0",
|
|
66
66
|
"semver": "^7.8.4",
|
|
@@ -70,10 +70,10 @@
|
|
|
70
70
|
"typescript": "^6.0.3"
|
|
71
71
|
},
|
|
72
72
|
"peerDependencies": {
|
|
73
|
-
"@open-mercato/shared": "0.6.6-develop.
|
|
73
|
+
"@open-mercato/shared": "0.6.6-develop.5675.1.d585628349"
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
|
-
"@open-mercato/shared": "0.6.6-develop.
|
|
76
|
+
"@open-mercato/shared": "0.6.6-develop.5675.1.d585628349",
|
|
77
77
|
"@types/jest": "^30.0.0",
|
|
78
78
|
"jest": "^30.4.2",
|
|
79
79
|
"ts-jest": "^29.4.11"
|
|
@@ -32,4 +32,27 @@ describe('parseModuleInstallArgs', () => {
|
|
|
32
32
|
'Unsupported option: --installed',
|
|
33
33
|
)
|
|
34
34
|
})
|
|
35
|
+
|
|
36
|
+
it('defaults allowThirdParty to false', () => {
|
|
37
|
+
expect(parseModuleInstallArgs(['@open-mercato/test-package'])).toMatchObject({
|
|
38
|
+
allowThirdParty: false,
|
|
39
|
+
})
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('accepts --allow-third-party as a boolean flag', () => {
|
|
43
|
+
expect(parseModuleInstallArgs(['@scope/pkg', '--allow-third-party'])).toMatchObject({
|
|
44
|
+
packageSpec: '@scope/pkg',
|
|
45
|
+
allowThirdParty: true,
|
|
46
|
+
})
|
|
47
|
+
expect(parseModuleInstallArgs(['--allow-third-party', '@scope/pkg'])).toMatchObject({
|
|
48
|
+
packageSpec: '@scope/pkg',
|
|
49
|
+
allowThirdParty: true,
|
|
50
|
+
})
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('rejects --allow-third-party values', () => {
|
|
54
|
+
expect(() => parseModuleInstallArgs(['@scope/pkg', '--allow-third-party=true'])).toThrow(
|
|
55
|
+
'--allow-third-party does not accept a value',
|
|
56
|
+
)
|
|
57
|
+
})
|
|
35
58
|
})
|
|
@@ -10,15 +10,17 @@ function buildPackageFixture(
|
|
|
10
10
|
options?: {
|
|
11
11
|
ejectable?: boolean
|
|
12
12
|
extraSourceFiles?: Array<{ relativePath: string; content: string }>
|
|
13
|
+
packageName?: string
|
|
13
14
|
},
|
|
14
15
|
): void {
|
|
15
16
|
const ejectable = options?.ejectable ?? false
|
|
17
|
+
const packageName = options?.packageName ?? '@open-mercato/test-package'
|
|
16
18
|
for (const base of ['src', 'dist']) {
|
|
17
19
|
fs.mkdirSync(path.join(packageRoot, base, 'modules', moduleId), { recursive: true })
|
|
18
20
|
}
|
|
19
21
|
fs.writeFileSync(
|
|
20
22
|
path.join(packageRoot, 'package.json'),
|
|
21
|
-
JSON.stringify({ name:
|
|
23
|
+
JSON.stringify({ name: packageName, version: '0.1.0' }),
|
|
22
24
|
)
|
|
23
25
|
fs.writeFileSync(
|
|
24
26
|
path.join(packageRoot, 'src', 'modules', moduleId, 'index.ts'),
|
|
@@ -236,3 +238,66 @@ describe('enableOfficialModule', () => {
|
|
|
236
238
|
).rejects.toThrow('Unsupported package spec suffix')
|
|
237
239
|
})
|
|
238
240
|
})
|
|
241
|
+
|
|
242
|
+
describe('third-party module packages', () => {
|
|
243
|
+
let tmpDir: string
|
|
244
|
+
|
|
245
|
+
beforeEach(() => {
|
|
246
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'module-install-3p-test-'))
|
|
247
|
+
})
|
|
248
|
+
|
|
249
|
+
afterEach(() => {
|
|
250
|
+
fs.rmSync(tmpDir, { recursive: true, force: true })
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
it('rejects adding a non-@open-mercato package without --allow-third-party', async () => {
|
|
254
|
+
const packageRoot = path.join(tmpDir, 'node_modules', '@fast-white-cat', 'integration-ksef-direct')
|
|
255
|
+
const appDir = path.join(tmpDir, 'app')
|
|
256
|
+
buildPackageFixture(packageRoot, 'ksef_direct', {
|
|
257
|
+
packageName: '@fast-white-cat/integration-ksef-direct',
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
const resolver = buildResolver(appDir, packageRoot, 'export const enabledModules = []\n')
|
|
261
|
+
|
|
262
|
+
await expect(
|
|
263
|
+
addOfficialModule(resolver, '@fast-white-cat/integration-ksef-direct@0.1.0', false),
|
|
264
|
+
).rejects.toThrow('Re-run with --allow-third-party')
|
|
265
|
+
})
|
|
266
|
+
|
|
267
|
+
it('rejects enabling a non-@open-mercato package without --allow-third-party', async () => {
|
|
268
|
+
const packageRoot = path.join(tmpDir, 'node_modules', '@fast-white-cat', 'integration-ksef-direct')
|
|
269
|
+
const appDir = path.join(tmpDir, 'app')
|
|
270
|
+
buildPackageFixture(packageRoot, 'ksef_direct', {
|
|
271
|
+
packageName: '@fast-white-cat/integration-ksef-direct',
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
const resolver = buildResolver(appDir, packageRoot, 'export const enabledModules = []\n')
|
|
275
|
+
|
|
276
|
+
await expect(
|
|
277
|
+
enableOfficialModule(resolver, '@fast-white-cat/integration-ksef-direct'),
|
|
278
|
+
).rejects.toThrow('Re-run with --allow-third-party')
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
it('enables a non-@open-mercato package when --allow-third-party is set', async () => {
|
|
282
|
+
const packageRoot = path.join(tmpDir, 'node_modules', '@fast-white-cat', 'integration-ksef-direct')
|
|
283
|
+
const appDir = path.join(tmpDir, 'app')
|
|
284
|
+
buildPackageFixture(packageRoot, 'ksef_direct', {
|
|
285
|
+
packageName: '@fast-white-cat/integration-ksef-direct',
|
|
286
|
+
})
|
|
287
|
+
|
|
288
|
+
const resolver = buildResolver(appDir, packageRoot, 'export const enabledModules = []\n')
|
|
289
|
+
|
|
290
|
+
await expect(
|
|
291
|
+
enableOfficialModule(resolver, '@fast-white-cat/integration-ksef-direct', undefined, false, true),
|
|
292
|
+
).resolves.toEqual({
|
|
293
|
+
moduleId: 'ksef_direct',
|
|
294
|
+
packageName: '@fast-white-cat/integration-ksef-direct',
|
|
295
|
+
from: '@fast-white-cat/integration-ksef-direct',
|
|
296
|
+
registrationChanged: true,
|
|
297
|
+
})
|
|
298
|
+
|
|
299
|
+
expect(fs.readFileSync(path.join(appDir, 'src', 'modules.ts'), 'utf8')).toContain(
|
|
300
|
+
"{ id: 'ksef_direct', from: '@fast-white-cat/integration-ksef-direct' }",
|
|
301
|
+
)
|
|
302
|
+
})
|
|
303
|
+
})
|
|
@@ -57,6 +57,33 @@ describe('module-package', () => {
|
|
|
57
57
|
expect(modulePackage.distModuleDir).toContain(path.join('dist', 'modules', 'test_package'))
|
|
58
58
|
})
|
|
59
59
|
|
|
60
|
+
it('validates a third-party (non-@open-mercato) module package by structure', () => {
|
|
61
|
+
const packageRoot = path.join(tmpDir, 'node_modules', '@fast-white-cat', 'integration-ksef-direct')
|
|
62
|
+
for (const base of ['src', 'dist']) {
|
|
63
|
+
fs.mkdirSync(path.join(packageRoot, base, 'modules', 'ksef_direct'), { recursive: true })
|
|
64
|
+
}
|
|
65
|
+
fs.writeFileSync(
|
|
66
|
+
path.join(packageRoot, 'package.json'),
|
|
67
|
+
JSON.stringify({ name: '@fast-white-cat/integration-ksef-direct', version: '0.1.0' }),
|
|
68
|
+
)
|
|
69
|
+
fs.writeFileSync(
|
|
70
|
+
path.join(packageRoot, 'src', 'modules', 'ksef_direct', 'index.ts'),
|
|
71
|
+
"export const metadata = { title: 'KSeF Direct', ejectable: false }\n",
|
|
72
|
+
)
|
|
73
|
+
fs.writeFileSync(
|
|
74
|
+
path.join(packageRoot, 'dist', 'modules', 'ksef_direct', 'index.js'),
|
|
75
|
+
'exports.metadata = {};\n',
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
const modulePackage = readOfficialModulePackageFromRoot(
|
|
79
|
+
packageRoot,
|
|
80
|
+
'@fast-white-cat/integration-ksef-direct',
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
expect(modulePackage.packageName).toBe('@fast-white-cat/integration-ksef-direct')
|
|
84
|
+
expect(modulePackage.metadata.moduleId).toBe('ksef_direct')
|
|
85
|
+
})
|
|
86
|
+
|
|
60
87
|
it('resolves a hoisted installed module package from a monorepo app', () => {
|
|
61
88
|
const appDir = path.join(tmpDir, 'apps', 'mercato')
|
|
62
89
|
const installedPackageRoot = path.join(tmpDir, 'node_modules', '@open-mercato', 'test-package')
|
|
@@ -2,12 +2,14 @@ export type ParsedModuleInstallArgs = {
|
|
|
2
2
|
packageSpec: string | null
|
|
3
3
|
eject: boolean
|
|
4
4
|
moduleId: string | null
|
|
5
|
+
allowThirdParty: boolean
|
|
5
6
|
}
|
|
6
7
|
|
|
7
8
|
export function parseModuleInstallArgs(args: string[]): ParsedModuleInstallArgs {
|
|
8
9
|
let packageSpec: string | null = null
|
|
9
10
|
let eject = false
|
|
10
11
|
let moduleId: string | null = null
|
|
12
|
+
let allowThirdParty = false
|
|
11
13
|
|
|
12
14
|
for (let index = 0; index < args.length; index += 1) {
|
|
13
15
|
const arg = args[index]
|
|
@@ -22,6 +24,15 @@ export function parseModuleInstallArgs(args: string[]): ParsedModuleInstallArgs
|
|
|
22
24
|
throw new Error('--eject does not accept a value')
|
|
23
25
|
}
|
|
24
26
|
|
|
27
|
+
if (arg === '--allow-third-party') {
|
|
28
|
+
allowThirdParty = true
|
|
29
|
+
continue
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (arg.startsWith('--allow-third-party=')) {
|
|
33
|
+
throw new Error('--allow-third-party does not accept a value')
|
|
34
|
+
}
|
|
35
|
+
|
|
25
36
|
if (arg === '--module') {
|
|
26
37
|
const next = args[index + 1]
|
|
27
38
|
if (next && !next.startsWith('-')) {
|
|
@@ -46,5 +57,5 @@ export function parseModuleInstallArgs(args: string[]): ParsedModuleInstallArgs
|
|
|
46
57
|
}
|
|
47
58
|
}
|
|
48
59
|
|
|
49
|
-
return { packageSpec, eject, moduleId }
|
|
60
|
+
return { packageSpec, eject, moduleId, allowThirdParty }
|
|
50
61
|
}
|
|
@@ -24,7 +24,8 @@ type InstallTarget = {
|
|
|
24
24
|
args: string[]
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
const
|
|
27
|
+
const OFFICIAL_PACKAGE_SCOPE = '@open-mercato/'
|
|
28
|
+
const SAFE_PACKAGE_SPEC_PATTERN = /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*(?:@.+)?$/i
|
|
28
29
|
const SAFE_PACKAGE_TAG_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/
|
|
29
30
|
const SAFE_PACKAGE_FILE_LOCATOR_PATTERN = /^file:[A-Za-z0-9_./: \\-]+$/
|
|
30
31
|
|
|
@@ -133,21 +134,36 @@ async function runGeneratorsWithRegistrationNotice(
|
|
|
133
134
|
}
|
|
134
135
|
}
|
|
135
136
|
|
|
137
|
+
function isOfficialPackage(packageName: string): boolean {
|
|
138
|
+
return packageName.startsWith(OFFICIAL_PACKAGE_SCOPE)
|
|
139
|
+
}
|
|
140
|
+
|
|
136
141
|
function assertPackageName(packageName: string | null): asserts packageName is string {
|
|
137
|
-
if (!packageName
|
|
138
|
-
throw new Error('
|
|
142
|
+
if (!packageName) {
|
|
143
|
+
throw new Error('Could not determine a package name from the provided spec.')
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function assertThirdPartyAllowed(packageName: string, allowThirdParty: boolean): void {
|
|
148
|
+
if (isOfficialPackage(packageName) || allowThirdParty) {
|
|
149
|
+
return
|
|
139
150
|
}
|
|
151
|
+
|
|
152
|
+
throw new Error(
|
|
153
|
+
`Package "${packageName}" is outside the ${OFFICIAL_PACKAGE_SCOPE}* scope. Re-run with --allow-third-party to install third-party module packages.`,
|
|
154
|
+
)
|
|
140
155
|
}
|
|
141
156
|
|
|
142
|
-
function assertSupportedPackageSpec(packageSpec: string): string {
|
|
157
|
+
function assertSupportedPackageSpec(packageSpec: string, allowThirdParty: boolean): string {
|
|
143
158
|
const trimmed = packageSpec.trim()
|
|
144
159
|
|
|
145
160
|
if (!SAFE_PACKAGE_SPEC_PATTERN.test(trimmed)) {
|
|
146
|
-
throw new Error('Unsupported package spec.
|
|
161
|
+
throw new Error('Unsupported package spec. Provide a valid npm package name with an optional tag/version or file: locator.')
|
|
147
162
|
}
|
|
148
163
|
|
|
149
164
|
const packageName = parsePackageNameFromSpec(trimmed)
|
|
150
165
|
assertPackageName(packageName)
|
|
166
|
+
assertThirdPartyAllowed(packageName, allowThirdParty)
|
|
151
167
|
|
|
152
168
|
if (trimmed === packageName) {
|
|
153
169
|
return trimmed
|
|
@@ -240,8 +256,9 @@ export async function addOfficialModule(
|
|
|
240
256
|
packageSpec: string,
|
|
241
257
|
eject: boolean,
|
|
242
258
|
moduleId?: string,
|
|
259
|
+
allowThirdParty = false,
|
|
243
260
|
): Promise<ModuleCommandResult> {
|
|
244
|
-
const safePackageSpec = assertSupportedPackageSpec(packageSpec)
|
|
261
|
+
const safePackageSpec = assertSupportedPackageSpec(packageSpec, allowThirdParty)
|
|
245
262
|
const packageName = parsePackageNameFromSpec(safePackageSpec)
|
|
246
263
|
assertPackageName(packageName)
|
|
247
264
|
|
|
@@ -256,10 +273,9 @@ export async function enableOfficialModule(
|
|
|
256
273
|
packageName: string,
|
|
257
274
|
moduleId?: string,
|
|
258
275
|
eject = false,
|
|
276
|
+
allowThirdParty = false,
|
|
259
277
|
): Promise<ModuleCommandResult> {
|
|
260
|
-
|
|
261
|
-
throw new Error('Only @open-mercato/* packages can be enabled with "mercato module enable".')
|
|
262
|
-
}
|
|
278
|
+
assertThirdPartyAllowed(packageName, allowThirdParty)
|
|
263
279
|
|
|
264
280
|
const modulePackage = resolveInstalledOfficialModulePackage(resolver, packageName, moduleId)
|
|
265
281
|
return registerResolvedOfficialModule(resolver, modulePackage, packageName, eject)
|
|
@@ -270,8 +270,8 @@ export function readOfficialModulePackageFromRoot(
|
|
|
270
270
|
|
|
271
271
|
const packageJson = readPackageJson(packageJsonPath)
|
|
272
272
|
const packageName = packageJson.name
|
|
273
|
-
if (!packageName
|
|
274
|
-
throw new Error(`Package at ${
|
|
273
|
+
if (!packageName) {
|
|
274
|
+
throw new Error(`Package manifest at ${packageJsonPath} is missing the "name" field.`)
|
|
275
275
|
}
|
|
276
276
|
|
|
277
277
|
if (expectedPackageName && packageName !== expectedPackageName) {
|
package/src/mercato.ts
CHANGED
|
@@ -1282,8 +1282,8 @@ export async function run(argv = process.argv) {
|
|
|
1282
1282
|
|
|
1283
1283
|
if (!subcommand || subcommand === 'help' || subcommand === '--help' || subcommand === '-h') {
|
|
1284
1284
|
console.log('Usage: yarn mercato module <add|enable|eject> ...')
|
|
1285
|
-
console.log(' yarn mercato module add <packageSpec> [--module <moduleId>] [--eject]')
|
|
1286
|
-
console.log(' yarn mercato module enable <packageName> [--module <moduleId>] [--eject]')
|
|
1285
|
+
console.log(' yarn mercato module add <packageSpec> [--module <moduleId>] [--eject] [--allow-third-party]')
|
|
1286
|
+
console.log(' yarn mercato module enable <packageName> [--module <moduleId>] [--eject] [--allow-third-party]')
|
|
1287
1287
|
console.log(' yarn mercato module eject <moduleId>')
|
|
1288
1288
|
return 0
|
|
1289
1289
|
}
|
|
@@ -1291,14 +1291,14 @@ export async function run(argv = process.argv) {
|
|
|
1291
1291
|
if (subcommand === 'add') {
|
|
1292
1292
|
const { createResolver } = await import('./lib/resolver')
|
|
1293
1293
|
const { addOfficialModule } = await import('./lib/module-install')
|
|
1294
|
-
const { packageSpec, eject, moduleId } = parseModuleInstallArgs(commandArgs)
|
|
1294
|
+
const { packageSpec, eject, moduleId, allowThirdParty } = parseModuleInstallArgs(commandArgs)
|
|
1295
1295
|
|
|
1296
1296
|
if (!packageSpec) {
|
|
1297
|
-
console.error('Usage: yarn mercato module add <packageSpec> [--module <moduleId>] [--eject]')
|
|
1297
|
+
console.error('Usage: yarn mercato module add <packageSpec> [--module <moduleId>] [--eject] [--allow-third-party]')
|
|
1298
1298
|
return 1
|
|
1299
1299
|
}
|
|
1300
1300
|
|
|
1301
|
-
const result = await addOfficialModule(createResolver(), packageSpec, eject, moduleId ?? undefined)
|
|
1301
|
+
const result = await addOfficialModule(createResolver(), packageSpec, eject, moduleId ?? undefined, allowThirdParty)
|
|
1302
1302
|
console.log(`\n✅ Module "${result.moduleId}" enabled from ${result.from}.\n`)
|
|
1303
1303
|
console.log('Next steps:')
|
|
1304
1304
|
console.log(' 1. Review generated files if needed: .mercato/generated/')
|
|
@@ -1309,14 +1309,14 @@ export async function run(argv = process.argv) {
|
|
|
1309
1309
|
if (subcommand === 'enable') {
|
|
1310
1310
|
const packageName = commandArgs.find((arg) => !arg.startsWith('-'))
|
|
1311
1311
|
if (!packageName) {
|
|
1312
|
-
console.error('Usage: yarn mercato module enable <packageName> [--module <moduleId>] [--eject]')
|
|
1312
|
+
console.error('Usage: yarn mercato module enable <packageName> [--module <moduleId>] [--eject] [--allow-third-party]')
|
|
1313
1313
|
return 1
|
|
1314
1314
|
}
|
|
1315
1315
|
|
|
1316
1316
|
const { createResolver } = await import('./lib/resolver')
|
|
1317
1317
|
const { enableOfficialModule } = await import('./lib/module-install')
|
|
1318
|
-
const { moduleId, eject } = parseModuleInstallArgs(commandArgs)
|
|
1319
|
-
const result = await enableOfficialModule(createResolver(), packageName, moduleId ?? undefined, eject)
|
|
1318
|
+
const { moduleId, eject, allowThirdParty } = parseModuleInstallArgs(commandArgs)
|
|
1319
|
+
const result = await enableOfficialModule(createResolver(), packageName, moduleId ?? undefined, eject, allowThirdParty)
|
|
1320
1320
|
console.log(`\n✅ Module "${result.moduleId}" enabled from ${result.from}.\n`)
|
|
1321
1321
|
console.log('Next steps:')
|
|
1322
1322
|
console.log(' 1. Review generated files if needed: .mercato/generated/')
|