create-ai-project 1.16.2 → 1.17.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.
Files changed (123) hide show
  1. package/.claude/agents-en/acceptance-test-generator.md +4 -3
  2. package/.claude/agents-en/code-reviewer.md +2 -2
  3. package/.claude/agents-en/code-verifier.md +2 -2
  4. package/.claude/agents-en/design-sync.md +2 -2
  5. package/.claude/agents-en/document-reviewer.md +4 -4
  6. package/.claude/agents-en/integration-test-reviewer.md +2 -2
  7. package/.claude/agents-en/investigator.md +2 -2
  8. package/.claude/agents-en/prd-creator.md +4 -2
  9. package/.claude/agents-en/quality-fixer-frontend.md +7 -5
  10. package/.claude/agents-en/quality-fixer.md +3 -3
  11. package/.claude/agents-en/requirement-analyzer.md +2 -2
  12. package/.claude/agents-en/scope-discoverer.md +2 -2
  13. package/.claude/agents-en/skill-creator.md +2 -2
  14. package/.claude/agents-en/skill-reviewer.md +2 -2
  15. package/.claude/agents-en/solver.md +2 -2
  16. package/.claude/agents-en/task-decomposer.md +2 -2
  17. package/.claude/agents-en/task-executor-frontend.md +3 -3
  18. package/.claude/agents-en/task-executor.md +2 -2
  19. package/.claude/agents-en/technical-designer-frontend.md +17 -6
  20. package/.claude/agents-en/technical-designer.md +2 -2
  21. package/.claude/agents-en/ui-spec-designer.md +115 -0
  22. package/.claude/agents-en/verifier.md +2 -2
  23. package/.claude/agents-en/work-planner.md +2 -2
  24. package/.claude/agents-ja/acceptance-test-generator.md +4 -3
  25. package/.claude/agents-ja/code-reviewer.md +2 -2
  26. package/.claude/agents-ja/code-verifier.md +2 -2
  27. package/.claude/agents-ja/design-sync.md +2 -2
  28. package/.claude/agents-ja/document-reviewer.md +4 -4
  29. package/.claude/agents-ja/integration-test-reviewer.md +2 -2
  30. package/.claude/agents-ja/investigator.md +2 -2
  31. package/.claude/agents-ja/prd-creator.md +4 -2
  32. package/.claude/agents-ja/quality-fixer-frontend.md +7 -5
  33. package/.claude/agents-ja/quality-fixer.md +3 -3
  34. package/.claude/agents-ja/requirement-analyzer.md +2 -2
  35. package/.claude/agents-ja/scope-discoverer.md +2 -2
  36. package/.claude/agents-ja/skill-creator.md +2 -2
  37. package/.claude/agents-ja/skill-reviewer.md +2 -2
  38. package/.claude/agents-ja/solver.md +2 -2
  39. package/.claude/agents-ja/task-decomposer.md +2 -2
  40. package/.claude/agents-ja/task-executor-frontend.md +3 -3
  41. package/.claude/agents-ja/task-executor.md +2 -2
  42. package/.claude/agents-ja/technical-designer-frontend.md +17 -6
  43. package/.claude/agents-ja/technical-designer.md +2 -2
  44. package/.claude/agents-ja/ui-spec-designer.md +115 -0
  45. package/.claude/agents-ja/verifier.md +2 -2
  46. package/.claude/agents-ja/work-planner.md +2 -2
  47. package/.claude/commands-en/add-integration-tests.md +1 -1
  48. package/.claude/commands-en/build.md +55 -19
  49. package/.claude/commands-en/create-skill.md +1 -1
  50. package/.claude/commands-en/design.md +1 -1
  51. package/.claude/commands-en/diagnose.md +2 -2
  52. package/.claude/commands-en/front-build.md +40 -20
  53. package/.claude/commands-en/front-design.md +25 -8
  54. package/.claude/commands-en/front-plan.md +17 -9
  55. package/.claude/commands-en/front-review.md +2 -2
  56. package/.claude/commands-en/implement.md +15 -10
  57. package/.claude/commands-en/project-inject.md +1 -1
  58. package/.claude/commands-en/refine-skill.md +1 -1
  59. package/.claude/commands-en/reverse-engineer.md +3 -3
  60. package/.claude/commands-en/review.md +2 -2
  61. package/.claude/commands-en/sync-skills.md +1 -1
  62. package/.claude/commands-en/update-doc.md +2 -2
  63. package/.claude/commands-ja/add-integration-tests.md +1 -1
  64. package/.claude/commands-ja/build.md +56 -18
  65. package/.claude/commands-ja/create-skill.md +1 -1
  66. package/.claude/commands-ja/design.md +1 -1
  67. package/.claude/commands-ja/diagnose.md +2 -2
  68. package/.claude/commands-ja/front-build.md +41 -21
  69. package/.claude/commands-ja/front-design.md +26 -9
  70. package/.claude/commands-ja/front-plan.md +15 -7
  71. package/.claude/commands-ja/front-review.md +2 -2
  72. package/.claude/commands-ja/implement.md +15 -10
  73. package/.claude/commands-ja/project-inject.md +1 -1
  74. package/.claude/commands-ja/refine-skill.md +1 -1
  75. package/.claude/commands-ja/reverse-engineer.md +3 -3
  76. package/.claude/commands-ja/review.md +2 -2
  77. package/.claude/commands-ja/sync-skills.md +1 -1
  78. package/.claude/commands-ja/update-doc.md +2 -2
  79. package/.claude/skills-en/documentation-criteria/SKILL.md +37 -1
  80. package/.claude/skills-en/documentation-criteria/references/design-template.md +24 -0
  81. package/.claude/skills-en/documentation-criteria/references/prd-template.md +10 -0
  82. package/.claude/skills-en/documentation-criteria/references/ui-spec-template.md +145 -0
  83. package/.claude/skills-en/{frontend/technical-spec → frontend-technical-spec}/SKILL.md +5 -5
  84. package/.claude/skills-en/{frontend/typescript-rules → frontend-typescript-rules}/SKILL.md +1 -1
  85. package/.claude/skills-en/{frontend/typescript-testing → frontend-typescript-testing}/SKILL.md +9 -2
  86. package/.claude/skills-en/frontend-typescript-testing/references/e2e.md +185 -0
  87. package/.claude/skills-en/integration-e2e-testing/SKILL.md +4 -0
  88. package/.claude/skills-en/integration-e2e-testing/references/e2e-design.md +86 -0
  89. package/.claude/skills-en/subagents-orchestration-guide/SKILL.md +44 -22
  90. package/.claude/skills-en/task-analyzer/references/skills-index.yaml +15 -11
  91. package/.claude/skills-en/technical-spec/SKILL.md +5 -4
  92. package/.claude/skills-ja/documentation-criteria/SKILL.md +37 -1
  93. package/.claude/skills-ja/documentation-criteria/references/design-template.md +24 -0
  94. package/.claude/skills-ja/documentation-criteria/references/prd-template.md +10 -0
  95. package/.claude/skills-ja/documentation-criteria/references/ui-spec-template.md +145 -0
  96. package/.claude/skills-ja/{frontend/technical-spec → frontend-technical-spec}/SKILL.md +5 -5
  97. package/.claude/skills-ja/{frontend/typescript-rules → frontend-typescript-rules}/SKILL.md +1 -1
  98. package/.claude/skills-ja/{frontend/typescript-testing → frontend-typescript-testing}/SKILL.md +2 -2
  99. package/.claude/skills-ja/frontend-typescript-testing/references/e2e.md +185 -0
  100. package/.claude/skills-ja/integration-e2e-testing/SKILL.md +4 -0
  101. package/.claude/skills-ja/integration-e2e-testing/references/e2e-design.md +86 -0
  102. package/.claude/skills-ja/subagents-orchestration-guide/SKILL.md +44 -22
  103. package/.claude/skills-ja/task-analyzer/references/skills-index.yaml +15 -11
  104. package/.claude/skills-ja/technical-spec/SKILL.md +5 -4
  105. package/CHANGELOG.md +67 -0
  106. package/CLAUDE.en.md +2 -2
  107. package/CLAUDE.ja.md +2 -2
  108. package/CLAUDE.md +68 -86
  109. package/README.ja.md +10 -7
  110. package/README.md +10 -7
  111. package/bin/create-project.js +76 -75
  112. package/biome.json +5 -8
  113. package/package.json +11 -24
  114. package/scripts/post-setup.js +54 -57
  115. package/scripts/set-language.js +107 -112
  116. package/scripts/setup-project.js +97 -92
  117. package/scripts/show-coverage.js +36 -22
  118. package/scripts/update-project.js +205 -201
  119. package/scripts/utils.js +19 -21
  120. package/tsconfig.json +3 -3
  121. package/vitest.config.mjs +2 -2
  122. package/.tsprunerc +0 -11
  123. package/scripts/check-unused-exports.js +0 -69
