@brms/ai-skills 0.1.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/README.md +256 -0
- package/bin/brms-skills.mjs +411 -0
- package/package.json +30 -0
- package/skills/brms-prototype-generator/SKILL.md +129 -0
- package/skills/brms-prototype-generator/agents/openai.yaml +7 -0
- package/skills/brms-prototype-generator/examples/few-shot-examples.md +577 -0
- package/skills/brms-prototype-generator/references/01-list-query.md +444 -0
- package/skills/brms-prototype-generator/references/02-form-entry.md +129 -0
- package/skills/brms-prototype-generator/references/03-detail-display.md +125 -0
- package/skills/brms-prototype-generator/references/04-composite-page-package.md +339 -0
- package/skills/brms-prototype-generator/references/05-dialog-patterns.md +113 -0
- package/skills/brms-prototype-generator/references/06-backend-request-patterns.md +118 -0
- package/skills/brms-prototype-generator/references/resource-index.md +46 -0
- package/skills/brms-prototype-generator/references/system-prompt.md +242 -0
- package/skills/brms-prototype-generator/scripts/analyze-doc.mjs +554 -0
- package/skills/brms-prototype-generator/scripts/check-project.mjs +228 -0
- package/skills/brms-prototype-generator/scripts/discover-targets.mjs +158 -0
- package/skills/brms-prototype-generator/scripts/install-codex.mjs +74 -0
- package/skills/brms-prototype-generator/scripts/plan-pages.mjs +390 -0
- package/skills/brms-prototype-generator/scripts/validate-generated.mjs +838 -0
- package/skills/brms-prototype-generator/templates/user-input-template.md +182 -0
- package/skills/brms-vxe-plus-developer/SKILL.md +105 -0
- package/skills/brms-vxe-plus-developer/agents/openai.yaml +7 -0
- package/skills/brms-vxe-plus-developer/references/prototype-to-real.md +54 -0
- package/skills/brms-vxe-plus-developer/references/real-base-development.md +110 -0
- package/skills/brms-vxe-plus-developer/references/resource-index.md +43 -0
- package/skills/brms-vxe-plus-developer/references/review-checklist.md +49 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/01-mental-model.md +150 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/02-vxe-plus-form.md +302 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/03-vxe-plus-table.md +253 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/04-example-map.md +488 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/05-request-and-eiinfo.md +170 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/90-anti-patterns.md +137 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/README.md +43 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/README.md +21 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/A1/P0/A1P01601.vue +483 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/A1/P1/A1P11011.vue +444 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/AB/BP/ABBP0201.vue +1648 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/AM/AF/component/AMAF0601/Bidding/formConfig.ts +228 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/AM/AF/component/AMAF0601/Record/columns.ts +110 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/BM/BR/BMBR01.vue +130 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/BM/BR/component/BMBR01/columns.ts +94 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/BM/BR/component/BMBR01/formConfig.ts +108 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Change/formConfig.ts +123 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Change/index.vue +103 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Clause/columns.ts +48 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Clause/index.vue +202 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Correcte/formConfig.ts +117 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Correcte/index.vue +103 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Explain/Pay/Payment/formConfig.ts +90 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Explain/Pay/Payment/index.vue +42 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Explain/Pay/columns.ts +376 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Explain/Pay/index.vue +619 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Explain/Settle/Domestic/formConfig.ts +73 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Explain/Settle/Domestic/index.vue +47 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Explain/Settle/Foreign/formConfig.ts +141 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Explain/Settle/Foreign/index.vue +42 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Explain/Settle/columns.ts +123 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Explain/Settle/index.vue +593 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Explain/index.vue +68 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Fee/columns.ts +150 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Fee/index.vue +235 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Files/columns.ts +63 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Files/index.vue +117 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Goods/columns.ts +327 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Goods/index.vue +790 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Main/Base/Approve/formConfig.ts +341 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Main/Base/Approve/index.vue +63 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Main/Base/Approve2/formConfig.ts +232 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Main/Base/Approve2/index.vue +27 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Main/Base/Diff/columns.ts +46 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Main/Base/Diff/index.vue +92 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Main/Base/formConfig.ts +979 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Main/Base/index.vue +62 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Main/Other/formConfig.ts +179 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Main/Other/index.vue +140 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Main/Sign/formConfig.ts +118 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Main/Sign/index.vue +44 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Main/index.vue +168 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Party/Major/formConfig.ts +257 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Party/Major/index.vue +47 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Party/columns.ts +256 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Party/index.vue +738 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Price/formConfig.ts +174 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Price/index.vue +51 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Top/index.vue +924 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/SM/SW/SMSW0101.vue +567 -0
- package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/demo/index.vue +448 -0
- package/skills/brms-vxe-plus-developer/scripts/check-project.mjs +259 -0
- package/skills/brms-vxe-plus-developer/scripts/check-vxe-plus-page.mjs +137 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
|
|
5
|
+
function parseArgs(argv) {
|
|
6
|
+
const args = {
|
|
7
|
+
repoRoot: process.cwd(),
|
|
8
|
+
targetProject: '',
|
|
9
|
+
format: 'markdown',
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
13
|
+
const arg = argv[i]
|
|
14
|
+
if (arg === '--repo-root') {
|
|
15
|
+
args.repoRoot = argv[i + 1] || ''
|
|
16
|
+
i += 1
|
|
17
|
+
}
|
|
18
|
+
else if (arg === '--target-project') {
|
|
19
|
+
args.targetProject = argv[i + 1] || ''
|
|
20
|
+
i += 1
|
|
21
|
+
}
|
|
22
|
+
else if (arg === '--format') {
|
|
23
|
+
args.format = argv[i + 1] || ''
|
|
24
|
+
i += 1
|
|
25
|
+
}
|
|
26
|
+
else if (arg === '--help' || arg === '-h') {
|
|
27
|
+
args.help = true
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
throw new Error(`Unknown argument: ${arg}`)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (!['json', 'markdown', 'both'].includes(args.format))
|
|
35
|
+
throw new Error('--format must be one of: json, markdown, both')
|
|
36
|
+
|
|
37
|
+
return args
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function existsDir(filePath) {
|
|
41
|
+
return fs.existsSync(filePath) && fs.statSync(filePath).isDirectory()
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function existsFile(filePath) {
|
|
45
|
+
return fs.existsSync(filePath) && fs.statSync(filePath).isFile()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function readJson(filePath) {
|
|
49
|
+
if (!existsFile(filePath))
|
|
50
|
+
return null
|
|
51
|
+
try {
|
|
52
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf8'))
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return null
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function rel(filePath, root) {
|
|
60
|
+
return path.relative(root, filePath).replaceAll(path.sep, '/')
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function hasAnyDependency(pkg, names) {
|
|
64
|
+
const deps = {
|
|
65
|
+
...(pkg?.dependencies || {}),
|
|
66
|
+
...(pkg?.devDependencies || {}),
|
|
67
|
+
}
|
|
68
|
+
return names.some(name => Object.prototype.hasOwnProperty.call(deps, name))
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function findProjects(repoRoot, targetProject) {
|
|
72
|
+
const projectRoot = path.join(repoRoot, 'project')
|
|
73
|
+
if (!existsDir(projectRoot))
|
|
74
|
+
return []
|
|
75
|
+
|
|
76
|
+
const explicitTarget = Boolean(targetProject)
|
|
77
|
+
const requested = targetProject
|
|
78
|
+
? [targetProject.replaceAll('\\', '/').replace(/^project\//, '')]
|
|
79
|
+
: fs.readdirSync(projectRoot, { withFileTypes: true }).filter(entry => entry.isDirectory()).map(entry => entry.name)
|
|
80
|
+
|
|
81
|
+
return requested.flatMap((name) => {
|
|
82
|
+
const projectDir = path.join(projectRoot, name)
|
|
83
|
+
const packageJson = path.join(projectDir, 'package.json')
|
|
84
|
+
const pkg = readJson(packageJson)
|
|
85
|
+
const srcDir = path.join(projectDir, 'src')
|
|
86
|
+
const viewsDir = path.join(srcDir, 'views')
|
|
87
|
+
const routeConfig = path.join(srcDir, 'routers', 'config', 'index.ts')
|
|
88
|
+
const localMenu = path.join(srcDir, 'routers', 'localMenuList.json')
|
|
89
|
+
const dynamicRouter = path.join(srcDir, 'routers', 'modules', 'dynamicRouter.ts')
|
|
90
|
+
|
|
91
|
+
if (!explicitTarget && !existsDir(viewsDir))
|
|
92
|
+
return []
|
|
93
|
+
|
|
94
|
+
return [{
|
|
95
|
+
id: name,
|
|
96
|
+
exists: existsDir(projectDir),
|
|
97
|
+
packageName: pkg?.name || '',
|
|
98
|
+
projectDir: existsDir(projectDir) ? rel(projectDir, repoRoot) : `project/${name}`,
|
|
99
|
+
srcDir: existsDir(srcDir) ? rel(srcDir, repoRoot) : '',
|
|
100
|
+
viewsDir: existsDir(viewsDir) ? rel(viewsDir, repoRoot) : '',
|
|
101
|
+
hasVueVite: hasAnyDependency(pkg, ['vue', 'vite', '@vitejs/plugin-vue']),
|
|
102
|
+
hasVxePlus: hasAnyDependency(pkg, ['@vxe-plus/components', 'vxe-table', 'vxe-pc-ui']),
|
|
103
|
+
hasEiInfo: hasAnyDependency(pkg, ['@eplat/ei']),
|
|
104
|
+
routeStyle: existsFile(routeConfig)
|
|
105
|
+
? 'config'
|
|
106
|
+
: existsFile(localMenu)
|
|
107
|
+
? 'local-menu'
|
|
108
|
+
: existsFile(dynamicRouter)
|
|
109
|
+
? 'dynamic-router'
|
|
110
|
+
: 'unknown',
|
|
111
|
+
routeFile: existsFile(routeConfig)
|
|
112
|
+
? rel(routeConfig, repoRoot)
|
|
113
|
+
: existsFile(localMenu)
|
|
114
|
+
? rel(localMenu, repoRoot)
|
|
115
|
+
: existsFile(dynamicRouter)
|
|
116
|
+
? rel(dynamicRouter, repoRoot)
|
|
117
|
+
: '',
|
|
118
|
+
}]
|
|
119
|
+
})
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function check(repoRoot, targetProject) {
|
|
123
|
+
const rootPkg = readJson(path.join(repoRoot, 'package.json'))
|
|
124
|
+
const workspaceFile = path.join(repoRoot, 'pnpm-workspace.yaml')
|
|
125
|
+
const blockers = []
|
|
126
|
+
const warnings = []
|
|
127
|
+
const signals = []
|
|
128
|
+
|
|
129
|
+
if (!rootPkg)
|
|
130
|
+
blockers.push('repo root is missing a readable package.json')
|
|
131
|
+
else
|
|
132
|
+
signals.push(`repo package: ${rootPkg.name || '(unnamed)'}`)
|
|
133
|
+
|
|
134
|
+
if (!existsFile(workspaceFile))
|
|
135
|
+
blockers.push('repo root is missing pnpm-workspace.yaml')
|
|
136
|
+
else
|
|
137
|
+
signals.push('pnpm workspace detected')
|
|
138
|
+
|
|
139
|
+
if (rootPkg?.volta?.node && rootPkg.volta.node !== '18.17.0')
|
|
140
|
+
warnings.push(`repo Volta node is ${rootPkg.volta.node}; skill was validated on 18.17.0`)
|
|
141
|
+
if (rootPkg?.volta?.pnpm && rootPkg.volta.pnpm !== '8.10.4')
|
|
142
|
+
warnings.push(`repo Volta pnpm is ${rootPkg.volta.pnpm}; skill was validated on 8.10.4`)
|
|
143
|
+
|
|
144
|
+
if (!hasAnyDependency(rootPkg, ['@eplat/ei']))
|
|
145
|
+
warnings.push('root package does not declare @eplat/ei; prototype can still use mock mode')
|
|
146
|
+
|
|
147
|
+
const hasExplicitTarget = Boolean(targetProject)
|
|
148
|
+
const projects = findProjects(repoRoot, targetProject)
|
|
149
|
+
if (!projects.length)
|
|
150
|
+
blockers.push('no project candidates found under project/*')
|
|
151
|
+
if (!hasExplicitTarget && projects.length > 1)
|
|
152
|
+
blockers.push('multiple project candidates found; ask the user to choose one and rerun with --target-project project/<name>')
|
|
153
|
+
|
|
154
|
+
for (const project of projects) {
|
|
155
|
+
if (!project.exists) {
|
|
156
|
+
blockers.push(`${project.projectDir} does not exist`)
|
|
157
|
+
continue
|
|
158
|
+
}
|
|
159
|
+
if (!project.srcDir)
|
|
160
|
+
blockers.push(`${project.projectDir} is missing src/`)
|
|
161
|
+
if (!project.viewsDir)
|
|
162
|
+
blockers.push(`${project.projectDir} is missing src/views/`)
|
|
163
|
+
if (!project.hasVueVite)
|
|
164
|
+
warnings.push(`${project.projectDir} does not clearly declare Vue/Vite dependencies`)
|
|
165
|
+
if (!project.hasVxePlus)
|
|
166
|
+
warnings.push(`${project.projectDir} does not clearly declare VxePlus/Vxe dependencies`)
|
|
167
|
+
if (project.routeStyle === 'unknown')
|
|
168
|
+
warnings.push(`${project.projectDir} route/menu registration style was not detected; plan route handoff manually`)
|
|
169
|
+
else
|
|
170
|
+
signals.push(`${project.projectDir} route style: ${project.routeStyle} (${project.routeFile})`)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return {
|
|
174
|
+
ok: blockers.length === 0,
|
|
175
|
+
repoRoot,
|
|
176
|
+
skill: 'brms-prototype-generator',
|
|
177
|
+
needsTargetProject: !hasExplicitTarget && projects.length > 1,
|
|
178
|
+
blockers,
|
|
179
|
+
warnings,
|
|
180
|
+
signals,
|
|
181
|
+
projects,
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function toMarkdown(report) {
|
|
186
|
+
const lines = [`# ${report.skill} Project Check`, '', `- Status: ${report.ok ? 'ok' : 'blocked'}`]
|
|
187
|
+
if (report.blockers.length) {
|
|
188
|
+
lines.push('', '## Blockers', ...report.blockers.map(item => `- ${item}`))
|
|
189
|
+
}
|
|
190
|
+
if (report.warnings.length) {
|
|
191
|
+
lines.push('', '## Warnings', ...report.warnings.map(item => `- ${item}`))
|
|
192
|
+
}
|
|
193
|
+
if (report.signals.length) {
|
|
194
|
+
lines.push('', '## Signals', ...report.signals.map(item => `- ${item}`))
|
|
195
|
+
}
|
|
196
|
+
if (report.projects.length) {
|
|
197
|
+
lines.push('', '## Projects')
|
|
198
|
+
for (const project of report.projects) {
|
|
199
|
+
lines.push(`- ${project.projectDir}: ${project.packageName || '(no package name)'}`)
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return lines.join('\n')
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function main() {
|
|
206
|
+
const args = parseArgs(process.argv.slice(2))
|
|
207
|
+
if (args.help) {
|
|
208
|
+
console.log('Usage: node scripts/check-project.mjs [--repo-root <repo>] [--target-project project/name] [--format json|markdown|both]')
|
|
209
|
+
process.exit(0)
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const report = check(path.resolve(args.repoRoot), args.targetProject)
|
|
213
|
+
if (args.format === 'json' || args.format === 'both')
|
|
214
|
+
console.log(JSON.stringify(report, null, 2))
|
|
215
|
+
if (args.format === 'both')
|
|
216
|
+
console.log('\n---\n')
|
|
217
|
+
if (args.format === 'markdown' || args.format === 'both')
|
|
218
|
+
console.log(toMarkdown(report))
|
|
219
|
+
process.exit(report.ok ? 0 : 1)
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
try {
|
|
223
|
+
main()
|
|
224
|
+
}
|
|
225
|
+
catch (error) {
|
|
226
|
+
console.error(error instanceof Error ? error.message : String(error))
|
|
227
|
+
process.exit(1)
|
|
228
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
|
|
5
|
+
function parseArgs(argv) {
|
|
6
|
+
const args = {
|
|
7
|
+
repoRoot: process.cwd(),
|
|
8
|
+
format: 'markdown',
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
12
|
+
const arg = argv[i]
|
|
13
|
+
if (arg === '--repo-root') {
|
|
14
|
+
args.repoRoot = argv[i + 1] || ''
|
|
15
|
+
i += 1
|
|
16
|
+
}
|
|
17
|
+
else if (arg === '--format') {
|
|
18
|
+
args.format = argv[i + 1] || ''
|
|
19
|
+
i += 1
|
|
20
|
+
}
|
|
21
|
+
else if (arg === '--help' || arg === '-h') {
|
|
22
|
+
args.help = true
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
throw new Error(`Unknown argument: ${arg}`)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (!['json', 'markdown', 'both'].includes(args.format))
|
|
30
|
+
throw new Error('--format must be one of: json, markdown, both')
|
|
31
|
+
|
|
32
|
+
return args
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function existsDir(filePath) {
|
|
36
|
+
return fs.existsSync(filePath) && fs.statSync(filePath).isDirectory()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function existsFile(filePath) {
|
|
40
|
+
return fs.existsSync(filePath) && fs.statSync(filePath).isFile()
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function toRepoRelative(filePath, repoRoot) {
|
|
44
|
+
return path.relative(repoRoot, filePath).replaceAll(path.sep, '/')
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function readPackageName(projectDir) {
|
|
48
|
+
const packageJson = path.join(projectDir, 'package.json')
|
|
49
|
+
if (!existsFile(packageJson))
|
|
50
|
+
return ''
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
return JSON.parse(fs.readFileSync(packageJson, 'utf8')).name || ''
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return ''
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function discover(repoRoot) {
|
|
61
|
+
const projectRoot = path.join(repoRoot, 'project')
|
|
62
|
+
const candidates = []
|
|
63
|
+
|
|
64
|
+
if (!existsDir(projectRoot))
|
|
65
|
+
return { repoRoot, candidates }
|
|
66
|
+
|
|
67
|
+
for (const entry of fs.readdirSync(projectRoot, { withFileTypes: true })) {
|
|
68
|
+
if (!entry.isDirectory())
|
|
69
|
+
continue
|
|
70
|
+
|
|
71
|
+
const projectDir = path.join(projectRoot, entry.name)
|
|
72
|
+
const srcDir = path.join(projectDir, 'src')
|
|
73
|
+
const viewsDir = path.join(srcDir, 'views')
|
|
74
|
+
if (!existsDir(srcDir) && !existsDir(viewsDir))
|
|
75
|
+
continue
|
|
76
|
+
|
|
77
|
+
const routeConfigDir = path.join(srcDir, 'routers', 'config')
|
|
78
|
+
const routeIndex = path.join(routeConfigDir, 'index.ts')
|
|
79
|
+
const localMenu = path.join(srcDir, 'routers', 'localMenuList.json')
|
|
80
|
+
const dynamicRouter = path.join(srcDir, 'routers', 'modules', 'dynamicRouter.ts')
|
|
81
|
+
const routeStyle = existsFile(routeIndex)
|
|
82
|
+
? 'config'
|
|
83
|
+
: existsFile(localMenu)
|
|
84
|
+
? 'local-menu'
|
|
85
|
+
: existsFile(dynamicRouter)
|
|
86
|
+
? 'dynamic-router'
|
|
87
|
+
: 'unknown'
|
|
88
|
+
const routeFile = existsFile(routeIndex)
|
|
89
|
+
? routeIndex
|
|
90
|
+
: existsFile(localMenu)
|
|
91
|
+
? localMenu
|
|
92
|
+
: existsFile(dynamicRouter)
|
|
93
|
+
? dynamicRouter
|
|
94
|
+
: ''
|
|
95
|
+
|
|
96
|
+
candidates.push({
|
|
97
|
+
id: entry.name,
|
|
98
|
+
packageName: readPackageName(projectDir),
|
|
99
|
+
projectDir: toRepoRelative(projectDir, repoRoot),
|
|
100
|
+
srcDir: existsDir(srcDir) ? toRepoRelative(srcDir, repoRoot) : '',
|
|
101
|
+
viewsDir: existsDir(viewsDir) ? toRepoRelative(viewsDir, repoRoot) : '',
|
|
102
|
+
routeConfigDir: existsDir(routeConfigDir) ? toRepoRelative(routeConfigDir, repoRoot) : '',
|
|
103
|
+
routeConfigIndex: existsFile(routeIndex) ? toRepoRelative(routeIndex, repoRoot) : '',
|
|
104
|
+
routeStyle,
|
|
105
|
+
routeFile: routeFile ? toRepoRelative(routeFile, repoRoot) : '',
|
|
106
|
+
canRegisterStaticRoute: routeStyle === 'config',
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return { repoRoot, candidates }
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function toMarkdown(report) {
|
|
114
|
+
const lines = ['# BRMS Prototype Target Discovery', '']
|
|
115
|
+
if (!report.candidates.length) {
|
|
116
|
+
lines.push('- No project candidates found under `project/*`.')
|
|
117
|
+
return lines.join('\n')
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
report.candidates.forEach((candidate, index) => {
|
|
121
|
+
lines.push(`## ${index + 1}. ${candidate.id}`)
|
|
122
|
+
lines.push(`- Project: \`${candidate.projectDir}\``)
|
|
123
|
+
if (candidate.packageName)
|
|
124
|
+
lines.push(`- Package: \`${candidate.packageName}\``)
|
|
125
|
+
lines.push(`- Views: ${candidate.viewsDir ? `\`${candidate.viewsDir}\`` : 'missing'}`)
|
|
126
|
+
lines.push(`- Route style: \`${candidate.routeStyle}\`${candidate.routeFile ? ` (\`${candidate.routeFile}\`)` : ''}`)
|
|
127
|
+
if (candidate.routeStyle !== 'config')
|
|
128
|
+
lines.push('- Menu handoff: inspect this route/menu style before writing route files; permission-center or local-menu projects may not use static route config.')
|
|
129
|
+
lines.push('')
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
return lines.join('\n')
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function main() {
|
|
136
|
+
const args = parseArgs(process.argv.slice(2))
|
|
137
|
+
if (args.help) {
|
|
138
|
+
console.log('Usage: node scripts/discover-targets.mjs [--repo-root <repo>] [--format json|markdown|both]')
|
|
139
|
+
process.exit(0)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const repoRoot = path.resolve(args.repoRoot)
|
|
143
|
+
const report = discover(repoRoot)
|
|
144
|
+
if (args.format === 'json' || args.format === 'both')
|
|
145
|
+
console.log(JSON.stringify(report, null, 2))
|
|
146
|
+
if (args.format === 'both')
|
|
147
|
+
console.log('\n---\n')
|
|
148
|
+
if (args.format === 'markdown' || args.format === 'both')
|
|
149
|
+
console.log(toMarkdown(report))
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
try {
|
|
153
|
+
main()
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
console.error(error instanceof Error ? error.message : String(error))
|
|
157
|
+
process.exit(1)
|
|
158
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs'
|
|
3
|
+
import os from 'node:os'
|
|
4
|
+
import path from 'node:path'
|
|
5
|
+
import { fileURLToPath } from 'node:url'
|
|
6
|
+
|
|
7
|
+
function parseArgs(argv) {
|
|
8
|
+
const args = { target: '' }
|
|
9
|
+
|
|
10
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
11
|
+
const arg = argv[i]
|
|
12
|
+
if (arg === '--target') {
|
|
13
|
+
args.target = argv[i + 1] || ''
|
|
14
|
+
i += 1
|
|
15
|
+
}
|
|
16
|
+
else if (arg === '--help' || arg === '-h') {
|
|
17
|
+
args.help = true
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
throw new Error(`Unknown argument: ${arg}`)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return args
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function defaultTargetRoot() {
|
|
28
|
+
if (process.env.CODEX_HOME)
|
|
29
|
+
return path.join(process.env.CODEX_HOME, 'skills')
|
|
30
|
+
|
|
31
|
+
return path.join(os.homedir(), '.codex', 'skills')
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function copySkill(sourceDir, targetDir) {
|
|
35
|
+
const source = path.resolve(sourceDir)
|
|
36
|
+
const target = path.resolve(targetDir)
|
|
37
|
+
|
|
38
|
+
if (source === target)
|
|
39
|
+
throw new Error('Source and target are the same directory.')
|
|
40
|
+
|
|
41
|
+
if (target.startsWith(`${source}${path.sep}`))
|
|
42
|
+
throw new Error('Target cannot be inside the source skill directory.')
|
|
43
|
+
|
|
44
|
+
fs.rmSync(target, { recursive: true, force: true })
|
|
45
|
+
fs.mkdirSync(path.dirname(target), { recursive: true })
|
|
46
|
+
fs.cpSync(source, target, {
|
|
47
|
+
recursive: true,
|
|
48
|
+
filter: src => !src.includes(`${path.sep}.DS_Store`),
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function main() {
|
|
53
|
+
const args = parseArgs(process.argv.slice(2))
|
|
54
|
+
if (args.help) {
|
|
55
|
+
console.log('Usage: node scripts/install-codex.mjs [--target <codex-skills-dir>]')
|
|
56
|
+
process.exit(0)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const scriptPath = fileURLToPath(import.meta.url)
|
|
60
|
+
const skillDir = path.resolve(path.dirname(scriptPath), '..')
|
|
61
|
+
const targetRoot = path.resolve(args.target || defaultTargetRoot())
|
|
62
|
+
const targetDir = path.join(targetRoot, path.basename(skillDir))
|
|
63
|
+
|
|
64
|
+
copySkill(skillDir, targetDir)
|
|
65
|
+
console.log(`Installed ${path.basename(skillDir)} to ${targetDir}`)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
main()
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
console.error(error instanceof Error ? error.message : String(error))
|
|
73
|
+
process.exit(1)
|
|
74
|
+
}
|