claudeos-core 1.7.0 → 2.0.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 (39) hide show
  1. package/CHANGELOG.md +138 -0
  2. package/CONTRIBUTING.md +92 -59
  3. package/README.de.md +465 -240
  4. package/README.es.md +446 -223
  5. package/README.fr.md +461 -238
  6. package/README.hi.md +485 -261
  7. package/README.ja.md +440 -235
  8. package/README.ko.md +244 -56
  9. package/README.md +215 -47
  10. package/README.ru.md +462 -238
  11. package/README.vi.md +454 -230
  12. package/README.zh-CN.md +476 -252
  13. package/bin/cli.js +144 -140
  14. package/bin/commands/init.js +550 -46
  15. package/bin/commands/memory.js +426 -0
  16. package/bin/lib/cli-utils.js +206 -143
  17. package/bootstrap.sh +81 -390
  18. package/content-validator/index.js +436 -340
  19. package/lib/expected-guides.js +23 -0
  20. package/lib/expected-outputs.js +91 -0
  21. package/lib/language-config.js +35 -0
  22. package/lib/memory-scaffold.js +1014 -0
  23. package/lib/plan-parser.js +153 -149
  24. package/lib/staged-rules.js +118 -0
  25. package/manifest-generator/index.js +176 -171
  26. package/package.json +1 -1
  27. package/pass-json-validator/index.js +337 -299
  28. package/pass-prompts/templates/common/pass3-footer.md +16 -0
  29. package/pass-prompts/templates/common/pass4.md +317 -0
  30. package/pass-prompts/templates/common/staging-override.md +26 -0
  31. package/pass-prompts/templates/python-flask/pass1.md +119 -0
  32. package/pass-prompts/templates/python-flask/pass2.md +85 -0
  33. package/pass-prompts/templates/python-flask/pass3.md +103 -0
  34. package/plan-installer/domain-grouper.js +2 -1
  35. package/plan-installer/prompt-generator.js +120 -96
  36. package/plan-installer/scanners/scan-frontend.js +219 -10
  37. package/plan-installer/scanners/scan-java.js +226 -223
  38. package/plan-installer/scanners/scan-python.js +21 -0
  39. package/sync-checker/index.js +133 -132