@@ -1,49 +1,50 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const fs = require('fs');
4
- const path = require('path');
5
- const readline = require('readline');
6
- const { copyDirectory, removeDirectory, copyFile } = require('./utils');
3
+ import fs from 'node:fs'
4
+ import path from 'node:path'
5
+ import readline from 'node:readline'
6
+ import { fileURLToPath } from 'node:url'
7
+ import { copyDirectory, copyFile, removeDirectory } from './utils.js'
7
8
 
8
- const MANIFEST_FILE = '.create-ai-project.json';
9
- const CLAUDELANG_FILE = '.claudelang';
10
- const SUPPORTED_LANGUAGES = ['ja', 'en'];
9
+ const __dirname = path.dirname(fileURLToPath(import.meta.url))
10
+
11
+ const MANIFEST_FILE = '.create-ai-project.json'
12
+ const CLAUDELANG_FILE = '.claudelang'
13
+ const SUPPORTED_LANGUAGES = ['ja', 'en']
11
14
 
12
15
  // Categories that can be ignored
13
- const VALID_CATEGORIES = ['agents', 'commands', 'skills'];
16
+ const VALID_CATEGORIES = ['agents', 'commands', 'skills']
14
17
 
15
18
  // Directories and files managed by the boilerplate
16
19
  const MANAGED_DIRS = [
17
20
  (lang) => `.claude/agents-${lang}`,
18
21
  (lang) => `.claude/commands-${lang}`,
19
22
  (lang) => `.claude/skills-${lang}`,
20
- ];
23
+ ]
21
24
 
