@open-mercato/cli 0.6.6-develop.6382.1.4b9b9091ab → 0.6.6-develop.6384.1.f06fc0b42c
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/.turbo/turbo-build.log +11 -0
- package/build.mjs +70 -2
- package/dist/agentic/guides/core.auth.md +3 -0
- package/dist/agentic/guides/core.catalog.md +3 -0
- package/dist/agentic/guides/core.currencies.md +3 -0
- package/dist/agentic/guides/core.customer_accounts.md +3 -0
- package/dist/agentic/guides/core.customers.md +3 -0
- package/dist/agentic/guides/core.data_sync.md +3 -0
- package/dist/agentic/guides/core.integrations.md +3 -0
- package/dist/agentic/guides/core.sales.md +3 -0
- package/dist/agentic/guides/core.workflows.md +3 -0
- package/dist/agentic/guides/module-facts.json +2073 -0
- package/dist/agentic/guides/modules/auth.md +64 -0
- package/dist/agentic/guides/modules/catalog.md +70 -0
- package/dist/agentic/guides/modules/currencies.md +50 -0
- package/dist/agentic/guides/modules/customer_accounts.md +76 -0
- package/dist/agentic/guides/modules/customers.md +115 -0
- package/dist/agentic/guides/modules/data_sync.md +49 -0
- package/dist/agentic/guides/modules/integrations.md +49 -0
- package/dist/agentic/guides/modules/sales.md +109 -0
- package/dist/agentic/guides/modules/workflows.md +73 -0
- package/dist/lib/__integration__/TC-INT-008.spec.js +29 -1
- package/dist/lib/__integration__/TC-INT-008.spec.js.map +2 -2
- package/dist/lib/agentic-setup.js +87 -0
- package/dist/lib/agentic-setup.js.map +2 -2
- package/package.json +5 -5
- package/src/lib/__integration__/TC-INT-008.spec.ts +41 -1
- package/src/lib/agentic-setup.ts +129 -0
package/src/lib/agentic-setup.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import { existsSync, mkdirSync, readFileSync, writeFileSync, copyFileSync, symlinkSync, lstatSync, unlinkSync, readdirSync } from 'node:fs'
|
|
10
10
|
import { join, dirname, basename } from 'node:path'
|
|
11
11
|
import { fileURLToPath } from 'node:url'
|
|
12
|
+
import { Project, SyntaxKind } from 'ts-morph'
|
|
12
13
|
|
|
13
14
|
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
14
15
|
// In the built output (dist/lib/agentic-setup.js), __dirname is dist/lib/.
|
|
@@ -52,14 +53,125 @@ function copyFile(srcDir: string, srcRelative: string, destPath: string): void {
|
|
|
52
53
|
copyFileSync(srcPath, destPath)
|
|
53
54
|
}
|
|
54
55
|
|
|
56
|
+
// ─── Module fact-sheet selection (mirrors packages/create-app/src/setup/tools/shared.ts) ──
|
|
57
|
+
|
|
58
|
+
// AST-parse the static `enabledModules` array literal in the app's src/modules.ts
|
|
59
|
+
// and collect each entry's `id`. Only the static literal is read (conditional
|
|
60
|
+
// .push()/spread entries are intentionally not seen — see spec D6).
|
|
61
|
+
function readEnabledModuleIds(modulesPath: string): string[] {
|
|
62
|
+
if (!existsSync(modulesPath)) return []
|
|
63
|
+
try {
|
|
64
|
+
const project = new Project({ useInMemoryFileSystem: true })
|
|
65
|
+
const sourceFile = project.createSourceFile('modules.ts', readFileSync(modulesPath, 'utf-8'))
|
|
66
|
+
const declaration = sourceFile.getVariableDeclaration('enabledModules')
|
|
67
|
+
const arrayLiteral = declaration?.getInitializerIfKind(SyntaxKind.ArrayLiteralExpression)
|
|
68
|
+
if (!arrayLiteral) return []
|
|
69
|
+
const ids: string[] = []
|
|
70
|
+
for (const element of arrayLiteral.getElements()) {
|
|
71
|
+
const objectLiteral = element.asKind(SyntaxKind.ObjectLiteralExpression)
|
|
72
|
+
if (!objectLiteral) continue
|
|
73
|
+
const idProperty = objectLiteral.getProperty('id')?.asKind(SyntaxKind.PropertyAssignment)
|
|
74
|
+
const idValue = idProperty?.getInitializerIfKind(SyntaxKind.StringLiteral)?.getLiteralValue()
|
|
75
|
+
if (idValue) ids.push(idValue)
|
|
76
|
+
}
|
|
77
|
+
return ids
|
|
78
|
+
} catch {
|
|
79
|
+
return []
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Resolve which per-module fact-sheets to ship: the intersection of the bundled
|
|
84
|
+
// fact-sheets (the D5 allowlist, materialized by build.mjs) with the app's enabled
|
|
85
|
+
// modules. Falls back to the full bundled set when the enabled set cannot be read
|
|
86
|
+
// (R5 — degraded, never empty).
|
|
87
|
+
function selectModuleFactSheets(targetDir: string, modulesSubdir: string): string[] {
|
|
88
|
+
const available = existsSync(modulesSubdir)
|
|
89
|
+
? readdirSync(modulesSubdir)
|
|
90
|
+
.filter((file) => file.endsWith('.md'))
|
|
91
|
+
.map((file) => file.replace(/\.md$/, ''))
|
|
92
|
+
: []
|
|
93
|
+
if (available.length === 0) return []
|
|
94
|
+
const enabled = new Set(readEnabledModuleIds(join(targetDir, 'src', 'modules.ts')))
|
|
95
|
+
const selected = available.filter((moduleId) => enabled.has(moduleId))
|
|
96
|
+
return selected.length > 0 ? selected : available
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const MODULE_GUIDES_START = '<!-- om:module-guides:start -->'
|
|
100
|
+
const MODULE_GUIDES_END = '<!-- om:module-guides:end -->'
|
|
101
|
+
|
|
102
|
+
// Read each module's guide label from the bundled `module-facts.json` (emitted by
|
|
103
|
+
// build.mjs from the generator's extraction of each module's own `metadata`). The
|
|
104
|
+
// label falls back description → title → generic, so the CLI never re-declares
|
|
105
|
+
// specific module names or descriptions. A missing/malformed sidecar degrades to an
|
|
106
|
+
// empty map (generic labels), never a throw.
|
|
107
|
+
function readModuleGuideLabels(guidesDir: string): Record<string, string> {
|
|
108
|
+
const factsPath = join(guidesDir, 'module-facts.json')
|
|
109
|
+
if (!existsSync(factsPath)) return {}
|
|
110
|
+
try {
|
|
111
|
+
const parsed = JSON.parse(readFileSync(factsPath, 'utf-8')) as Record<
|
|
112
|
+
string,
|
|
113
|
+
{ description?: unknown; title?: unknown }
|
|
114
|
+
>
|
|
115
|
+
const labels: Record<string, string> = {}
|
|
116
|
+
for (const [moduleId, entry] of Object.entries(parsed)) {
|
|
117
|
+
const label =
|
|
118
|
+
(entry && typeof entry.description === 'string' && entry.description) ||
|
|
119
|
+
(entry && typeof entry.title === 'string' && entry.title) ||
|
|
120
|
+
''
|
|
121
|
+
if (label) labels[moduleId] = label
|
|
122
|
+
}
|
|
123
|
+
return labels
|
|
124
|
+
} catch {
|
|
125
|
+
return {}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function renderModuleGuidesBlock(selected: string[], labels: Record<string, string>): string {
|
|
130
|
+
if (selected.length === 0) return '_No module fact-sheets are bundled for this app._'
|
|
131
|
+
const rows = selected.map((moduleId) => {
|
|
132
|
+
const label = labels[moduleId] ?? `Use the ${moduleId} module`
|
|
133
|
+
return `| ${label} | \`.ai/guides/modules/${moduleId}.md\` |`
|
|
134
|
+
})
|
|
135
|
+
return ['| Task | Load |', '|---|---|', ...rows].join('\n')
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Regenerate the marker-delimited Module-Specific Guides block in the written
|
|
139
|
+
// AGENTS.md from the selected module set. Replaces strictly between the markers so
|
|
140
|
+
// surrounding prose is untouched and repeat runs are idempotent.
|
|
141
|
+
function injectModuleGuides(
|
|
142
|
+
agentsMdPath: string,
|
|
143
|
+
selected: string[],
|
|
144
|
+
labels: Record<string, string> = {},
|
|
145
|
+
): void {
|
|
146
|
+
if (!existsSync(agentsMdPath)) return
|
|
147
|
+
const content = readFileSync(agentsMdPath, 'utf-8')
|
|
148
|
+
const startIndex = content.indexOf(MODULE_GUIDES_START)
|
|
149
|
+
const endIndex = content.indexOf(MODULE_GUIDES_END)
|
|
150
|
+
if (startIndex === -1 || endIndex === -1 || endIndex < startIndex) {
|
|
151
|
+
console.warn(
|
|
152
|
+
`[agentic] Module-Specific Guides markers (${MODULE_GUIDES_START} … ${MODULE_GUIDES_END}) not found in ${agentsMdPath}; the per-module guide list was not generated.`,
|
|
153
|
+
)
|
|
154
|
+
return
|
|
155
|
+
}
|
|
156
|
+
const before = content.slice(0, startIndex + MODULE_GUIDES_START.length)
|
|
157
|
+
const after = content.slice(endIndex)
|
|
158
|
+
const next = `${before}\n${renderModuleGuidesBlock(selected, labels)}\n${after}`
|
|
159
|
+
if (next !== content) writeFileSync(agentsMdPath, next)
|
|
160
|
+
}
|
|
161
|
+
|
|
55
162
|
// ─── Generators ──────────────────────────────────────────────────────────
|
|
56
163
|
|
|
57
164
|
function generateShared(config: AgenticConfig): void {
|
|
58
165
|
const { targetDir } = config
|
|
59
166
|
const srcDir = join(AGENTIC_DIR, 'shared')
|
|
60
167
|
|
|
168
|
+
// Resolve which per-module fact-sheets this app gets (enabled ∩ bundled allowlist).
|
|
169
|
+
const selectedModules = selectModuleFactSheets(targetDir, join(GUIDES_DIR, 'modules'))
|
|
170
|
+
const moduleGuideLabels = readModuleGuideLabels(GUIDES_DIR)
|
|
171
|
+
|
|
61
172
|
// AGENTS.md
|
|
62
173
|
writeTemplate(srcDir, 'AGENTS.md.template', join(targetDir, 'AGENTS.md'), config)
|
|
174
|
+
injectModuleGuides(join(targetDir, 'AGENTS.md'), selectedModules, moduleGuideLabels)
|
|
63
175
|
|
|
64
176
|
// .ai/ structure
|
|
65
177
|
writeTemplate(srcDir, 'ai/specs/README.md', join(targetDir, '.ai', 'specs', 'README.md'), config)
|
|
@@ -244,6 +356,9 @@ function generateShared(config: AgenticConfig): void {
|
|
|
244
356
|
|
|
245
357
|
copyFile(srcDir, 'ai/qa/tests/playwright.config.ts', join(targetDir, '.ai', 'qa', 'tests', 'playwright.config.ts'))
|
|
246
358
|
|
|
359
|
+
// Package & conceptual guides are copied wholesale (framework-wide). Per-module
|
|
360
|
+
// fact-sheets (.ai/guides/modules/<module>.md) are filtered to the app's enabled
|
|
361
|
+
// module set; the combined module-facts.json sidecar is copied as-is.
|
|
247
362
|
if (existsSync(GUIDES_DIR)) {
|
|
248
363
|
const guidesDestDir = join(targetDir, '.ai', 'guides')
|
|
249
364
|
for (const file of readdirSync(GUIDES_DIR)) {
|
|
@@ -253,6 +368,20 @@ function generateShared(config: AgenticConfig): void {
|
|
|
253
368
|
ensureDir(destPath)
|
|
254
369
|
copyFileSync(srcPath, destPath)
|
|
255
370
|
}
|
|
371
|
+
|
|
372
|
+
const moduleFactsPath = join(GUIDES_DIR, 'module-facts.json')
|
|
373
|
+
if (existsSync(moduleFactsPath)) {
|
|
374
|
+
const destPath = join(guidesDestDir, 'module-facts.json')
|
|
375
|
+
ensureDir(destPath)
|
|
376
|
+
copyFileSync(moduleFactsPath, destPath)
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const modulesSubdir = join(GUIDES_DIR, 'modules')
|
|
380
|
+
for (const moduleId of selectedModules) {
|
|
381
|
+
const destPath = join(guidesDestDir, 'modules', `${moduleId}.md`)
|
|
382
|
+
ensureDir(destPath)
|
|
383
|
+
copyFileSync(join(modulesSubdir, `${moduleId}.md`), destPath)
|
|
384
|
+
}
|
|
256
385
|
}
|
|
257
386
|
}
|
|
258
387
|
|