@zeyue0329/xiaoma-cli 1.20.0 → 1.22.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/package.json +1 -1
- package/src/xmc-skills/2-plan-workflows/xiaoma-prd-clarify/README.md +74 -0
- package/src/xmc-skills/2-plan-workflows/xiaoma-prd-clarify/SKILL.md +58 -0
- package/src/xmc-skills/2-plan-workflows/xiaoma-prd-clarify/examples/example-clarification.md +61 -0
- package/src/xmc-skills/2-plan-workflows/xiaoma-prd-clarify/references/checklist.md +99 -0
- package/src/xmc-skills/2-plan-workflows/xiaoma-prd-clarify/references/output-template.md +73 -0
- package/src/xmc-skills/2-plan-workflows/xiaoma-prd-clarify/references/scoring.md +73 -0
- package/src/xmc-skills/2-plan-workflows/xiaoma-prd-clarify/scripts/export_to_excel.py +156 -0
- package/src/xmc-skills/module-help.csv +1 -0
- package/src/zqyl-skills/backend/components/xiaoma-zqyl-bar-chart-backend/SKILL.md +142 -0
- package/src/zqyl-skills/backend/components/xiaoma-zqyl-button-backend/SKILL.md +108 -0
- package/src/zqyl-skills/backend/components/xiaoma-zqyl-collapse-backend/SKILL.md +142 -0
- package/src/zqyl-skills/backend/components/xiaoma-zqyl-container-foot-backend/SKILL.md +192 -0
- package/src/zqyl-skills/backend/components/xiaoma-zqyl-data-census-backend/SKILL.md +104 -0
- package/src/zqyl-skills/backend/components/xiaoma-zqyl-dialog-backend/SKILL.md +205 -0
- package/src/zqyl-skills/backend/components/xiaoma-zqyl-drawer-backend/SKILL.md +100 -0
- package/src/zqyl-skills/backend/components/xiaoma-zqyl-empty-page-backend/SKILL.md +131 -0
- package/src/zqyl-skills/backend/components/xiaoma-zqyl-file-upload-backend/SKILL.md +291 -0
- package/src/zqyl-skills/backend/components/xiaoma-zqyl-flow-chart-backend/SKILL.md +118 -0
- package/src/zqyl-skills/backend/components/xiaoma-zqyl-form-editor-backend/SKILL.md +315 -0
- package/src/zqyl-skills/backend/components/xiaoma-zqyl-form-view-backend/SKILL.md +165 -0
- package/src/zqyl-skills/backend/components/xiaoma-zqyl-funnel-chart-backend/SKILL.md +102 -0
- package/src/zqyl-skills/backend/components/xiaoma-zqyl-gauge-chart-backend/SKILL.md +103 -0
- package/src/zqyl-skills/backend/components/xiaoma-zqyl-heatmap-chart-backend/SKILL.md +125 -0
- package/src/zqyl-skills/backend/components/xiaoma-zqyl-line-chart-backend/SKILL.md +136 -0
- package/src/zqyl-skills/backend/components/xiaoma-zqyl-map-chart-backend/SKILL.md +130 -0
- package/src/zqyl-skills/backend/components/xiaoma-zqyl-message-feedback-backend/SKILL.md +63 -0
- package/src/zqyl-skills/backend/components/xiaoma-zqyl-module-backend/SKILL.md +180 -0
- package/src/zqyl-skills/backend/components/xiaoma-zqyl-pie-chart-backend/SKILL.md +132 -0
- package/src/zqyl-skills/backend/components/xiaoma-zqyl-popover-backend/SKILL.md +61 -0
- package/src/zqyl-skills/backend/components/xiaoma-zqyl-preview-backend/SKILL.md +117 -0
- package/src/zqyl-skills/backend/components/xiaoma-zqyl-search-form-backend/SKILL.md +239 -0
- package/src/zqyl-skills/backend/components/xiaoma-zqyl-select-tree-backend/SKILL.md +161 -0
- package/src/zqyl-skills/backend/components/xiaoma-zqyl-table-simple-backend/SKILL.md +341 -0
- package/src/zqyl-skills/backend/components/xiaoma-zqyl-tips-backend/SKILL.md +257 -0
- package/src/zqyl-skills/backend/components/xiaoma-zqyl-title-backend/SKILL.md +145 -0
- package/src/zqyl-skills/backend/xiaoma-zqyl-feedback-page-backend/SKILL.md +30 -0
- package/src/zqyl-skills/backend/xiaoma-zqyl-feedback-page-backend/pages/feedbackPage.md +124 -0
- package/src/zqyl-skills/backend/xiaoma-zqyl-form-detail-page-backend/SKILL.md +39 -0
- package/src/zqyl-skills/backend/xiaoma-zqyl-form-detail-page-backend/pages/formDetailPage.md +354 -0
- package/src/zqyl-skills/backend/xiaoma-zqyl-import-dialog-page-backend/SKILL.md +27 -0
- package/src/zqyl-skills/backend/xiaoma-zqyl-import-dialog-page-backend/pages/importDialogPage.md +101 -0
- package/src/zqyl-skills/backend/xiaoma-zqyl-list-page-backend/SKILL.md +31 -0
- package/src/zqyl-skills/backend/xiaoma-zqyl-list-page-backend/pages/listPage.md +306 -0
- package/src/zqyl-skills/front/components/xiaoma-zqyl-bar-chart-front/SKILL.md +142 -0
- package/src/zqyl-skills/front/components/xiaoma-zqyl-button-front/SKILL.md +108 -0
- package/src/zqyl-skills/front/components/xiaoma-zqyl-collapse-front/SKILL.md +142 -0
- package/src/zqyl-skills/front/components/xiaoma-zqyl-container-foot-front/SKILL.md +192 -0
- package/src/zqyl-skills/front/components/xiaoma-zqyl-data-census-front/SKILL.md +104 -0
- package/src/zqyl-skills/front/components/xiaoma-zqyl-dialog-front/SKILL.md +205 -0
- package/src/zqyl-skills/front/components/xiaoma-zqyl-drawer-front/SKILL.md +100 -0
- package/src/zqyl-skills/front/components/xiaoma-zqyl-empty-page-front/SKILL.md +131 -0
- package/src/zqyl-skills/front/components/xiaoma-zqyl-file-upload-front/SKILL.md +291 -0
- package/src/zqyl-skills/front/components/xiaoma-zqyl-flow-chart-front/SKILL.md +118 -0
- package/src/zqyl-skills/front/components/xiaoma-zqyl-form-editor-front/SKILL.md +315 -0
- package/src/zqyl-skills/front/components/xiaoma-zqyl-form-view-front/SKILL.md +165 -0
- package/src/zqyl-skills/front/components/xiaoma-zqyl-funnel-chart-front/SKILL.md +102 -0
- package/src/zqyl-skills/front/components/xiaoma-zqyl-gauge-chart-front/SKILL.md +103 -0
- package/src/zqyl-skills/front/components/xiaoma-zqyl-heatmap-chart-front/SKILL.md +125 -0
- package/src/zqyl-skills/front/components/xiaoma-zqyl-line-chart-front/SKILL.md +136 -0
- package/src/zqyl-skills/front/components/xiaoma-zqyl-map-chart-front/SKILL.md +130 -0
- package/src/zqyl-skills/front/components/xiaoma-zqyl-message-feedback-front/SKILL.md +63 -0
- package/src/zqyl-skills/front/components/xiaoma-zqyl-module-front/SKILL.md +180 -0
- package/src/zqyl-skills/front/components/xiaoma-zqyl-pie-chart-front/SKILL.md +132 -0
- package/src/zqyl-skills/front/components/xiaoma-zqyl-popover-front/SKILL.md +61 -0
- package/src/zqyl-skills/front/components/xiaoma-zqyl-preview-front/SKILL.md +117 -0
- package/src/zqyl-skills/front/components/xiaoma-zqyl-search-form-front/SKILL.md +239 -0
- package/src/zqyl-skills/front/components/xiaoma-zqyl-select-tree-front/SKILL.md +161 -0
- package/src/zqyl-skills/front/components/xiaoma-zqyl-table-simple-front/SKILL.md +341 -0
- package/src/zqyl-skills/front/components/xiaoma-zqyl-tips-front/SKILL.md +257 -0
- package/src/zqyl-skills/front/components/xiaoma-zqyl-title-front/SKILL.md +145 -0
- package/src/zqyl-skills/front/xiaoma-zqyl-feedback-page-front/SKILL.md +30 -0
- package/src/zqyl-skills/front/xiaoma-zqyl-feedback-page-front/pages/feedbackPage.md +124 -0
- package/src/zqyl-skills/front/xiaoma-zqyl-form-detail-page-front/SKILL.md +39 -0
- package/src/zqyl-skills/front/xiaoma-zqyl-form-detail-page-front/pages/formDetailPage.md +351 -0
- package/src/zqyl-skills/front/xiaoma-zqyl-import-dialog-page-front/SKILL.md +27 -0
- package/src/zqyl-skills/front/xiaoma-zqyl-import-dialog-page-front/pages/importDialogPage.md +101 -0
- package/src/zqyl-skills/front/xiaoma-zqyl-list-page-front/SKILL.md +31 -0
- package/src/zqyl-skills/front/xiaoma-zqyl-list-page-front/pages/listPage.md +380 -0
- package/src/zqyl-skills/mid/components/xiaoma-zqyl-bar-chart-mid/SKILL.md +142 -0
- package/src/zqyl-skills/mid/components/xiaoma-zqyl-button-mid/SKILL.md +108 -0
- package/src/zqyl-skills/mid/components/xiaoma-zqyl-collapse-mid/SKILL.md +142 -0
- package/src/zqyl-skills/mid/components/xiaoma-zqyl-container-foot-mid/SKILL.md +192 -0
- package/src/zqyl-skills/mid/components/xiaoma-zqyl-data-census-mid/SKILL.md +104 -0
- package/src/zqyl-skills/mid/components/xiaoma-zqyl-dialog-mid/SKILL.md +205 -0
- package/src/zqyl-skills/mid/components/xiaoma-zqyl-drawer-mid/SKILL.md +100 -0
- package/src/zqyl-skills/mid/components/xiaoma-zqyl-empty-page-mid/SKILL.md +131 -0
- package/src/zqyl-skills/mid/components/xiaoma-zqyl-file-upload-mid/SKILL.md +291 -0
- package/src/zqyl-skills/mid/components/xiaoma-zqyl-flow-chart-mid/SKILL.md +118 -0
- package/src/zqyl-skills/mid/components/xiaoma-zqyl-form-editor-mid/SKILL.md +315 -0
- package/src/zqyl-skills/mid/components/xiaoma-zqyl-form-view-mid/SKILL.md +165 -0
- package/src/zqyl-skills/mid/components/xiaoma-zqyl-funnel-chart-mid/SKILL.md +102 -0
- package/src/zqyl-skills/mid/components/xiaoma-zqyl-gauge-chart-mid/SKILL.md +103 -0
- package/src/zqyl-skills/mid/components/xiaoma-zqyl-heatmap-chart-mid/SKILL.md +125 -0
- package/src/zqyl-skills/mid/components/xiaoma-zqyl-line-chart-mid/SKILL.md +136 -0
- package/src/zqyl-skills/mid/components/xiaoma-zqyl-manager-title-mid/SKILL.md +132 -0
- package/src/zqyl-skills/mid/components/xiaoma-zqyl-map-chart-mid/SKILL.md +130 -0
- package/src/zqyl-skills/mid/components/xiaoma-zqyl-message-feedback-mid/SKILL.md +63 -0
- package/src/zqyl-skills/mid/components/xiaoma-zqyl-module-mid/SKILL.md +180 -0
- package/src/zqyl-skills/mid/components/xiaoma-zqyl-mps-table-mid/SKILL.md +179 -0
- package/src/zqyl-skills/mid/components/xiaoma-zqyl-pie-chart-mid/SKILL.md +132 -0
- package/src/zqyl-skills/mid/components/xiaoma-zqyl-popover-mid/SKILL.md +61 -0
- package/src/zqyl-skills/mid/components/xiaoma-zqyl-preview-mid/SKILL.md +117 -0
- package/src/zqyl-skills/mid/components/xiaoma-zqyl-search-form-mid/SKILL.md +239 -0
- package/src/zqyl-skills/mid/components/xiaoma-zqyl-select-tree-mid/SKILL.md +161 -0
- package/src/zqyl-skills/mid/components/xiaoma-zqyl-table-simple-mid/SKILL.md +341 -0
- package/src/zqyl-skills/mid/components/xiaoma-zqyl-tips-mid/SKILL.md +257 -0
- package/src/zqyl-skills/mid/components/xiaoma-zqyl-title-mid/SKILL.md +145 -0
- package/src/zqyl-skills/mid/xiaoma-zqyl-feedback-page-mid/SKILL.md +30 -0
- package/src/zqyl-skills/mid/xiaoma-zqyl-feedback-page-mid/pages/feedbackPage.md +125 -0
- package/src/zqyl-skills/mid/xiaoma-zqyl-form-detail-page-mid/SKILL.md +39 -0
- package/src/zqyl-skills/mid/xiaoma-zqyl-form-detail-page-mid/pages/formDetailPage.md +357 -0
- package/src/zqyl-skills/mid/xiaoma-zqyl-import-dialog-page-mid/SKILL.md +27 -0
- package/src/zqyl-skills/mid/xiaoma-zqyl-import-dialog-page-mid/pages/importDialogPage.md +102 -0
- package/src/zqyl-skills/mid/xiaoma-zqyl-list-page-mid/SKILL.md +30 -0
- package/src/zqyl-skills/mid/xiaoma-zqyl-list-page-mid/pages/listPage.md +389 -0
- package/src/zqyl-skills/module-help.csv +15 -0
- package/src/zqyl-skills/module.yaml +38 -0
- package/src/zqyl-skills/xiaoma-zqyl-ui-spec/SKILL.md +478 -0
- package/src/zqyl-skills/xiaoma-zqyl-ui-spec/VERSION.md +30 -0
- package/src/zqyl-skills/xiaoma-zqyl-ui-spec/components-index.md +55 -0
- package/src/zqyl-skills/xiaoma-zqyl-ui-spec/design-tokens.md +167 -0
- package/src/zqyl-skills/xiaoma-zqyl-ui-spec/reference.md +385 -0
- package/tools/installer/core/manifest.js +4 -3
- package/tools/installer/list-options.js +2 -2
- package/tools/installer/modules/official-modules.js +15 -47
- package/tools/installer/modules/version-resolver.js +2 -2
- package/tools/installer/project-root.js +12 -9
- package/tools/installer/ui.js +2 -1
- package/tools/validate-zqyl-pack.js +171 -0
|
@@ -2,7 +2,7 @@ const path = require('node:path');
|
|
|
2
2
|
const semver = require('semver');
|
|
3
3
|
const yaml = require('yaml');
|
|
4
4
|
const fs = require('../fs-native');
|
|
5
|
-
const { getExternalModuleCachePath, getModulePath, resolveInstalledModuleYaml } = require('../project-root');
|
|
5
|
+
const { BUILTIN_MODULE_CODES, getExternalModuleCachePath, getModulePath, resolveInstalledModuleYaml } = require('../project-root');
|
|
6
6
|
|
|
7
7
|
const DEFAULT_PARENT_DEPTH = 8;
|
|
8
8
|
|
|
@@ -141,7 +141,7 @@ async function buildSearchRoots(moduleName, moduleSourcePath) {
|
|
|
141
141
|
|
|
142
142
|
await addRoot(moduleSourcePath);
|
|
143
143
|
|
|
144
|
-
if (moduleName
|
|
144
|
+
if (BUILTIN_MODULE_CODES.includes(moduleName)) {
|
|
145
145
|
await addRoot(getModulePath(moduleName));
|
|
146
146
|
} else {
|
|
147
147
|
await addRoot(getExternalModuleCachePath(moduleName));
|
|
@@ -59,20 +59,22 @@ function getSourcePath(...segments) {
|
|
|
59
59
|
return path.join(getProjectRoot(), 'src', ...segments);
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Built-in module codes. Each ships inside this repo as `src/<code>-skills/`
|
|
64
|
+
* and is versioned with the CLI itself; every other code resolves to an
|
|
65
|
+
* external/community/custom source. Single source of truth — the installer,
|
|
66
|
+
* manifest writer, version resolver, and `--list-options` all key off this.
|
|
67
|
+
*/
|
|
68
|
+
const BUILTIN_MODULE_CODES = ['core', 'xmc', 'xpm', 'zqyl'];
|
|
69
|
+
|
|
62
70
|
/**
|
|
63
71
|
* Get path to a module's directory
|
|
64
|
-
*
|
|
72
|
+
* Built-in modules live directly under src/ (as *-skills dirs)
|
|
65
73
|
* All other modules are stored remote
|
|
66
74
|
*/
|
|
67
75
|
function getModulePath(moduleName, ...segments) {
|
|
68
|
-
if (moduleName
|
|
69
|
-
return getSourcePath(
|
|
70
|
-
}
|
|
71
|
-
if (moduleName === 'xmc') {
|
|
72
|
-
return getSourcePath('xmc-skills', ...segments);
|
|
73
|
-
}
|
|
74
|
-
if (moduleName === 'xpm') {
|
|
75
|
-
return getSourcePath('xpm-skills', ...segments);
|
|
76
|
+
if (BUILTIN_MODULE_CODES.includes(moduleName)) {
|
|
77
|
+
return getSourcePath(`${moduleName}-skills`, ...segments);
|
|
76
78
|
}
|
|
77
79
|
return getSourcePath('modules', moduleName, ...segments);
|
|
78
80
|
}
|
|
@@ -221,6 +223,7 @@ async function resolveInstalledModuleYaml(moduleName) {
|
|
|
221
223
|
}
|
|
222
224
|
|
|
223
225
|
module.exports = {
|
|
226
|
+
BUILTIN_MODULE_CODES,
|
|
224
227
|
getProjectRoot,
|
|
225
228
|
getSourcePath,
|
|
226
229
|
getModulePath,
|
package/tools/installer/ui.js
CHANGED
|
@@ -7,6 +7,7 @@ const { CLIUtils } = require('./cli-utils');
|
|
|
7
7
|
const { ExternalModuleManager } = require('./modules/external-manager');
|
|
8
8
|
const { resolveModuleVersion } = require('./modules/version-resolver');
|
|
9
9
|
const { Manifest } = require('./core/manifest');
|
|
10
|
+
const { BUILTIN_MODULE_CODES } = require('./project-root');
|
|
10
11
|
const {
|
|
11
12
|
parseChannelOptions,
|
|
12
13
|
buildPlan,
|
|
@@ -884,7 +885,7 @@ class UI {
|
|
|
884
885
|
// they can be managed via --custom-source, uninstall, or a dedicated installer.
|
|
885
886
|
const externalManager = new ExternalModuleManager();
|
|
886
887
|
const registryModules = await externalManager.listAvailable();
|
|
887
|
-
const officialRegistryCodes = new Set([
|
|
888
|
+
const officialRegistryCodes = new Set([...BUILTIN_MODULE_CODES, ...registryModules.map((m) => m.code)]);
|
|
888
889
|
const installedNonOfficial = [...installedModuleIds].filter((id) => !officialRegistryCodes.has(id));
|
|
889
890
|
|
|
890
891
|
// Phase 2: Custom URL modules
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ZQYL Pack Consistency Validator
|
|
3
|
+
*
|
|
4
|
+
* The zqyl module is the only pack whose skills ship in three near-identical
|
|
5
|
+
* platform variants (backend / mid / front), and whose descriptions carry
|
|
6
|
+
* import-authored text that asserts facts about OTHER files. A multi-agent UAT
|
|
7
|
+
* showed both failure modes are silent: a wrong `platformType` produces the wrong
|
|
8
|
+
* theme with no console error, and a skill reference that does not resolve just
|
|
9
|
+
* makes the agent guess. Neither is caught by validate-skills.js (frontmatter
|
|
10
|
+
* shape) or validate-file-refs.js (path resolution) — skill NAMES are not paths.
|
|
11
|
+
*
|
|
12
|
+
* What it checks:
|
|
13
|
+
* - ZQYL-01: every `xiaoma-zqyl-*` skill name asserted anywhere in the pack resolves
|
|
14
|
+
* to an installed skill directory (placeholder forms are exempt)
|
|
15
|
+
* - ZQYL-02: the `platformType` quoted in a skill's description equals the value in
|
|
16
|
+
* that same skill's body (`- platformType:`x``) — catches invented values
|
|
17
|
+
* - ZQYL-03: frontmatter `name` matches the directory (the manifest generator skips
|
|
18
|
+
* mismatches silently, so the skill would vanish at install time)
|
|
19
|
+
* - ZQYL-04: no unresolved `{平台}` placeholder inside a platform-pinned file
|
|
20
|
+
* - ZQYL-05: components-index.md's availability matrix matches the directories on disk
|
|
21
|
+
*
|
|
22
|
+
* Usage:
|
|
23
|
+
* node tools/validate-zqyl-pack.js # report, exit 0
|
|
24
|
+
* node tools/validate-zqyl-pack.js --strict # exit 1 on any finding
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
const fs = require('node:fs');
|
|
28
|
+
const path = require('node:path');
|
|
29
|
+
const yaml = require('yaml');
|
|
30
|
+
|
|
31
|
+
const PROJECT_ROOT = path.resolve(__dirname, '..');
|
|
32
|
+
const PACK_DIR = path.join(PROJECT_ROOT, 'src', 'zqyl-skills');
|
|
33
|
+
const INDEX_FILE = path.join(PACK_DIR, 'xiaoma-zqyl-ui-spec', 'components-index.md');
|
|
34
|
+
const STRICT = process.argv.includes('--strict');
|
|
35
|
+
|
|
36
|
+
const PLATFORMS = ['backend', 'mid', 'front'];
|
|
37
|
+
const findings = [];
|
|
38
|
+
|
|
39
|
+
function report(rule, file, detail) {
|
|
40
|
+
findings.push({ rule, file: path.relative(PROJECT_ROOT, file), detail });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function walk(dir, onFile) {
|
|
44
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
45
|
+
const full = path.join(dir, entry.name);
|
|
46
|
+
if (entry.isDirectory()) walk(full, onFile);
|
|
47
|
+
else onFile(full);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (!fs.existsSync(PACK_DIR)) {
|
|
52
|
+
console.log('src/zqyl-skills not present — nothing to validate.');
|
|
53
|
+
process.exit(0);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// --- collect skills -------------------------------------------------------
|
|
57
|
+
|
|
58
|
+
const skills = new Map(); // name -> { dir, fm, body }
|
|
59
|
+
walk(PACK_DIR, (file) => {
|
|
60
|
+
if (path.basename(file) !== 'SKILL.md') return;
|
|
61
|
+
const raw = fs.readFileSync(file, 'utf8').replaceAll('\r\n', '\n');
|
|
62
|
+
const match = raw.match(/^---\n([\S\s]*?)\n---\n/);
|
|
63
|
+
if (!match) {
|
|
64
|
+
report('ZQYL-03', file, 'SKILL.md has no frontmatter');
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
let fm;
|
|
68
|
+
try {
|
|
69
|
+
fm = yaml.parse(match[1]);
|
|
70
|
+
} catch (error) {
|
|
71
|
+
report('ZQYL-03', file, `unparseable frontmatter: ${error.message}`);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const dirName = path.basename(path.dirname(file));
|
|
75
|
+
if (!fm || fm.name !== dirName) {
|
|
76
|
+
report('ZQYL-03', file, `frontmatter name "${fm && fm.name}" != directory "${dirName}" — the installer would skip this skill silently`);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
skills.set(fm.name, { dir: path.dirname(file), fm, body: raw.slice(match[0].length) });
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// --- ZQYL-01: asserted skill names resolve --------------------------------
|
|
83
|
+
|
|
84
|
+
walk(PACK_DIR, (file) => {
|
|
85
|
+
if (!file.endsWith('.md')) return;
|
|
86
|
+
const text = fs.readFileSync(file, 'utf8');
|
|
87
|
+
for (const [lineNo, line] of text.split('\n').entries()) {
|
|
88
|
+
for (const m of line.matchAll(/xiaoma-zqyl-[a-z0-9-]+/g)) {
|
|
89
|
+
const name = m[0];
|
|
90
|
+
const after = line.slice(m.index + name.length);
|
|
91
|
+
// `xiaoma-zqyl-{组件 key}-{平台}` and `xiaoma-zqyl-{line,bar}-chart-…` are notation, not claims
|
|
92
|
+
if (after.startsWith('{') || after.startsWith(',')) continue;
|
|
93
|
+
if (skills.has(name)) continue;
|
|
94
|
+
report('ZQYL-01', file, `line ${lineNo + 1}: references "${name}", which is not a skill in this pack`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// --- ZQYL-02: description platformType matches the skill's own body -------
|
|
100
|
+
|
|
101
|
+
for (const [name, { dir, fm, body }] of skills) {
|
|
102
|
+
const claimed = fm.description && fm.description.match(/platformType\s*`([A-Za-z]+)`/);
|
|
103
|
+
if (!claimed) continue;
|
|
104
|
+
const own = body.match(/^-\s*platformType[::]\s*`([A-Za-z]+)`/m);
|
|
105
|
+
if (own && own[1] !== claimed[1]) {
|
|
106
|
+
report(
|
|
107
|
+
'ZQYL-02',
|
|
108
|
+
path.join(dir, 'SKILL.md'),
|
|
109
|
+
`description claims platformType \`${claimed[1]}\` but the body declares \`${own[1]}\` (${name})`,
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// --- ZQYL-04: no {平台} left in a platform-pinned file ---------------------
|
|
115
|
+
|
|
116
|
+
for (const [name, { dir }] of skills) {
|
|
117
|
+
if (!PLATFORMS.some((p) => name.endsWith(`-${p}`))) continue;
|
|
118
|
+
walk(dir, (file) => {
|
|
119
|
+
if (!file.endsWith('.md')) return;
|
|
120
|
+
const text = fs.readFileSync(file, 'utf8');
|
|
121
|
+
for (const [lineNo, line] of text.split('\n').entries()) {
|
|
122
|
+
// only flag placeholders attached to a skill reference; prose notation elsewhere is fine
|
|
123
|
+
if (/xiaoma-zqyl-[a-z0-9-]*-\{平台\}/.test(line)) {
|
|
124
|
+
report('ZQYL-04', file, `line ${lineNo + 1}: unresolved {平台} in "${name}", a skill already pinned to one platform`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// --- ZQYL-05: components-index matrix matches disk ------------------------
|
|
131
|
+
|
|
132
|
+
if (fs.existsSync(INDEX_FILE)) {
|
|
133
|
+
const rows = fs
|
|
134
|
+
.readFileSync(INDEX_FILE, 'utf8')
|
|
135
|
+
.split('\n')
|
|
136
|
+
.filter((l) => /^\|\s*`[a-z-]+`\s*\|/.test(l));
|
|
137
|
+
for (const row of rows) {
|
|
138
|
+
const cells = row.split('|').map((c) => c.trim());
|
|
139
|
+
const key = cells[1].replaceAll('`', '');
|
|
140
|
+
const [b, m, f] = [cells[3], cells[4], cells[5]];
|
|
141
|
+
for (const [platform, cell] of [
|
|
142
|
+
['backend', b],
|
|
143
|
+
['mid', m],
|
|
144
|
+
['front', f],
|
|
145
|
+
]) {
|
|
146
|
+
const claimsAvailable = cell === '✅';
|
|
147
|
+
const exists = skills.has(`xiaoma-zqyl-${key}-${platform}`);
|
|
148
|
+
if (claimsAvailable !== exists) {
|
|
149
|
+
report(
|
|
150
|
+
'ZQYL-05',
|
|
151
|
+
INDEX_FILE,
|
|
152
|
+
`"${key}" is marked ${claimsAvailable ? 'available' : 'unavailable'} on ${platform}, but xiaoma-zqyl-${key}-${platform} ${exists ? 'exists' : 'does not exist'}`,
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
} else {
|
|
158
|
+
report('ZQYL-05', INDEX_FILE, 'components-index.md is missing — the 24 chart skills lose their only entry point');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// --- output ---------------------------------------------------------------
|
|
162
|
+
|
|
163
|
+
console.log(`\nZQYL pack validation: ${skills.size} skills in ${path.relative(PROJECT_ROOT, PACK_DIR)}\n`);
|
|
164
|
+
if (findings.length === 0) {
|
|
165
|
+
console.log(' All checks passed.\n');
|
|
166
|
+
} else {
|
|
167
|
+
for (const f of findings) console.log(` [${f.rule}] ${f.file}\n ${f.detail}`);
|
|
168
|
+
console.log(`\n ${findings.length} finding(s).\n`);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (STRICT && findings.length > 0) process.exit(1);
|