22
- const MANAGED_FILES = [
23
- (lang) => `CLAUDE.${lang}.md`,
24
- ];
25
+ const MANAGED_FILES = [(lang) => `CLAUDE.${lang}.md`]
25
26
 
26
27
  // ---------------------------------------------------------------------------
27
28
  // Helpers
28
29
  // ---------------------------------------------------------------------------
29
30
 
30
31
  function getPackageRoot() {
31
- return path.join(__dirname, '..');
32
+ return path.join(__dirname, '..')
32
33
  }
33
34
 
34
35
  function getPackageVersion() {
35
- const pkg = JSON.parse(fs.readFileSync(path.join(getPackageRoot(), 'package.json'), 'utf8'));
36
- return pkg.version;
36
+ const pkg = JSON.parse(fs.readFileSync(path.join(getPackageRoot(), 'package.json'), 'utf8'))
37
+ return pkg.version
37
38
  }
38
39
 
39
40
  function prompt(question) {
40
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
41
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
41
42
  return new Promise((resolve) => {
42
43
  rl.question(question, (answer) => {
43
- rl.close();
44
- resolve(answer.trim());
45
- });
46
- });
44
+ rl.close()
45
+ resolve(answer.trim())
46
+ })
47
+ })
47
48
  }
48
49
 
49
50
  // ---------------------------------------------------------------------------
@@ -60,25 +61,27 @@ function prompt(question) {
60
61
  */
61
62
  function resolveIgnorePaths(category, name) {
62
63
  if (category === 'CLAUDE.md') {
63
- return SUPPORTED_LANGUAGES.map((lang) => `CLAUDE.${lang}.md`);
64
+ return SUPPORTED_LANGUAGES.map((lang) => `CLAUDE.${lang}.md`)
64
65
  }
65
66
 
66
67
  if (!VALID_CATEGORIES.includes(category)) {
67
- console.error(` Error: unknown category "${category}". Valid: ${VALID_CATEGORIES.join(', ')}, CLAUDE.md`);
68
- process.exit(1);
68
+ console.error(
69
+ ` Error: unknown category "${category}". Valid: ${VALID_CATEGORIES.join(', ')}, CLAUDE.md`
70
+ )
71
+ process.exit(1)
69
72
  }
70
73
 
71
74
  if (!name) {
72
- console.error(` Error: --ignore ${category} requires a resource name.`);
73
- console.error(` Example: --ignore ${category} my-resource`);
74
- process.exit(1);
75
+ console.error(` Error: --ignore ${category} requires a resource name.`)
76
+ console.error(` Example: --ignore ${category} my-resource`)
77
+ process.exit(1)
75
78
  }
76
79
 
77
80
  return SUPPORTED_LANGUAGES.map((lang) => {
78
- const base = `.claude/${category}-${lang}/${name}`;
81
+ const base = `.claude/${category}-${lang}/${name}`
79
82
  // agents and commands are .md files, skills are directories
80
- return category === 'skills' ? base : `${base}.md`;
81
- });
83
+ return category === 'skills' ? base : `${base}.md`
84
+ })
82
85
  }
83
86
 
84
87
  /**
@@ -86,17 +89,17 @@ function resolveIgnorePaths(category, name) {
86
89
  * Stored as "category/name" (e.g., "agents/task-executor") or "CLAUDE.md".
87
90
  */
88
91
  function formatIgnoreId(category, name) {
89
- if (category === 'CLAUDE.md') return 'CLAUDE.md';
90
- return `${category}/${name}`;
92
+ if (category === 'CLAUDE.md') return 'CLAUDE.md'
93
+ return `${category}/${name}`
91
94
  }
92
95
 
93
96
  /**
94
97
  * Parse a stored ignore identifier back to category and name.
95
98
  */
96
99
  function parseIgnoreId(id) {
97
- if (id === 'CLAUDE.md') return { category: 'CLAUDE.md', name: null };
98
- const [category, ...rest] = id.split('/');
99
- return { category, name: rest.join('/') };
100
+ if (id === 'CLAUDE.md') return { category: 'CLAUDE.md', name: null }
101
+ const [category, ...rest] = id.split('/')
102
+ return { category, name: rest.join('/') }
100
103
  }
