adspecs 0.1.18 → 0.1.20

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.
Files changed (88) hide show
  1. package/.adspecs/extensions/git/commands/adspecs.git.initialize.md +4 -4
  2. package/.adspecs/extensions/git/extension.yml +1 -1
  3. package/.adspecs/extensions/git/git-config.yml +17 -2
  4. package/.adspecs/extensions.yml +32 -0
  5. package/.adspecs/feature.json +16 -16
  6. package/.adspecs/feature.yml +28 -28
  7. package/.adspecs/paths.json +17 -0
  8. package/.adspecs/templates/02-/344/272/247/345/223/201/351/234/200/346/261/202/350/257/264/346/230/216/344/271/246/346/250/241/346/235/277.md +4 -0
  9. package/.adspecs/workflows/adspecs/workflow.yml +5 -4
  10. package/.claude-plugin/marketplace.json +23 -23
  11. package/.claude-plugin/plugin.json +18 -18
  12. package/.qoder-plugin/plugin.json +31 -31
  13. package/CLAUDE.md +1 -5
  14. package/README.md +395 -395
  15. package/bin/adspecs.js +129 -129
  16. package/hooks/commit-queue.js +245 -245
  17. package/hooks/hooks.json +63 -63
  18. package/hooks/session-start.js +44 -44
  19. package/hooks/wiki-queue.js +127 -127
  20. package/package.json +61 -61
  21. package/references/ant6-front-standard/index.md +99 -99
  22. package/references/antd-front-demo/.env.develop +12 -0
  23. package/references/antd-front-demo/.env.production +5 -0
  24. package/references/antd-front-demo/package-lock.json +2 -2
  25. package/references/antd-front-demo/package.json +1 -1
  26. package/references/antd-front-demo/public/mockServiceWorker.js +361 -361
  27. package/references/ecp-end-standard/index.md +63 -63
  28. package/references/python-end-standard/01-Python/345/220/216/347/253/257/347/274/226/347/240/201/350/247/204/350/214/203.md +372 -372
  29. package/references/python-end-standard/02-/346/225/260/346/215/256/345/272/223/350/256/276/350/256/241/344/270/216/344/275/277/347/224/250/350/247/204/350/214/203.md +226 -226
  30. package/references/python-end-standard/03-Celery/345/274/202/346/255/245/344/273/273/345/212/241/350/247/204/350/214/203.md +237 -237
  31. package/references/python-end-standard/04-Redis/344/275/277/347/224/250/350/247/204/350/214/203.md +231 -231
  32. package/scripts/postinstall.js +107 -107
  33. package/scripts/sync-version.js +105 -105
  34. package/skills/.claude/.wiki-update-queue +26 -26
  35. package/skills/adspecs-constitution/SKILL.md +157 -0
  36. package/skills/adspecs-export-word/SKILL.md +498 -498
  37. package/skills/adspecs-export-word/references/md-to-docx.js +862 -862
  38. package/skills/adspecs-export-word/references/package-lock.json +220 -220
  39. package/skills/adspecs-export-word/references/package.json +10 -10
  40. package/skills/adspecs-front-prototype/SKILL.md +405 -0
  41. package/skills/adspecs-git-commit/SKILL.md +23 -8
  42. package/skills/adspecs-git-initialize/SKILL.md +54 -0
  43. package/skills/adspecs-plan/SKILL.md +59 -69
  44. package/skills/adspecs-prd/SKILL.md +13 -5
  45. package/skills/adspecs-prd-to-demo/SKILL.md +532 -0
  46. package/skills/adspecs-tasks/SKILL.md +175 -204
  47. package/skills/adspecs-update-status/SKILL.md +382 -382
  48. package/skills/adspecs-utest/SKILL.md +107 -116
  49. package/skills/grill-me/SKILL.md +7 -0
  50. package/skills/grill-me/agents/openai.yaml +5 -0
  51. package/skills/playwright-cli/SKILL.md +420 -0
  52. package/skills/playwright-cli/references/element-attributes.md +23 -0
  53. package/skills/playwright-cli/references/playwright-tests.md +39 -0
  54. package/skills/playwright-cli/references/request-mocking.md +87 -0
  55. package/skills/playwright-cli/references/running-code.md +241 -0
  56. package/skills/playwright-cli/references/session-management.md +225 -0
  57. package/skills/playwright-cli/references/storage-state.md +275 -0
  58. package/skills/playwright-cli/references/test-generation.md +433 -0
  59. package/skills/playwright-cli/references/tracing.md +139 -0
  60. package/skills/playwright-cli/references/video-recording.md +143 -0
  61. package/skills/playwright-trace/SKILL.md +171 -0
  62. package/skills/project-init/references/front-demo/.claude/settings.local.json +9 -0
  63. package/skills/wiki-update/SKILL.md +232 -232
  64. package/src/commands/doctor.js +197 -197
  65. package/src/commands/init.js +83 -83
  66. package/src/commands/plugin.js +165 -165
  67. package/src/commands/update.js +87 -87
  68. package/src/lib/area-scanner.js +129 -129
  69. package/src/lib/copier.js +104 -104
  70. package/src/lib/dir-utils.js +133 -133
  71. package/src/lib/json-merge.js +114 -114
  72. package/src/lib/paths-defaults.js +37 -37
  73. package/src/lib/prompts.js +347 -345
  74. package/src/lib/readme-gen.js +143 -143
  75. package/src/lib/report.js +327 -327
  76. package/src/lib/scaffolder.js +518 -518
  77. package/src/lib/short-name.js +36 -36
  78. package/src/utils.js +80 -80
  79. package/references/antd-front-demo/.env +0 -15
  80. package/references/antd-front-demo/src/pages/aps/coil/components/CoilDrawer.tsx +0 -141
  81. package/references/antd-front-demo/src/pages/aps/coil/index.tsx +0 -209
  82. package/references/antd-front-demo/src/pages/aps/optimization/index.tsx +0 -192
  83. package/references/antd-front-demo/src/pages/aps/order/components/OrderDrawer.tsx +0 -251
  84. package/references/antd-front-demo/src/pages/aps/order/index.tsx +0 -273
  85. package/references/antd-front-demo/src/pages/aps/param/index.tsx +0 -153
  86. package/references/antd-front-demo/src/pages/aps/plan/components/CuttingPlanVisualization.tsx +0 -821
  87. package/references/antd-front-demo/src/pages/aps/plan/index.tsx +0 -254
  88. package/references/antd-front-demo/src/pages/aps/task/index.tsx +0 -190