package/bootstrap.sh CHANGED
@@ -1,390 +1,81 @@
1
- #!/bin/bash
2
-
3
- # ClaudeOS-Core — Bootstrap (3-Pass Auto)
4
- #
5
- # One-click full system auto-build
6
- # Automatically splits Pass 1 into N runs based on project size
7
- #
8
- # Prerequisites: bash, node (v18+), claude CLI
9
- # Cross-platform alternative: node bin/cli.js init
10
- #
11
- # Usage: bash claudeos-core-tools/bootstrap.sh --lang ko
12
- # bash claudeos-core-tools/bootstrap.sh (interactive)
13
-
14
- # Require bash (not sh/dash) script uses bash arrays and [[ ]]
15
- if [ -z "$BASH_VERSION" ]; then
16
- echo "❌ This script requires bash. Run with: bash $0" >&2
17
- exit 1
18
- fi
19
-
20
- set -e
21
-
22
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
23
- PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
24
- TOOLS_DIR="$SCRIPT_DIR"
25
- GENERATED_DIR="$PROJECT_ROOT/claudeos-core/generated"
26
-
27
- cd "$PROJECT_ROOT"
28
-
29
- # Cleanup temp files on exit (Ctrl+C, errors, etc.)
30
- trap 'rc=$?; rm -f "$GENERATED_DIR"/_tmp_*.md "$GENERATED_DIR"/_tmp_*.md.final 2>/dev/null; exit $rc' EXIT
31
-
32
- # ─── Language selection (required) ──────────────────────────────
33
- SUPPORTED_LANGS=("en" "ko" "zh-CN" "ja" "es" "vi" "hi" "ru" "fr" "de")
34
- LANG_LABELS=("English" "한국어 (Korean)" "简体中文 (Chinese Simplified)" "日本語 (Japanese)" "Español (Spanish)" "Tiếng Việt (Vietnamese)" "हिन्दी (Hindi)" "Русский (Russian)" "Français (French)" "Deutsch (German)")
35
-
36
- CLAUDEOS_LANG=""
37
- CLAUDEOS_FORCE=false
38
-
39
- # Parse arguments
40
- while [[ $# -gt 0 ]]; do
41
- case $1 in
42
- --lang) [ -z "$2" ] && echo " ❌ --lang requires a value" && exit 1; CLAUDEOS_LANG="$2"; shift 2 ;;
43
- --lang=*) CLAUDEOS_LANG="${1#*=}"; shift ;;
44
- --force|-f) CLAUDEOS_FORCE=true; shift ;;
45
- *) echo "⚠️ Unknown argument: $1 (ignored)"; shift ;;
46
- esac
47
- done
48
-
49
- # Interactive selection if --lang not provided
50
- if [ -z "$CLAUDEOS_LANG" ]; then
51
- echo ""
52
- echo "╔══════════════════════════════════════════════════╗"
53
- echo "║ Select generated document language (required)"
54
- echo "╚══════════════════════════════════════════════════╝"
55
- echo ""
56
- echo " Generated files (CLAUDE.md, Standards, Rules,"
57
- echo " Skills, Guides) will be written in this language."
58
- echo ""
59
- for i in "${!SUPPORTED_LANGS[@]}"; do
60
- printf " %2d. %-6s %s\n" "$((i+1))" "${SUPPORTED_LANGS[$i]}" "${LANG_LABELS[$i]}"
61
- done
62
- echo ""
63
- LANG_COUNT=${#SUPPORTED_LANGS[@]}
64
- read -rp " Enter number (1-${LANG_COUNT}) or language code: " LANG_INPUT
65
-
66
- # Accept number
67
- if [[ "$LANG_INPUT" =~ ^[0-9]+$ ]] && [ "$LANG_INPUT" -ge 1 ] && [ "$LANG_INPUT" -le "$LANG_COUNT" ]; then
68
- CLAUDEOS_LANG="${SUPPORTED_LANGS[$((LANG_INPUT-1))]}"
69
- else
70
- # Accept language code
71
- CLAUDEOS_LANG="$LANG_INPUT"
72
- fi
73
- fi
74
-
75
- # Validate
76
- VALID=false
77
- for l in "${SUPPORTED_LANGS[@]}"; do
78
- if [ "$l" = "$CLAUDEOS_LANG" ]; then VALID=true; break; fi
79
- done
80
- if [ "$VALID" = false ]; then
81
- echo ""
82
- printf ' ❌ Unsupported language: "%s"\n' "$CLAUDEOS_LANG"
83
- echo " Supported: ${SUPPORTED_LANGS[*]}"
84
- echo ""
85
- exit 1
86
- fi
87
-
88
- export CLAUDEOS_LANG
89
- export CLAUDEOS_ROOT="$PROJECT_ROOT"
90
-
91
- # ─── Prerequisites check ──────────────────────────────────────
92
- if ! command -v node &> /dev/null; then
93
- echo ""
94
- echo " ❌ Node.js not found."
95
- echo " Install: https://nodejs.org/"
96
- echo ""
97
- exit 1
98
- fi
99
-
100
- NODE_MAJOR=$(node -e "console.log(process.versions.node.split('.')[0])" 2>/dev/null)
101
- if ! [[ "$NODE_MAJOR" =~ ^[0-9]+$ ]] || [ "$NODE_MAJOR" -lt 18 ]; then
102
- echo ""
103
- echo " ❌ Node.js v18+ required (current: v$(node --version))"
104
- echo " Install: https://nodejs.org/"
105
- echo ""
106
- exit 1
107
- fi
108
-
109
- if ! command -v claude &> /dev/null; then
110
- echo ""
111
- echo " ❌ Claude Code CLI not found."
112
- echo " Install: https://code.claude.com/docs/en/overview"
113
- echo " Then run: claude (and complete authentication)"
114
- echo ""
115
- exit 1
116
- fi
117
-
118
- ## perl is no longer required — placeholder substitution now uses Node.js
119
-
120
-
121
-
122
- echo ""
123
- echo "╔════════════════════════════════════════════════════╗"
124
- echo "║ ClaudeOS-Core — Bootstrap (3-Pass) ║"
125
- echo "╚════════════════════════════════════════════════════╝"
126
- echo " Project root: $PROJECT_ROOT"
127
- # Find label for selected lang
128
- for i in "${!SUPPORTED_LANGS[@]}"; do
129
- if [ "${SUPPORTED_LANGS[$i]}" = "$CLAUDEOS_LANG" ]; then
130
- echo " Language: ${LANG_LABELS[$i]} ($CLAUDEOS_LANG)"
131
- break
132
- fi
133
- done
134
- echo ""
135
-
136
- # ─── [1] Install dependencies ────────────────────────────────────
137
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
138
- echo "[1] Installing dependencies..."
139
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
140
- cd "$TOOLS_DIR"
141
- if [ ! -d "node_modules" ]; then
142
- npm install --silent
143
- fi
144
- cd "$PROJECT_ROOT"
145
- echo " ✅ Done"
146
- echo ""
147
-
148
- # ─── [2] Create directory structure ─────────────────────────────
149
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
150
- echo "[2] Creating directory structure..."
151
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
152
- mkdir -p .claude/rules/{00.core,10.backend,20.frontend,30.security-db,40.infra,50.sync}
153
- mkdir -p claudeos-core/generated
154
- mkdir -p claudeos-core/standard/{00.core,10.backend-api,20.frontend-ui,30.security-db,40.infra,50.verification,90.optional}
155
- mkdir -p claudeos-core/skills/{00.shared,10.backend-crud/scaffold-crud-feature,20.frontend-page/scaffold-page-feature,50.testing,90.experimental}
156
- mkdir -p claudeos-core/plan
157
- mkdir -p claudeos-core/guide/{01.onboarding,02.usage,03.troubleshooting,04.architecture}
158
- mkdir -p claudeos-core/database
159
- mkdir -p claudeos-core/mcp-guide
160
- echo " ✅ Done"
161
- echo ""
162
-
163
- # ─── [3] Run plan-installer (project analysis) ────────────
164
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
165
- echo "[3] Analyzing project (plan-installer)..."
166
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
167
- node "$TOOLS_DIR/plan-installer/index.js"
168
- echo ""
169
-
170
- # ─── Resume / Fresh selection ────────────────────────────
171
- PASS1_EXISTING=$(ls -1 "$GENERATED_DIR"/pass1-*.json 2>/dev/null | wc -l | tr -d ' ')
172
- PASS2_EXISTING=false
173
- [ -f "$GENERATED_DIR/pass2-merged.json" ] && PASS2_EXISTING=true
174
-
175
- if [ "$PASS1_EXISTING" -gt 0 ] || [ "$PASS2_EXISTING" = true ]; then
176
- PASS2_LABEL="✗"
177
- [ "$PASS2_EXISTING" = true ] && PASS2_LABEL="✓"
178
- if [ "$CLAUDEOS_FORCE" = true ]; then
179
- rm -f "$GENERATED_DIR"/pass1-*.json "$GENERATED_DIR"/pass2-merged.json
180
- echo " 🔄 Previous results deleted (--force)"
181
- echo ""
182
- else
183
- echo ""
184
- echo " ⚠️ Previous analysis found (pass1: ${PASS1_EXISTING} completed, pass2: ${PASS2_LABEL})"
185
- echo ""
186
- echo " 1. Continue — Resume from where it stopped"
187
- echo " 2. Fresh — Delete all and start over"
188
- echo ""
189
- read -rp " Enter number (1-2): " RESUME_CHOICE
190
- if [ "$RESUME_CHOICE" = "2" ]; then
191
- rm -f "$GENERATED_DIR"/pass1-*.json "$GENERATED_DIR"/pass2-merged.json
192
- echo " 🔄 Previous results deleted"
193
- fi
194
- echo ""
195
- fi
196
- fi
197
-
198
- # ─── [4] Pass 1: Deep analysis per domain group (multi-stack) ──────────
199
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
200
- echo "[4] Pass 1 — Deep analysis per domain group..."
201
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
202
-
203
- # Read groups from domain-groups.json
204
- TOTAL_GROUPS=$(node -e "
205
- const g = require(process.argv[1]);
206
- console.log(g.totalGroups);
207
- " "$GENERATED_DIR/domain-groups.json")
208
-
209
- # Validate TOTAL_GROUPS is a positive integer
210
- if ! [[ "$TOTAL_GROUPS" =~ ^[0-9]+$ ]] || [ "$TOTAL_GROUPS" -lt 1 ]; then
211
- echo " ❌ Invalid TOTAL_GROUPS: '${TOTAL_GROUPS}'. domain-groups.json may be malformed."
212
- exit 1
213
- fi
214
-
215
- for i in $(seq 1 "$TOTAL_GROUPS"); do
216
- DOMAIN_LIST=$(node -e "
217
- const g = require(process.argv[1]);
218
- console.log(g.groups[process.argv[2] - 1].domains.join(', '));
219
- " "$GENERATED_DIR/domain-groups.json" "$i")
220
- EST_FILES=$(node -e "
221
- const g = require(process.argv[1]);
222
- console.log(g.groups[process.argv[2] - 1].estimatedFiles);
223
- " "$GENERATED_DIR/domain-groups.json" "$i")
224
- GROUP_TYPE=$(node -e "
225
- const g = require(process.argv[1]);
226
- console.log(g.groups[process.argv[2] - 1].type || 'backend');
227
- " "$GENERATED_DIR/domain-groups.json" "$i")
228
-
229
- echo ""
230
- echo " [Pass 1-${i}/${TOTAL_GROUPS}] (${GROUP_TYPE}) Analyzing: ${DOMAIN_LIST} (~${EST_FILES} files)"
231
-
232
- # Skip already completed passes
233
- if [ -f "$GENERATED_DIR/pass1-${i}.json" ]; then
234
- echo " ⏭️ pass1-${i}.json already exists, skipping"
235
- continue
236
- fi
237
-
238
- # Select prompt by type
239
- PROMPT_FILE="$GENERATED_DIR/pass1-${GROUP_TYPE}-prompt.md"
240
- if [ ! -f "$PROMPT_FILE" ]; then
241
- PROMPT_FILE="$GENERATED_DIR/pass1-prompt.md"
242
- fi
243
- # Substitute placeholders via temp file (uses Node.js for safe literal replacement)
244
- TMP_PROMPT="$GENERATED_DIR/_tmp_pass1_prompt.md"
245
- cp "$PROMPT_FILE" "$TMP_PROMPT"
246
- export _DOMAIN_LIST="$DOMAIN_LIST"
247
- export _PASS_NUM="$i"
248
- export _PROJECT_ROOT="$PROJECT_ROOT"
249
- node -e "
250
- const fs = require('fs');
251
- let c = fs.readFileSync(process.argv[1], 'utf8');
252
- c = c.replace(/\{\{DOMAIN_GROUP\}\}/g, process.env._DOMAIN_LIST);
253
- c = c.replace(/\{\{PASS_NUM\}\}/g, process.env._PASS_NUM);
254
- c = c.replace(/\{\{PROJECT_ROOT\}\}/g, process.env._PROJECT_ROOT);
255
- fs.writeFileSync(process.argv[1], c);
256
- " "$TMP_PROMPT"
257
-
258
- echo " ⏳ [Pass 1-${i}/${TOTAL_GROUPS}] Running claude -p (no output is normal, please wait)..."
259
- if ! (cd "$PROJECT_ROOT" && cat "$TMP_PROMPT" | claude -p --dangerously-skip-permissions); then
260
- rm -f "$TMP_PROMPT"
261
- echo " ❌ Pass 1-${i} failed. Aborting."
262
- exit 1
263
- fi
264
- rm -f "$TMP_PROMPT"
265
-
266
- # Verify JSON was created
267
- if [ ! -f "$GENERATED_DIR/pass1-${i}.json" ]; then
268
- echo " ❌ pass1-${i}.json was not created. Aborting."
269
- exit 1
270
- fi
271
-
272
- echo " ✅ pass1-${i}.json created"
273
- done
274
- unset _DOMAIN_LIST _PASS_NUM _PROJECT_ROOT
275
- echo ""
276
-
277
- # ─── [5] Pass 2: Merge analysis results ─────────────────────────
278
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
279
- echo "[5] Pass 2 — Merging analysis results..."
280
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
281
-
282
- if [ -f "$GENERATED_DIR/pass2-merged.json" ]; then
283
- echo " ⏭️ pass2-merged.json already exists, skipping"
284
- else
285
- TMP_PASS2="$GENERATED_DIR/_tmp_pass2_prompt.md"
286
- export _PROJECT_ROOT="$PROJECT_ROOT"
287
- node -e "
288
- const fs = require('fs');
289
- let c = fs.readFileSync(process.argv[1], 'utf8');
290
- c = c.replace(/\{\{PROJECT_ROOT\}\}/g, process.env._PROJECT_ROOT);
291
- fs.writeFileSync(process.argv[2], c);
292
- " "$GENERATED_DIR/pass2-prompt.md" "$TMP_PASS2"
293
-
294
- echo " ⏳ [Pass 2] Running claude -p (no output is normal, please wait)..."
295
- if ! (cd "$PROJECT_ROOT" && cat "$TMP_PASS2" | claude -p --dangerously-skip-permissions); then
296
- rm -f "$TMP_PASS2"
297
- echo " ❌ Pass 2 failed. Aborting."
298
- exit 1
299
- fi
300
- rm -f "$TMP_PASS2"
301
-
302
- if [ ! -f "$GENERATED_DIR/pass2-merged.json" ]; then
303
- echo " ❌ pass2-merged.json was not created. Aborting."
304
- exit 1
305
- fi
306
-
307
- echo " ✅ pass2-merged.json created"
308
- fi
309
- echo ""
310
-
311
- # ─── [6] Pass 3: Generate + Master Plan build + verification ────────
312
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
313
- echo "[6] Pass 3 — Generating all files..."
314
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
315
- TMP_PASS3="$GENERATED_DIR/_tmp_pass3_prompt.md"
316
- export _PROJECT_ROOT="$PROJECT_ROOT"
317
- node -e "
318
- const fs = require('fs');
319
- let c = fs.readFileSync(process.argv[1], 'utf8');
320
- c = c.replace(/\{\{PROJECT_ROOT\}\}/g, process.env._PROJECT_ROOT);
321
- fs.writeFileSync(process.argv[2], c);
322
- " "$GENERATED_DIR/pass3-prompt.md" "$TMP_PASS3"
323
-
324
- echo " ⏳ [Pass 3] Running claude -p (no output is normal, please wait)..."
325
- if ! (cd "$PROJECT_ROOT" && cat "$TMP_PASS3" | claude -p --dangerously-skip-permissions); then
326
- rm -f "$TMP_PASS3"
327
- echo " ❌ Pass 3 failed. Aborting."
328
- exit 1
329
- fi
330
- rm -f "$TMP_PASS3"
331
-
332
- if [ ! -f "$PROJECT_ROOT/CLAUDE.md" ]; then
333
- echo " ❌ CLAUDE.md was not created. Pass 3 may have failed silently."
334
- exit 1
335
- fi
336
- unset _PROJECT_ROOT
337
- echo ""
338
-
339
- # ─── [7] Run verification tools ───────────────────────────────
340
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
341
- echo "[7] Running verification tools..."
342
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
343
-
344
- if [ -f "$TOOLS_DIR/manifest-generator/index.js" ]; then
345
- echo -n " ⏳ manifest-generator..."
346
- if node "$TOOLS_DIR/manifest-generator/index.js" > /dev/null 2>&1; then
347
- echo " ✅"
348
- else
349
- echo " ❌ (non-fatal)"
350
- fi
351
- fi
352
-
353
- if [ -f "$TOOLS_DIR/health-checker/index.js" ]; then
354
- echo -n " ⏳ health-checker..."
355
- if node "$TOOLS_DIR/health-checker/index.js" > /dev/null 2>&1; then
356
- echo " ✅"
357
- else
358
- echo " ⚠️ issues found (non-fatal)"
359
- fi
360
- fi
361
- echo ""
362
-
363
- # ─── Complete ───────────────────────────────────────────────
364
- TOTAL_FILES=$(find .claude claudeos-core -type f 2>/dev/null | grep -v '/node_modules/' | grep -v '/generated/' | wc -l | tr -d ' ')
365
- TOTAL_GROUPS_DONE=$TOTAL_GROUPS
366
- PASS1_FILES=$(ls -1 "$GENERATED_DIR"/pass1-*.json 2>/dev/null | wc -l | tr -d ' ')
367
-
368
- echo ""
369
- echo "╔════════════════════════════════════════════════════╗"
370
- echo "║ ✅ ClaudeOS-Core — Complete ║"
371
- echo "║ ║"
372
- printf "║ Files created: %-29s║\n" "${TOTAL_FILES}"
373
- printf "║ Domains analyzed: %-29s║\n" "${TOTAL_GROUPS_DONE} groups"
374
- printf "║ Analysis passes: %-29s║\n" "${PASS1_FILES} pass1 files"
375
- # Find label for selected lang
376
- LANG_LABEL="$CLAUDEOS_LANG"
377
- for i in "${!SUPPORTED_LANGS[@]}"; do
378
- if [ "${SUPPORTED_LANGS[$i]}" = "$CLAUDEOS_LANG" ]; then
379
- LANG_LABEL="${LANG_LABELS[$i]}"; break
380
- fi
381
- done
382
- printf "║ Output language: %-29s║\n" "${LANG_LABEL}"
383
- echo "║ ║"
384
- echo "║ Verify anytime: ║"
385
- echo "║ npx claudeos-core health ║"
386
- echo "║ ║"
387
- echo "║ Start using: ║"
388
- echo "║ \"Create a CRUD for orders\" ║"
389
- echo "╚════════════════════════════════════════════════════╝"
390
- echo ""
1
+ #!/bin/bash
2
+
3
+ # ClaudeOS-Core — Bootstrap
4
+ #
5
+ # Thin wrapper that forwards to `node bin/cli.js init`.
6
+ #
7
+ # The full init pipeline (plan-installer, Pass 1 multi-group, Pass 2 merge,
8
+ # Pass 3 file generation, Pass 4 memory scaffolding, verification) is
9
+ # implemented in bin/commands/init.js — this script just ensures Node.js
10
+ # is available, installs npm dependencies on first run, and delegates.
11
+ #
12
+ # Why delegation instead of reimplementing the pipeline in bash:
13
+ # - init.js supports features this script does not (and cannot reasonably
14
+ # reimplement): --lang (10 languages), --resume (interrupted init
15
+ # recovery), Pass 4 memory scaffolding with translated fallback,
16
+ # progress bar with ETA, stale-marker detection, clear error messages.
17
+ # - A single source of truth (init.js) prevents the two code paths from
18
+ # drifting, which was the cause of bug #21's cousin: bootstrap.sh was
19
+ # still advertising "3-Pass" while the CLI had moved to 4-Pass with
20
+ # persistent memory scaffolding.
21
+ #
22
+ # Prerequisites:
23
+ # - bash (this script), node (v18+), claude CLI (for the init pipeline)
24
+ #
25
+ # Usage:
26
+ # bash claudeos-core-tools/bootstrap.sh # interactive lang pick
27
+ # bash claudeos-core-tools/bootstrap.sh --lang ko # Korean
28
+ # bash claudeos-core-tools/bootstrap.sh --lang en --force # fresh English init
29
+ #
30
+ # Cross-platform alternative (recommended):
31
+ # npx claudeos-core init
32
+ # node claudeos-core-tools/bin/cli.js init
33
+
34
+ if [ -z "$BASH_VERSION" ]; then
35
+ echo "❌ This script requires bash. Run with: bash $0" >&2
36
+ exit 1
37
+ fi
38
+
39
+ set -e
40
+
41
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
42
+ PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
43
+ TOOLS_DIR="$SCRIPT_DIR"
44
+
45
+ cd "$PROJECT_ROOT"
46
+
47
+ # ─── Prerequisites check ──────────────────────────────────────
48
+ if ! command -v node >/dev/null 2>&1; then
49
+ echo "❌ node is required but not found in PATH. Install Node.js 18+ and re-run." >&2
50
+ exit 1
51
+ fi
52
+
53
+ NODE_MAJOR="$(node -p 'process.versions.node.split(".")[0]' 2>/dev/null || echo 0)"
54
+ if [ "$NODE_MAJOR" -lt 18 ]; then
55
+ echo "❌ Node.js 18+ required (found v$(node -v 2>/dev/null))." >&2
56
+ exit 1
57
+ fi
58
+
59
+ if ! command -v claude >/dev/null 2>&1; then
60
+ echo "⚠️ \`claude\` CLI not found in PATH. The init pipeline requires it." >&2
61
+ echo " Install & sign in: https://docs.claude.com/en/docs/claude-code/overview" >&2
62
+ # Don't exit — let init.js surface the exact point of failure with context.
63
+ fi
64
+
65
+ # ─── [1/2] Ensure npm dependencies ────────────────────────────
66
+ # init.js requires glob + gray-matter. If node_modules is missing (first
67
+ # bootstrap run for a freshly-cloned tools directory), install them.
68
+ if [ ! -d "$TOOLS_DIR/node_modules" ]; then
69
+ echo "[1/2] Installing dependencies (first bootstrap run)..."
70
+ (cd "$TOOLS_DIR" && npm install --silent --no-audit --no-fund) || {
71
+ echo "❌ npm install failed. Check network / npm registry access." >&2
72
+ exit 1
73
+ }
74
+ echo " ✅ Dependencies installed"
75
+ echo
76
+ fi
77
+
78
+ # ─── [2/2] Delegate to the CLI ────────────────────────────────
79
+ echo "[2/2] Running ClaudeOS-Core init..."
80
+ echo
81
+ exec node "$TOOLS_DIR/bin/cli.js" init "$@"