101
104
 
102
105
  // ---------------------------------------------------------------------------
@@ -104,16 +107,16 @@ function parseIgnoreId(id) {
104
107
  // ---------------------------------------------------------------------------
105
108
 
106
109
  function loadManifest(projectRoot) {
107
- const manifestPath = path.join(projectRoot, MANIFEST_FILE);
110
+ const manifestPath = path.join(projectRoot, MANIFEST_FILE)
108
111
  if (!fs.existsSync(manifestPath)) {
109
- return null;
112
+ return null
110
113
  }
111
- return JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
114
+ return JSON.parse(fs.readFileSync(manifestPath, 'utf8'))
112
115
  }
113
116
 
114
117
  function saveManifest(projectRoot, manifest) {
115
- const manifestPath = path.join(projectRoot, MANIFEST_FILE);
116
- fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n');
118
+ const manifestPath = path.join(projectRoot, MANIFEST_FILE)
119
+ fs.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`)
117
120
  }
118
121
 
119
122
  // ---------------------------------------------------------------------------
@@ -121,33 +124,35 @@ function saveManifest(projectRoot, manifest) {
121
124
  // ---------------------------------------------------------------------------
122
125
 
123
126
  function detectLanguage(projectRoot) {
124
- const langPath = path.join(projectRoot, CLAUDELANG_FILE);
127
+ const langPath = path.join(projectRoot, CLAUDELANG_FILE)
125
128
  if (fs.existsSync(langPath)) {
126
129
  try {
127
- const config = JSON.parse(fs.readFileSync(langPath, 'utf8'));
130
+ const config = JSON.parse(fs.readFileSync(langPath, 'utf8'))
128
131
  if (SUPPORTED_LANGUAGES.includes(config.current)) {
129
- return config.current;
132
+ return config.current
130
133
  }
131
134
  } catch {
132
135
  // fall through to interactive prompt
133
136
  }
134
137
  }
135
- return null;
138
+ return null
136
139
  }
137
140
 
138
141
  async function resolveLanguage(projectRoot) {
139
- const detected = detectLanguage(projectRoot);
142
+ const detected = detectLanguage(projectRoot)
140
143
  if (detected) {
141
- console.log(` Detected language from .claudelang: ${detected}`);
142
- return detected;
144
+ console.log(` Detected language from .claudelang: ${detected}`)
145
+ return detected
143
146
  }
144
147
 
145
- const answer = await prompt(' Select language (ja/en): ');
148
+ const answer = await prompt(' Select language (ja/en): ')
146
149
  if (!SUPPORTED_LANGUAGES.includes(answer)) {
147
- console.error(` Error: unsupported language "${answer}". Supported: ${SUPPORTED_LANGUAGES.join(', ')}`);
148
- process.exit(1);
150
+ console.error(
151
+ ` Error: unsupported language "${answer}". Supported: ${SUPPORTED_LANGUAGES.join(', ')}`
152
+ )
153
+ process.exit(1)
149
154
  }
150
- return answer;
155
+ return answer
151
156
  }
152
157
 
153
158
  // ---------------------------------------------------------------------------
@@ -155,19 +160,19 @@ async function resolveLanguage(projectRoot) {
155
160
  // ---------------------------------------------------------------------------
156
161
 
157
162
  async function initManifest(projectRoot) {
158
- console.log('\n .create-ai-project.json not found. Initializing...\n');
159
- const language = await resolveLanguage(projectRoot);
163
+ console.log('\n .create-ai-project.json not found. Initializing...\n')
164
+ const language = await resolveLanguage(projectRoot)
160
165
 
161
166
  const manifest = {
162
167
  version: 'unknown',
163
168
  language,
164
169
  ignored: [],
165
170
  updatedAt: new Date().toISOString(),
166
- };
171
+ }
167
172
 
168
- saveManifest(projectRoot, manifest);
169
- console.log(` Created ${MANIFEST_FILE} (version: unknown)\n`);
170
- return manifest;
173
+ saveManifest(projectRoot, manifest)
174
+ console.log(` Created ${MANIFEST_FILE} (version: unknown)\n`)
175
+ return manifest
171
176
  }
172
177
 
173
178
  // ---------------------------------------------------------------------------
@@ -175,41 +180,41 @@ async function initManifest(projectRoot) {
175
180
  // ---------------------------------------------------------------------------
176
181
 
177
182
  function addIgnore(projectRoot, category, name) {
178
- const manifest = loadManifest(projectRoot);
183
+ const manifest = loadManifest(projectRoot)
179
184
  if (!manifest) {
180
- console.error(` Error: ${MANIFEST_FILE} not found. Run "npx create-ai-project update" first.`);
181
- process.exit(1);
185
+ console.error(` Error: ${MANIFEST_FILE} not found. Run "npx create-ai-project update" first.`)
186
+ process.exit(1)
182
187
  }
183
188
 
184
189
  // Validate the identifier resolves to real paths
185
- resolveIgnorePaths(category, name);
190
+ resolveIgnorePaths(category, name)
186
191
 
187
- const id = formatIgnoreId(category, name);
192
+ const id = formatIgnoreId(category, name)
188
193
  if (manifest.ignored.includes(id)) {
189
- console.log(` Already ignored: ${id}`);
190
- return;
194
+ console.log(` Already ignored: ${id}`)
195
+ return
191
196
  }
192
- manifest.ignored.push(id);
193
- saveManifest(projectRoot, manifest);
194
- console.log(` Added to ignore list: ${id}`);
197
+ manifest.ignored.push(id)
198
+ saveManifest(projectRoot, manifest)
199
+ console.log(` Added to ignore list: ${id}`)
195
200
  }
196
201
 
197
202
  function removeIgnore(projectRoot, category, name) {
198
- const manifest = loadManifest(projectRoot);
203
+ const manifest = loadManifest(projectRoot)
199
204
  if (!manifest) {
200
- console.error(` Error: ${MANIFEST_FILE} not found. Run "npx create-ai-project update" first.`);
201
- process.exit(1);
205
+ console.error(` Error: ${MANIFEST_FILE} not found. Run "npx create-ai-project update" first.`)
206
+ process.exit(1)
202
207
  }
203
208
 
204
- const id = formatIgnoreId(category, name);
205
- const idx = manifest.ignored.indexOf(id);
209
+ const id = formatIgnoreId(category, name)
210
+ const idx = manifest.ignored.indexOf(id)
206
211
  if (idx === -1) {
207
- console.log(` Not in ignore list: ${id}`);
208
- return;
212
+ console.log(` Not in ignore list: ${id}`)
213
+ return
209
214
  }
210
- manifest.ignored.splice(idx, 1);
211
- saveManifest(projectRoot, manifest);
212
- console.log(` Removed from ignore list: ${id}`);
215
+ manifest.ignored.splice(idx, 1)
216
+ saveManifest(projectRoot, manifest)
217
+ console.log(` Removed from ignore list: ${id}`)
213
218
  }
214
219
 
215
220
  // ---------------------------------------------------------------------------
@@ -217,12 +222,12 @@ function removeIgnore(projectRoot, category, name) {
217
222
  // ---------------------------------------------------------------------------
218
223
 
219
224
  function resolveAllIgnoredPaths(ignoredIds) {
220
- const paths = [];
225
+ const paths = []
221
226
  for (const id of ignoredIds) {
222
- const { category, name } = parseIgnoreId(id);
223
- paths.push(...resolveIgnorePaths(category, name));
227
+ const { category, name } = parseIgnoreId(id)
228
+ paths.push(...resolveIgnorePaths(category, name))
224
229
  }
225
- return paths;
230
+ return paths
226
231
  }
227
232
 
228
233
  // ---------------------------------------------------------------------------
@@ -230,39 +235,39 @@ function resolveAllIgnoredPaths(ignoredIds) {
230
235
  // ---------------------------------------------------------------------------
231
236
 
232
237
  function backupIgnored(projectRoot, ignoredPaths) {
233
- const backups = [];
238
+ const backups = []
234
239
  for (const rel of ignoredPaths) {
235
- const abs = path.join(projectRoot, rel);
236
- if (!fs.existsSync(abs)) continue;
240
+ const abs = path.join(projectRoot, rel)
241
+ if (!fs.existsSync(abs)) continue
237
242
 
238
- const stat = fs.statSync(abs);
239
- const tmpDir = path.join(projectRoot, 'tmp', '.update-backup');
240
- const tmpPath = path.join(tmpDir, rel);
243
+ const stat = fs.statSync(abs)
244
+ const tmpDir = path.join(projectRoot, 'tmp', '.update-backup')
245
+ const tmpPath = path.join(tmpDir, rel)
241
246
 
242
247
  if (stat.isDirectory()) {
243
- copyDirectory(abs, tmpPath);
248
+ copyDirectory(abs, tmpPath)
244
249
  } else {
245
- copyFile(abs, tmpPath);
250
+ copyFile(abs, tmpPath)
246
251
  }
247
- backups.push({ rel, tmpPath, isDir: stat.isDirectory() });
252
+ backups.push({ rel, tmpPath, isDir: stat.isDirectory() })
248
253
  }
249
- return backups;
254
+ return backups
250
255
  }
251
256
 
252
257
  function restoreIgnored(projectRoot, backups) {
253
258
  for (const { rel, tmpPath, isDir } of backups) {
254
- const abs = path.join(projectRoot, rel);
259
+ const abs = path.join(projectRoot, rel)
255
260
  if (isDir) {
256
- removeDirectory(abs);
257
- copyDirectory(tmpPath, abs);
261
+ removeDirectory(abs)
262
+ copyDirectory(tmpPath, abs)
258
263
  } else {
259
- copyFile(tmpPath, abs);
264
+ copyFile(tmpPath, abs)
260
265
  }
261
266
  }
262
267
 
263
268
  // Clean up backup directory
264
- const tmpDir = path.join(projectRoot, 'tmp', '.update-backup');
265
- removeDirectory(tmpDir);
269
+ const tmpDir = path.join(projectRoot, 'tmp', '.update-backup')
270
+ removeDirectory(tmpDir)
266
271
  }
267
272
 
268
273
  // ---------------------------------------------------------------------------
@@ -270,16 +275,16 @@ function restoreIgnored(projectRoot, backups) {
270
275
  // ---------------------------------------------------------------------------
271
276
 
272
277
  function getManagedPaths() {
273
- const paths = { dirs: [], files: [] };
278
+ const paths = { dirs: [], files: [] }
274
279
  for (const lang of SUPPORTED_LANGUAGES) {
275
280
  for (const dirFn of MANAGED_DIRS) {
276
- paths.dirs.push(dirFn(lang));
281
+ paths.dirs.push(dirFn(lang))
277
282
  }
278
283
  for (const fileFn of MANAGED_FILES) {
279
- paths.files.push(fileFn(lang));
284
+ paths.files.push(fileFn(lang))
280
285
  }
281
286
  }
282
- return paths;
287
+ return paths
283
288
  }
284
289
 
285
290
  // ---------------------------------------------------------------------------
@@ -287,110 +292,109 @@ function getManagedPaths() {
287
292
  // ---------------------------------------------------------------------------
288
293
 
289
294
  function showChangelog(packageRoot) {
290
- const changelogPath = path.join(packageRoot, 'CHANGELOG.md');
295
+ const changelogPath = path.join(packageRoot, 'CHANGELOG.md')
291
296
  if (!fs.existsSync(changelogPath)) {
292
- return;
297
+ return
293
298
  }
294
- const content = fs.readFileSync(changelogPath, 'utf8');
295
- console.log(' ---- CHANGELOG ----');
299
+ const content = fs.readFileSync(changelogPath, 'utf8')
300
+ console.log(' ---- CHANGELOG ----')
296
301
  // Show first 40 lines to keep it concise
297
- const lines = content.split('\n').slice(0, 40);
302
+ const lines = content.split('\n').slice(0, 40)
298
303
  for (const line of lines) {
299
- console.log(` ${line}`);
304
+ console.log(` ${line}`)
300
305
  }
301
306
  if (content.split('\n').length > 40) {
302
- console.log(' ... (truncated)');
307
+ console.log(' ... (truncated)')
303
308
  }
304
- console.log(' --------------------\n');
309
+ console.log(' --------------------\n')
305
310
  }
306
311
 
307
312
  // ---------------------------------------------------------------------------
308
313
  // Update execution
309
314
  // ---------------------------------------------------------------------------
310
315
 
311
- function performUpdate(packageRoot, projectRoot, manifest, dryRun) {
312
- const managed = getManagedPaths();
313
- const ignoredIds = manifest.ignored || [];
314
- const ignoredPaths = resolveAllIgnoredPaths(ignoredIds);
316
+ async function performUpdate(packageRoot, projectRoot, manifest, dryRun) {
317
+ const managed = getManagedPaths()
318
+ const ignoredIds = manifest.ignored || []
319
+ const ignoredPaths = resolveAllIgnoredPaths(ignoredIds)
315
320
 
316
321
  if (ignoredIds.length > 0) {
317
- console.log(' The following are ignored and will be preserved:');
322
+ console.log(' The following are ignored and will be preserved:')
318
323
  for (const id of ignoredIds) {
319
- console.log(` - ${id}`);
324
+ console.log(` - ${id}`)
320
325
  }
321
- console.log(' Warning: version mismatch may occur for ignored resources.\n');
326
+ console.log(' Warning: version mismatch may occur for ignored resources.\n')
322
327
  }
323
328
 
324
329
  if (dryRun) {
325
- console.log(' [dry-run] The following would be updated:\n');
330
+ console.log(' [dry-run] The following would be updated:\n')
326
331
  for (const dir of managed.dirs) {
327
- const dst = path.join(projectRoot, dir);
328
- const dstExists = fs.existsSync(dst);
329
- console.log(` ${dstExists ? 'UPDATE' : 'SKIP '} ${dir}/`);
332
+ const dst = path.join(projectRoot, dir)
333
+ const dstExists = fs.existsSync(dst)
334
+ console.log(` ${dstExists ? 'UPDATE' : 'SKIP '} ${dir}/`)
330
335
  }
331
336
  for (const file of managed.files) {
332
- const dst = path.join(projectRoot, file);
333
- const dstExists = fs.existsSync(dst);
334
- console.log(` ${dstExists ? 'UPDATE' : 'SKIP '} ${file}`);
337
+ const dst = path.join(projectRoot, file)
338
+ const dstExists = fs.existsSync(dst)
339
+ console.log(` ${dstExists ? 'UPDATE' : 'SKIP '} ${file}`)
335
340
  }
336
- console.log('\n No changes were made (dry-run).');
337
- return;
341
+ console.log('\n No changes were made (dry-run).')
342
+ return
338
343
  }
339
344
 
340
345
  // 1. Backup ignored paths
341
- const backups = backupIgnored(projectRoot, ignoredPaths);
346
+ const backups = backupIgnored(projectRoot, ignoredPaths)
342
347
 
343
348
  // 2. Replace managed directories (only if target directory exists)
344
349
  for (const dir of managed.dirs) {
345
- const src = path.join(packageRoot, dir);
346
- const dst = path.join(projectRoot, dir);
347
- if (!fs.existsSync(src)) continue;
350
+ const src = path.join(packageRoot, dir)
351
+ const dst = path.join(projectRoot, dir)
352
+ if (!fs.existsSync(src)) continue
348
353
  if (!fs.existsSync(dst)) {
349
- console.log(` Skipped ${dir}/ (not present in project)`);
350
- continue;
354
+ console.log(` Skipped ${dir}/ (not present in project)`)
355
+ continue
351
356
  }
352
357
 
353
- removeDirectory(dst);
354
- copyDirectory(src, dst);
355
- console.log(` Updated ${dir}/`);
358
+ removeDirectory(dst)
359
+ copyDirectory(src, dst)
360
+ console.log(` Updated ${dir}/`)
356
361
  }
357
362
 
358
363
  // 3. Replace managed files (only if target file exists)
359
364
  for (const file of managed.files) {
360
- const src = path.join(packageRoot, file);
361
- const dst = path.join(projectRoot, file);
362
- if (!fs.existsSync(src)) continue;
365
+ const src = path.join(packageRoot, file)
366
+ const dst = path.join(projectRoot, file)
367
+ if (!fs.existsSync(src)) continue
363
368
  if (!fs.existsSync(dst)) {
364
- console.log(` Skipped ${file} (not present in project)`);
365
- continue;
369
+ console.log(` Skipped ${file} (not present in project)`)
370
+ continue
366
371
  }
367
372
 
368
- copyFile(src, dst);
369
- console.log(` Updated ${file}`);
373
+ copyFile(src, dst)
374
+ console.log(` Updated ${file}`)
370
375
  }
371
376
 
372
377
  // 4. Restore ignored paths
373
378
  if (backups.length > 0) {
374
- restoreIgnored(projectRoot, backups);
375
- console.log(' Restored ignored resources.');
379
+ restoreIgnored(projectRoot, backups)
380
+ console.log(' Restored ignored resources.')
376
381
  }
377
382
 
378
383
  // 5. Re-run set-language to regenerate active directories
379
- // Use the package's set-language.js (not the project's) to ensure latest version
380
- const language = manifest.language;
381
- const { switchLanguage } = require('./set-language');
382
- const originalCwd = process.cwd();
383
- process.chdir(projectRoot);
384
- switchLanguage(language);
385
- process.chdir(originalCwd);
386
- console.log(` Regenerated active directories for language: ${language}`);
384
+ const language = manifest.language
385
+ const { switchLanguage } = await import('./set-language.js')
386
+ const originalCwd = process.cwd()
387
+ process.chdir(projectRoot)
388
+ switchLanguage(language)
389
+ process.chdir(originalCwd)
390
+ console.log(` Regenerated active directories for language: ${language}`)
387
391
 
388
392
  // 6. Update manifest
389
- const newVersion = getPackageVersion();
390
- manifest.version = newVersion;
391
- manifest.updatedAt = new Date().toISOString();
392
- saveManifest(projectRoot, manifest);
393
- console.log(` Manifest updated to version ${newVersion}.`);
393
+ const newVersion = getPackageVersion()
394
+ manifest.version = newVersion
395
+ manifest.updatedAt = new Date().toISOString()
396
+ saveManifest(projectRoot, manifest)
397
+ console.log(` Manifest updated to version ${newVersion}.`)
394
398
  }
395
399
 
396
400
  // ---------------------------------------------------------------------------
@@ -398,84 +402,84 @@ function performUpdate(packageRoot, projectRoot, manifest, dryRun) {
398
402
  // ---------------------------------------------------------------------------
399
403
 
400
404
  async function main() {
401
- const args = process.argv.slice(2);
402
- const projectRoot = process.cwd();
403
- const packageRoot = getPackageRoot();
404
- const packageVersion = getPackageVersion();
405
+ const args = process.argv.slice(2)
406
+ const projectRoot = process.cwd()
407
+ const packageRoot = getPackageRoot()
408
+ const packageVersion = getPackageVersion()
405
409
 
406
410
  // Handle --ignore <category> [name]
407
411
  if (args.includes('--ignore')) {
408
- const idx = args.indexOf('--ignore');
409
- const category = args[idx + 1];
410
- const name = args[idx + 2]; // undefined for CLAUDE.md (no name needed)
412
+ const idx = args.indexOf('--ignore')
413
+ const category = args[idx + 1]
414
+ const name = args[idx + 2] // undefined for CLAUDE.md (no name needed)
411
415
  if (!category) {
412
- console.error(' Error: --ignore requires a category.');
413
- console.error(' Usage: --ignore agents <name>');
414
- console.error(' --ignore commands <name>');
415
- console.error(' --ignore skills <name>');
416
- console.error(' --ignore CLAUDE.md');
417
- process.exit(1);
416
+ console.error(' Error: --ignore requires a category.')
417
+ console.error(' Usage: --ignore agents <name>')
418
+ console.error(' --ignore commands <name>')
419
+ console.error(' --ignore skills <name>')
420
+ console.error(' --ignore CLAUDE.md')
421
+ process.exit(1)
418
422
  }
419
- addIgnore(projectRoot, category, name);
420
- return;
423
+ addIgnore(projectRoot, category, name)
424
+ return
421
425
  }
422
426
 
423
427
  // Handle --unignore <category> [name]
424
428
  if (args.includes('--unignore')) {
425
- const idx = args.indexOf('--unignore');
426
- const category = args[idx + 1];
427
- const name = args[idx + 2];
429
+ const idx = args.indexOf('--unignore')
430
+ const category = args[idx + 1]
431
+ const name = args[idx + 2]
428
432
  if (!category) {
429
- console.error(' Error: --unignore requires a category.');
430
- console.error(' Usage: --unignore agents <name>');
431
- console.error(' --unignore commands <name>');
432
- console.error(' --unignore skills <name>');
433
- console.error(' --unignore CLAUDE.md');
434
- process.exit(1);
433
+ console.error(' Error: --unignore requires a category.')
434
+ console.error(' Usage: --unignore agents <name>')
435
+ console.error(' --unignore commands <name>')
436
+ console.error(' --unignore skills <name>')
437
+ console.error(' --unignore CLAUDE.md')
438
+ process.exit(1)
435
439
  }
436
- removeIgnore(projectRoot, category, name);
437
- return;
440
+ removeIgnore(projectRoot, category, name)
441
+ return
438
442
  }
439
443
 
440
- const dryRun = args.includes('--dry-run');
444
+ const dryRun = args.includes('--dry-run')
441
445
 
442
- console.log('\n create-ai-project update');
443
- console.log(` Package version: ${packageVersion}\n`);
446
+ console.log('\n create-ai-project update')
447
+ console.log(` Package version: ${packageVersion}\n`)
444
448
 
445
449
  // Load or initialize manifest
446
- let manifest = loadManifest(projectRoot);
450
+ let manifest = loadManifest(projectRoot)
447
451
  if (!manifest) {
448
- manifest = await initManifest(projectRoot);
452
+ manifest = await initManifest(projectRoot)
449
453
  }
450
454
 
451
- const currentVersion = manifest.version;
452
- console.log(` Current project version: ${currentVersion}`);
453
- console.log(` Latest package version: ${packageVersion}\n`);
455
+ const currentVersion = manifest.version
456
+ console.log(` Current project version: ${currentVersion}`)
457
+ console.log(` Latest package version: ${packageVersion}\n`)
454
458
 
455
459
  if (currentVersion === packageVersion) {
456
- console.log(' Already up to date. No changes needed.\n');
457
- return;
460
+ console.log(' Already up to date. No changes needed.\n')
461
+ return
458
462
  }
459
463
 
460
464
  // Show changelog
461
- showChangelog(packageRoot);
465
+ showChangelog(packageRoot)
462
466
 
463
467
  // Confirm update
464
468
  if (!dryRun) {
465
- const answer = await prompt(' Apply update? (y/N): ');
469
+ const answer = await prompt(' Apply update? (y/N): ')
466
470
  if (answer.toLowerCase() !== 'y') {
467
- console.log(' Update cancelled.\n');
468
- return;
471
+ console.log(' Update cancelled.\n')
472
+ return
469
473
  }
470
- console.log();
474
+ console.log()
471
475
  }
472
476
 
473
- performUpdate(packageRoot, projectRoot, manifest, dryRun);
477
+ await performUpdate(packageRoot, projectRoot, manifest, dryRun)
474
478
 
475
- console.log('\n Update complete.\n');
479
+ console.log('\n Update complete.\n')
476
480
  }
477
481
 
478
482
  main().catch((err) => {
479
- console.error(` Error: ${err.message}`);
480
- process.exit(1);
481
- });
483
+ console.error(` Error: ${err.message}`)
484
+ process.exit(1)
485
+ })