@@ -1,129 +1,129 @@
1
- 'use strict';
2
-
3
- const fs = require('fs');
4
- const path = require('path');
5
- const { hasAnyFile } = require('./dir-utils');
6
-
7
- /**
8
- * 区域状态扫描
9
- *
10
- * 按模式扫描目标目录,返回各区域的存在状态,
11
- * 为冲突决策和计划摘要提供数据基础。
12
- */
13
-
14
- /**
15
- * 各区域的目录名映射
16
- */
17
- const AREA_DIRS = {
18
- adspecs: '.adspecs',
19
- docs: 'docs',
20
- wiki: 'wiki',
21
- webUi: 'web-ui',
22
- service: 'service',
23
- frontDemo: 'front-demo',
24
- };
25
-
26
- /**
27
- * 按模式返回需要处理的区域列表
28
- *
29
- * @param {string} mode - 初始化模式
30
- * @returns {string[]} 区域 key 列表
31
- */
32
- function getAreaListForMode(mode) {
33
- switch (mode) {
34
- case 'simple':
35
- return ['adspecs', 'docs', 'wiki'];
36
- case 'classic':
37
- return ['adspecs', 'docs', 'wiki', 'frontDemo'];
38
- case 'full':
39
- case 'demo':
40
- return ['adspecs', 'docs', 'wiki', 'webUi', 'service', 'frontDemo'];
41
- default:
42
- return ['adspecs', 'docs', 'wiki'];
43
- }
44
- }
45
-
46
- /**
47
- * 按模式扫描目标目录,返回各区域存在状态
48
- *
49
- * @param {string} targetDir - 目标项目根目录
50
- * @param {string} mode - 初始化模式
51
- * @returns {object} 区域状态映射 { areaKey: { exists, hasFiles, dirName } }
52
- */
53
- function scanAreaStates(targetDir, mode) {
54
- const areas = getAreaListForMode(mode);
55
- const states = {};
56
-
57
- for (const areaKey of areas) {
58
- const dirName = AREA_DIRS[areaKey];
59
- const fullPath = path.join(targetDir, dirName);
60
- const exists = fs.existsSync(fullPath);
61
-
62
- states[areaKey] = {
63
- exists,
64
- hasFiles: exists ? hasAnyFile(fullPath) : false,
65
- dirName,
66
- };
67
- }
68
-
69
- return states;
70
- }
71
-
72
- /**
73
- * 将区域 key 转换为中文显示名
74
- *
75
- * @param {string} areaKey
76
- * @returns {string}
77
- */
78
- function areaDisplayName(areaKey) {
79
- const names = {
80
- adspecs: '.adspecs',
81
- docs: 'docs',
82
- wiki: 'wiki',
83
- webUi: 'web-ui',
84
- service: 'service',
85
- frontDemo: 'front-demo',
86
- };
87
- return names[areaKey] || areaKey;
88
- }
89
-
90
- /**
91
- * 将决策转换为中文描述
92
- *
93
- * @param {string} decision - create | recreate | update | skip
94
- * @returns {string}
95
- */
96
- function decisionLabel(decision) {
97
- const labels = {
98
- create: '创建',
99
- recreate: '重新创建',
100
- update: '更新',
101
- skip: '跳过',
102
- };
103
- return labels[decision] || decision;
104
- }
105
-
106
- /**
107
- * 将决策转换为状态图标
108
- *
109
- * @param {string} decision
110
- * @returns {string}
111
- */
112
- function decisionIcon(decision) {
113
- const icons = {
114
- create: '✅',
115
- recreate: '🔄',
116
- update: '🔄',
117
- skip: '⏭',
118
- };
119
- return icons[decision] || '❓';
120
- }
121
-
122
- module.exports = {
123
- AREA_DIRS,
124
- getAreaListForMode,
125
- scanAreaStates,
126
- areaDisplayName,
127
- decisionLabel,
128
- decisionIcon,
129
- };
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const { hasAnyFile } = require('./dir-utils');
6
+
7
+ /**
8
+ * 区域状态扫描
9
+ *
10
+ * 按模式扫描目标目录,返回各区域的存在状态,
11
+ * 为冲突决策和计划摘要提供数据基础。
12
+ */
13
+
14
+ /**
15
+ * 各区域的目录名映射
16
+ */
17
+ const AREA_DIRS = {
18
+ adspecs: '.adspecs',
19
+ docs: 'docs',
20
+ wiki: 'wiki',
21
+ webUi: 'web-ui',
22
+ service: 'service',
23
+ frontDemo: 'front-demo',
24
+ };
25
+
26
+ /**
27
+ * 按模式返回需要处理的区域列表
28
+ *
29
+ * @param {string} mode - 初始化模式
30
+ * @returns {string[]} 区域 key 列表
31
+ */
32
+ function getAreaListForMode(mode) {
33
+ switch (mode) {
34
+ case 'simple':
35
+ return ['adspecs', 'docs', 'wiki'];
36
+ case 'classic':
37
+ return ['adspecs', 'docs', 'wiki', 'frontDemo'];
38
+ case 'full':
39
+ case 'demo':
40
+ return ['adspecs', 'docs', 'wiki', 'webUi', 'service', 'frontDemo'];
41
+ default:
42
+ return ['adspecs', 'docs', 'wiki'];
43
+ }
44
+ }
45
+
46
+ /**
47
+ * 按模式扫描目标目录,返回各区域存在状态
48
+ *
49
+ * @param {string} targetDir - 目标项目根目录
50
+ * @param {string} mode - 初始化模式
51
+ * @returns {object} 区域状态映射 { areaKey: { exists, hasFiles, dirName } }
52
+ */
53
+ function scanAreaStates(targetDir, mode) {
54
+ const areas = getAreaListForMode(mode);
55
+ const states = {};
56
+
57
+ for (const areaKey of areas) {
58
+ const dirName = AREA_DIRS[areaKey];
59
+ const fullPath = path.join(targetDir, dirName);
60
+ const exists = fs.existsSync(fullPath);
61
+
62
+ states[areaKey] = {
63
+ exists,
64
+ hasFiles: exists ? hasAnyFile(fullPath) : false,
65
+ dirName,
66
+ };
67
+ }
68
+
69
+ return states;
70
+ }
71
+
72
+ /**
73
+ * 将区域 key 转换为中文显示名
74
+ *
75
+ * @param {string} areaKey
76
+ * @returns {string}
77
+ */
78
+ function areaDisplayName(areaKey) {
79
+ const names = {
80
+ adspecs: '.adspecs',
81
+ docs: 'docs',
82
+ wiki: 'wiki',
83
+ webUi: 'web-ui',
84
+ service: 'service',
85
+ frontDemo: 'front-demo',
86
+ };
87
+ return names[areaKey] || areaKey;
88
+ }
89
+
90
+ /**
91
+ * 将决策转换为中文描述
92
+ *
93
+ * @param {string} decision - create | recreate | update | skip
94
+ * @returns {string}
95
+ */
96
+ function decisionLabel(decision) {
97
+ const labels = {
98
+ create: '创建',
99
+ recreate: '重新创建',
100
+ update: '更新',
101
+ skip: '跳过',
102
+ };
103
+ return labels[decision] || decision;
104
+ }
105
+
106
+ /**
107
+ * 将决策转换为状态图标
108
+ *
109
+ * @param {string} decision
110
+ * @returns {string}
111
+ */
112
+ function decisionIcon(decision) {
113
+ const icons = {
114
+ create: '✅',
115
+ recreate: '🔄',
116
+ update: '🔄',
117
+ skip: '⏭',
118
+ };
119
+ return icons[decision] || '❓';
120
+ }
121
+
122
+ module.exports = {
123
+ AREA_DIRS,
124
+ getAreaListForMode,
125
+ scanAreaStates,
126
+ areaDisplayName,
127
+ decisionLabel,
128
+ decisionIcon,
129
+ };
package/src/lib/copier.js CHANGED
@@ -1,104 +1,104 @@
1
- 'use strict';
2
-
3
- const fs = require('fs');
4
- const path = require('path');
5
-
6
- /**
7
- * 复制过程中需要跳过的目录名
8
- * 这些目录通常不应出现在目标项目中(体积大 / 与版本控制冲突 / 运行时缓存)
9
- */
10
- const EXCLUDED_DIRS = new Set([
11
- 'node_modules',
12
- '.git',
13
- '.vite',
14
- '.venv',
15
- '__pycache__',
16
- '.next',
17
- 'dist',
18
- 'build',
19
- ]);
20
-
21
- /**
22
- * 递归复制目录,过滤掉不需要的大目录
23
- *
24
- * @param {string} src - 源目录绝对路径
25
- * @param {string} dest - 目标目录绝对路径(不存在会自动创建)
26
- * @param {object} [opts] - 选项
27
- * @param {Set<string>} [opts.exclude] - 额外要排除的目录名
28
- * @param {function} [opts.onProgress] - 进度回调 (filePath: string) => void
29
- * @returns {{ fileCount: number, skippedDirs: string[] }} 复制的文件数和被跳过的目录
30
- */
31
- function copyDirFiltered(src, dest, opts = {}) {
32
- const exclude = opts.exclude || new Set();
33
- const onProgress = opts.onProgress || (() => {});
34
- const skippedDirs = [];
35
-
36
- if (!fs.existsSync(src)) {
37
- return { fileCount: 0, skippedDirs };
38
- }
39
-
40
- fs.mkdirSync(dest, { recursive: true });
41
-
42
- let fileCount = 0;
43
-
44
- function _copy(currentSrc, currentDest) {
45
- const entries = fs.readdirSync(currentSrc, { withFileTypes: true });
46
- for (const entry of entries) {
47
- const srcPath = path.join(currentSrc, entry.name);
48
- const destPath = path.join(currentDest, entry.name);
49
-
50
- if (entry.isDirectory()) {
51
- if (EXCLUDED_DIRS.has(entry.name) || exclude.has(entry.name)) {
52
- skippedDirs.push(entry.name);
53
- continue;
54
- }
55
- fs.mkdirSync(destPath, { recursive: true });
56
- _copy(srcPath, destPath);
57
- } else if (entry.isFile()) {
58
- fs.copyFileSync(srcPath, destPath);
59
- onProgress(destPath);
60
- fileCount++;
61
- }
62
- }
63
- }
64
-
65
- _copy(src, dest);
66
- return { fileCount, skippedDirs };
67
- }
68
-
69
- /**
70
- * 删除目录(如果存在)
71
- * @param {string} dirPath - 目录路径
72
- */
73
- function removeDir(dirPath) {
74
- if (fs.existsSync(dirPath)) {
75
- fs.rmSync(dirPath, { recursive: true, force: true });
76
- }
77
- }
78
-
79
- /**
80
- * 统计目录下的文件数量
81
- * @param {string} dirPath - 目录路径
82
- * @returns {number}
83
- */
84
- function countFiles(dirPath) {
85
- if (!fs.existsSync(dirPath)) return 0;
86
- let count = 0;
87
- const entries = fs.readdirSync(dirPath, { withFileTypes: true });
88
- for (const entry of entries) {
89
- const fullPath = path.join(dirPath, entry.name);
90
- if (entry.isDirectory()) {
91
- count += countFiles(fullPath);
92
- } else if (entry.isFile()) {
93
- count++;
94
- }
95
- }
96
- return count;
97
- }
98
-
99
- module.exports = {
100
- copyDirFiltered,
101
- removeDir,
102
- countFiles,
103
- EXCLUDED_DIRS,
104
- };
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ /**
7
+ * 复制过程中需要跳过的目录名
8
+ * 这些目录通常不应出现在目标项目中(体积大 / 与版本控制冲突 / 运行时缓存)
9
+ */
10
+ const EXCLUDED_DIRS = new Set([
11
+ 'node_modules',
12
+ '.git',
13
+ '.vite',
14
+ '.venv',
15
+ '__pycache__',
16
+ '.next',
17
+ 'dist',
18
+ 'build',
19
+ ]);
20
+
21
+ /**
22
+ * 递归复制目录,过滤掉不需要的大目录
23
+ *
24
+ * @param {string} src - 源目录绝对路径
25
+ * @param {string} dest - 目标目录绝对路径(不存在会自动创建)
26
+ * @param {object} [opts] - 选项
27
+ * @param {Set<string>} [opts.exclude] - 额外要排除的目录名
28
+ * @param {function} [opts.onProgress] - 进度回调 (filePath: string) => void
29
+ * @returns {{ fileCount: number, skippedDirs: string[] }} 复制的文件数和被跳过的目录
30
+ */
31
+ function copyDirFiltered(src, dest, opts = {}) {
32
+ const exclude = opts.exclude || new Set();
33
+ const onProgress = opts.onProgress || (() => {});
34
+ const skippedDirs = [];
35
+
36
+ if (!fs.existsSync(src)) {
37
+ return { fileCount: 0, skippedDirs };
38
+ }
39
+
40
+ fs.mkdirSync(dest, { recursive: true });
41
+
42
+ let fileCount = 0;
43
+
44
+ function _copy(currentSrc, currentDest) {
45
+ const entries = fs.readdirSync(currentSrc, { withFileTypes: true });
46
+ for (const entry of entries) {
47
+ const srcPath = path.join(currentSrc, entry.name);
48
+ const destPath = path.join(currentDest, entry.name);
49
+
50
+ if (entry.isDirectory()) {
51
+ if (EXCLUDED_DIRS.has(entry.name) || exclude.has(entry.name)) {
52
+ skippedDirs.push(entry.name);
53
+ continue;
54
+ }
55
+ fs.mkdirSync(destPath, { recursive: true });
56
+ _copy(srcPath, destPath);
57
+ } else if (entry.isFile()) {
58
+ fs.copyFileSync(srcPath, destPath);
59
+ onProgress(destPath);
60
+ fileCount++;
61
+ }
62
+ }
63
+ }
64
+
65
+ _copy(src, dest);
66
+ return { fileCount, skippedDirs };
67
+ }
68
+
69
+ /**
70
+ * 删除目录(如果存在)
71
+ * @param {string} dirPath - 目录路径
72
+ */
73
+ function removeDir(dirPath) {
74
+ if (fs.existsSync(dirPath)) {
75
+ fs.rmSync(dirPath, { recursive: true, force: true });
76
+ }
77
+ }
78
+
79
+ /**
80
+ * 统计目录下的文件数量
81
+ * @param {string} dirPath - 目录路径
82
+ * @returns {number}
83
+ */
84
+ function countFiles(dirPath) {
85
+ if (!fs.existsSync(dirPath)) return 0;
86
+ let count = 0;
87
+ const entries = fs.readdirSync(dirPath, { withFileTypes: true });
88
+ for (const entry of entries) {
89
+ const fullPath = path.join(dirPath, entry.name);
90
+ if (entry.isDirectory()) {
91
+ count += countFiles(fullPath);
92
+ } else if (entry.isFile()) {
93
+ count++;
94
+ }
95
+ }
96
+ return count;
97
+ }
98
+
99
+ module.exports = {
100
+ copyDirFiltered,
101
+ removeDir,
102
+ countFiles,
103
+ EXCLUDED_DIRS,
104
+ };