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.
- package/.claude/agents-en/acceptance-test-generator.md +4 -3
- package/.claude/agents-en/code-reviewer.md +2 -2
- package/.claude/agents-en/code-verifier.md +2 -2
- package/.claude/agents-en/design-sync.md +2 -2
- package/.claude/agents-en/document-reviewer.md +4 -4
- package/.claude/agents-en/integration-test-reviewer.md +2 -2
- package/.claude/agents-en/investigator.md +2 -2
- package/.claude/agents-en/prd-creator.md +4 -2
- package/.claude/agents-en/quality-fixer-frontend.md +7 -5
- package/.claude/agents-en/quality-fixer.md +3 -3
- package/.claude/agents-en/requirement-analyzer.md +2 -2
- package/.claude/agents-en/scope-discoverer.md +2 -2
- package/.claude/agents-en/skill-creator.md +2 -2
- package/.claude/agents-en/skill-reviewer.md +2 -2
- package/.claude/agents-en/solver.md +2 -2
- package/.claude/agents-en/task-decomposer.md +2 -2
- package/.claude/agents-en/task-executor-frontend.md +3 -3
- package/.claude/agents-en/task-executor.md +2 -2
- package/.claude/agents-en/technical-designer-frontend.md +17 -6
- package/.claude/agents-en/technical-designer.md +2 -2
- package/.claude/agents-en/ui-spec-designer.md +115 -0
- package/.claude/agents-en/verifier.md +2 -2
- package/.claude/agents-en/work-planner.md +2 -2
- package/.claude/agents-ja/acceptance-test-generator.md +4 -3
- package/.claude/agents-ja/code-reviewer.md +2 -2
- package/.claude/agents-ja/code-verifier.md +2 -2
- package/.claude/agents-ja/design-sync.md +2 -2
- package/.claude/agents-ja/document-reviewer.md +4 -4
- package/.claude/agents-ja/integration-test-reviewer.md +2 -2
- package/.claude/agents-ja/investigator.md +2 -2
- package/.claude/agents-ja/prd-creator.md +4 -2
- package/.claude/agents-ja/quality-fixer-frontend.md +7 -5
- package/.claude/agents-ja/quality-fixer.md +3 -3
- package/.claude/agents-ja/requirement-analyzer.md +2 -2
- package/.claude/agents-ja/scope-discoverer.md +2 -2
- package/.claude/agents-ja/skill-creator.md +2 -2
- package/.claude/agents-ja/skill-reviewer.md +2 -2
- package/.claude/agents-ja/solver.md +2 -2
- package/.claude/agents-ja/task-decomposer.md +2 -2
- package/.claude/agents-ja/task-executor-frontend.md +3 -3
- package/.claude/agents-ja/task-executor.md +2 -2
- package/.claude/agents-ja/technical-designer-frontend.md +17 -6
- package/.claude/agents-ja/technical-designer.md +2 -2
- package/.claude/agents-ja/ui-spec-designer.md +115 -0
- package/.claude/agents-ja/verifier.md +2 -2
- package/.claude/agents-ja/work-planner.md +2 -2
- package/.claude/commands-en/add-integration-tests.md +1 -1
- package/.claude/commands-en/build.md +55 -19
- package/.claude/commands-en/create-skill.md +1 -1
- package/.claude/commands-en/design.md +1 -1
- package/.claude/commands-en/diagnose.md +2 -2
- package/.claude/commands-en/front-build.md +40 -20
- package/.claude/commands-en/front-design.md +25 -8
- package/.claude/commands-en/front-plan.md +17 -9
- package/.claude/commands-en/front-review.md +2 -2
- package/.claude/commands-en/implement.md +15 -10
- package/.claude/commands-en/project-inject.md +1 -1
- package/.claude/commands-en/refine-skill.md +1 -1
- package/.claude/commands-en/reverse-engineer.md +3 -3
- package/.claude/commands-en/review.md +2 -2
- package/.claude/commands-en/sync-skills.md +1 -1
- package/.claude/commands-en/update-doc.md +2 -2
- package/.claude/commands-ja/add-integration-tests.md +1 -1
- package/.claude/commands-ja/build.md +56 -18
- package/.claude/commands-ja/create-skill.md +1 -1
- package/.claude/commands-ja/design.md +1 -1
- package/.claude/commands-ja/diagnose.md +2 -2
- package/.claude/commands-ja/front-build.md +41 -21
- package/.claude/commands-ja/front-design.md +26 -9
- package/.claude/commands-ja/front-plan.md +15 -7
- package/.claude/commands-ja/front-review.md +2 -2
- package/.claude/commands-ja/implement.md +15 -10
- package/.claude/commands-ja/project-inject.md +1 -1
- package/.claude/commands-ja/refine-skill.md +1 -1
- package/.claude/commands-ja/reverse-engineer.md +3 -3
- package/.claude/commands-ja/review.md +2 -2
- package/.claude/commands-ja/sync-skills.md +1 -1
- package/.claude/commands-ja/update-doc.md +2 -2
- package/.claude/skills-en/documentation-criteria/SKILL.md +37 -1
- package/.claude/skills-en/documentation-criteria/references/design-template.md +24 -0
- package/.claude/skills-en/documentation-criteria/references/prd-template.md +10 -0
- package/.claude/skills-en/documentation-criteria/references/ui-spec-template.md +145 -0
- package/.claude/skills-en/{frontend/technical-spec → frontend-technical-spec}/SKILL.md +5 -5
- package/.claude/skills-en/{frontend/typescript-rules → frontend-typescript-rules}/SKILL.md +1 -1
- package/.claude/skills-en/{frontend/typescript-testing → frontend-typescript-testing}/SKILL.md +9 -2
- package/.claude/skills-en/frontend-typescript-testing/references/e2e.md +185 -0
- package/.claude/skills-en/integration-e2e-testing/SKILL.md +4 -0
- package/.claude/skills-en/integration-e2e-testing/references/e2e-design.md +86 -0
- package/.claude/skills-en/subagents-orchestration-guide/SKILL.md +44 -22
- package/.claude/skills-en/task-analyzer/references/skills-index.yaml +15 -11
- package/.claude/skills-en/technical-spec/SKILL.md +5 -4
- package/.claude/skills-ja/documentation-criteria/SKILL.md +37 -1
- package/.claude/skills-ja/documentation-criteria/references/design-template.md +24 -0
- package/.claude/skills-ja/documentation-criteria/references/prd-template.md +10 -0
- package/.claude/skills-ja/documentation-criteria/references/ui-spec-template.md +145 -0
- package/.claude/skills-ja/{frontend/technical-spec → frontend-technical-spec}/SKILL.md +5 -5
- package/.claude/skills-ja/{frontend/typescript-rules → frontend-typescript-rules}/SKILL.md +1 -1
- package/.claude/skills-ja/{frontend/typescript-testing → frontend-typescript-testing}/SKILL.md +2 -2
- package/.claude/skills-ja/frontend-typescript-testing/references/e2e.md +185 -0
- package/.claude/skills-ja/integration-e2e-testing/SKILL.md +4 -0
- package/.claude/skills-ja/integration-e2e-testing/references/e2e-design.md +86 -0
- package/.claude/skills-ja/subagents-orchestration-guide/SKILL.md +44 -22
- package/.claude/skills-ja/task-analyzer/references/skills-index.yaml +15 -11
- package/.claude/skills-ja/technical-spec/SKILL.md +5 -4
- package/CHANGELOG.md +67 -0
- package/CLAUDE.en.md +2 -2
- package/CLAUDE.ja.md +2 -2
- package/CLAUDE.md +68 -86
- package/README.ja.md +10 -7
- package/README.md +10 -7
- package/bin/create-project.js +76 -75
- package/biome.json +5 -8
- package/package.json +11 -24
- package/scripts/post-setup.js +54 -57
- package/scripts/set-language.js +107 -112
- package/scripts/setup-project.js +97 -92
- package/scripts/show-coverage.js +36 -22
- package/scripts/update-project.js +205 -201
- package/scripts/utils.js +19 -21
- package/tsconfig.json +3 -3
- package/vitest.config.mjs +2 -2
- package/.tsprunerc +0 -11
- package/scripts/check-unused-exports.js +0 -69
|
@@ -1,49 +1,50 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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
|
|
9
|
-
|
|
10
|
-
const
|
|
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(
|
|
68
|
-
|
|
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)
|
|
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(
|
|
148
|
-
|
|
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
|
-
|
|
380
|
-
const
|
|
381
|
-
const
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
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]
|
|
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
|
+
})
|