claudeos-core 1.2.2 → 1.2.4

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/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.2.4] — 2026-04-03
4
+
5
+ ### Changed
6
+ - **50.sync/ rules role clarified** — no longer described as "hooks fallback"; now the primary sync reminder mechanism (`npx claudeos-core refresh`)
7
+ - All 6 pass3 templates updated to reference `npx claudeos-core refresh` instead of PostToolUse hooks
8
+ - All 10 READMEs updated: removed "Automatic plan sync (hooks)" section, plan table now references `refresh` command
9
+
10
+ ### Fixed
11
+ - **`plan-installer`**: malformed `package.json` no longer aborts entire `detectStack()` — Python, DB config, .env, and frontend config detection now continue normally
12
+
13
+ ### Removed
14
+ - **Automatic hook installation removed from `init`** — `installSyncHooks()` function and `[2.5]` step removed from `cli.js`
15
+ - PostToolUse hooks caused instability: npx cache paths broke across environments, added latency to every Edit/Write
16
+ - Plan sync is now manual via `npx claudeos-core refresh` (same result, zero complexity)
17
+ - All references to `PostToolUse`, `sync-hook`, and `.claude/settings.json` hooks removed from pass3 templates and READMEs
18
+
3
19
  ## [1.2.1] — 2026-04-02
4
20
 
5
21
  ### Added
package/README.de.md CHANGED
@@ -288,7 +288,7 @@ your-project/
288
288
  │ ├── 20.frontend/
289
289
  │ ├── 30.security-db/
290
290
  │ ├── 40.infra/
291
- │ └── 50.sync/ ← Auto-Sync-Regeln
291
+ │ └── 50.sync/ ← Sync-Erinnerungsregeln
292
292
 
293
293
  ├── claudeos-core/ ← Hauptausgabeverzeichnis
294
294
  │ ├── generated/ ← Analyse-JSON + dynamische Prompts
@@ -368,22 +368,11 @@ Explizit durch den `DO NOT Read`-Abschnitt der standard-reference Regel ausgesch
368
368
 
369
369
  | Ordner | Ausschlussgrund |
370
370
  |---|---|
371
- | `claudeos-core/plan/` | Master Plan Backups (~340KB). Automatisch durch Hooks synchronisiert. |
371
+ | `claudeos-core/plan/` | Master Plan Backups (~340KB). Verwenden Sie `npx claudeos-core refresh` zur Synchronisation. |
372
372
  | `claudeos-core/generated/` | Build-Metadaten JSON. Keine Coding-Referenz. |
373
373
  | `claudeos-core/guide/` | Onboarding-Guides für Menschen. |
374
374
  | `claudeos-core/mcp-guide/` | MCP Server Dokumentation. Keine Coding-Referenz. |
375
375
 
376
- ### Automatische Plan-Synchronisation (Hooks)
377
-
378
- Wenn Claude Code eine Standard- oder Rules-Datei bearbeitet, synchronisiert ein PostToolUse Hook automatisch den Master Plan:
379
-
380
- ```
381
- AI bearbeitet claudeos-core/standard/10.backend-api/01.controller-patterns.md
382
- → sync-hook aktualisiert automatisch plan/10.standard-master.md
383
- ```
384
-
385
- Keine manuelle Synchronisation nötig. Der Hook wird automatisch bei `npx claudeos-core init` installiert.
386
-
387
376
  ---
388
377
 
389
378
  ## Täglicher Arbeitsablauf
@@ -400,7 +389,7 @@ Keine manuelle Synchronisation nötig. Der Hook wird automatisch bei `npx claude
400
389
  ### Nach manueller Bearbeitung der Standards
401
390
 
402
391
  ```bash
403
- # Wenn Dateien außerhalb von Claude Code bearbeitet wurden (Hooks funktionieren nur innerhalb):
392
+ # Nach dem Bearbeiten von Standard- oder Rules-Dateien:
404
393
  npx claudeos-core refresh
405
394
 
406
395
  # Konsistenz überprüfen
package/README.es.md CHANGED
@@ -288,7 +288,7 @@ your-project/
288
288
  │ ├── 20.frontend/
289
289
  │ ├── 30.security-db/
290
290
  │ ├── 40.infra/
291
- │ └── 50.sync/ ← Reglas de sincronización automática
291
+ │ └── 50.sync/ ← Reglas de recordatorio de sincronización
292
292
 
293
293
  ├── claudeos-core/ ← Directorio principal de salida
294
294
  │ ├── generated/ ← JSON de análisis + prompts dinámicos
@@ -368,22 +368,11 @@ Excluidos explícitamente por la sección `DO NOT Read` de la regla standard-ref
368
368
 
369
369
  | Carpeta | Razón de exclusión |
370
370
  |---|---|
371
- | `claudeos-core/plan/` | Backups de Master Plan (~340KB). Auto-sincronizado por hooks. |
371
+ | `claudeos-core/plan/` | Backups de Master Plan (~340KB). Usa `npx claudeos-core refresh` para sincronizar. |
372
372
  | `claudeos-core/generated/` | Metadatos JSON de build. No es referencia de código. |
373
373
  | `claudeos-core/guide/` | Guías de onboarding para humanos. |
374
374
  | `claudeos-core/mcp-guide/` | Docs de servidor MCP. No es referencia de código. |
375
375
 
376
- ### Sincronización automática de Plan (hooks)
377
-
378
- Cuando Claude Code edita un archivo standard o rules, un hook PostToolUse sincroniza automáticamente el Master Plan:
379
-
380
- ```
381
- AI edita claudeos-core/standard/10.backend-api/01.controller-patterns.md
382
- → sync-hook actualiza automáticamente plan/10.standard-master.md
383
- ```
384
-
385
- No requiere sincronización manual. El hook se instala automáticamente durante `npx claudeos-core init`.
386
-
387
376
  ---
388
377
 
389
378
  ## Flujo de Trabajo Diario
@@ -400,7 +389,7 @@ No requiere sincronización manual. El hook se instala automáticamente durante
400
389
  ### Después de Editar Estándares Manualmente
401
390
 
402
391
  ```bash
403
- # Si editaste archivos fuera de Claude Code (los hooks solo funcionan dentro de Claude Code):
392
+ # Después de editar archivos standard o rules:
404
393
  npx claudeos-core refresh
405
394
 
406
395
  # Verifica que todo sea consistente
package/README.fr.md CHANGED
@@ -288,7 +288,7 @@ your-project/
288
288
  │ ├── 20.frontend/
289
289
  │ ├── 30.security-db/
290
290
  │ ├── 40.infra/
291
- │ └── 50.sync/ ← Règles de synchronisation auto
291
+ │ └── 50.sync/ ← Règles de rappel de synchronisation
292
292
 
293
293
  ├── claudeos-core/ ← Répertoire principal de sortie
294
294
  │ ├── generated/ ← JSON d'analyse + prompts dynamiques
@@ -368,22 +368,11 @@ Explicitement exclus par la section `DO NOT Read` de la règle standard-referenc
368
368
 
369
369
  | Dossier | Raison d'exclusion |
370
370
  |---|---|
371
- | `claudeos-core/plan/` | Sauvegardes Master Plan (~340Ko). Auto-synchronisé par hooks. |
371
+ | `claudeos-core/plan/` | Sauvegardes Master Plan (~340Ko). Utilisez `npx claudeos-core refresh` pour synchroniser. |
372
372
  | `claudeos-core/generated/` | JSON de métadonnées build. Pas une référence de code. |
373
373
  | `claudeos-core/guide/` | Guides d'onboarding pour humains. |
374
374
  | `claudeos-core/mcp-guide/` | Docs serveur MCP. Pas une référence de code. |
375
375
 
376
- ### Synchronisation automatique du Plan (hooks)
377
-
378
- Quand Claude Code édite un fichier standard ou rules, un hook PostToolUse synchronise automatiquement le Master Plan :
379
-
380
- ```
381
- AI édite claudeos-core/standard/10.backend-api/01.controller-patterns.md
382
- → sync-hook met à jour automatiquement plan/10.standard-master.md
383
- ```
384
-
385
- Aucune synchronisation manuelle nécessaire. Le hook est installé automatiquement lors de `npx claudeos-core init`.
386
-
387
376
  ---
388
377
 
389
378
  ## Flux de Travail Quotidien
@@ -400,7 +389,7 @@ Aucune synchronisation manuelle nécessaire. Le hook est installé automatiqueme
400
389
  ### Après Modification Manuelle des Standards
401
390
 
402
391
  ```bash
403
- # Si vous avez édité des fichiers en dehors de Claude Code (les hooks ne fonctionnent qu'à l'intérieur) :
392
+ # Après avoir édité des fichiers standard ou rules :
404
393
  npx claudeos-core refresh
405
394
 
406
395
  # Vérifier la cohérence
package/README.hi.md CHANGED
@@ -288,7 +288,7 @@ your-project/
288
288
  │ ├── 20.frontend/
289
289
  │ ├── 30.security-db/
290
290
  │ ├── 40.infra/
291
- │ └── 50.sync/ ← ऑटो-सिंक rules
291
+ │ └── 50.sync/ ← सिंक रिमाइंडर rules
292
292
 
293
293
  ├── claudeos-core/ ← मुख्य आउटपुट डायरेक्टरी
294
294
  │ ├── generated/ ← एनालिसिस JSON + डायनामिक प्रॉम्प्ट्स
@@ -368,22 +368,11 @@ standard-reference रूल के `DO NOT Read` सेक्शन द्व
368
368
 
369
369
  | फोल्डर | बाहर करने का कारण |
370
370
  |---|---|
371
- | `claudeos-core/plan/` | Master Plan बैकअप (~340KB)। hooks द्वारा ऑटो-सिंक। |
371
+ | `claudeos-core/plan/` | Master Plan बैकअप (~340KB)। `npx claudeos-core refresh` से सिंक करें। |
372
372
  | `claudeos-core/generated/` | बिल्ड मेटाडेटा JSON। कोडिंग रेफरेंस नहीं। |
373
373
  | `claudeos-core/guide/` | इंसानों के लिए ऑनबोर्डिंग गाइड। |
374
374
  | `claudeos-core/mcp-guide/` | MCP सर्वर डॉक्स। कोडिंग रेफरेंस नहीं। |
375
375
 
376
- ### ऑटोमैटिक Plan सिंक (hooks)
377
-
378
- जब Claude Code standard या rules फाइल एडिट करता है, PostToolUse hook ऑटोमैटिकली Master Plan सिंक करता है:
379
-
380
- ```
381
- AI claudeos-core/standard/10.backend-api/01.controller-patterns.md एडिट करता है
382
- → sync-hook ऑटोमैटिकली plan/10.standard-master.md अपडेट करता है
383
- ```
384
-
385
- मैन्युअल सिंक ज़रूरी नहीं। hook `npx claudeos-core init` के दौरान ऑटोमैटिकली इंस्टॉल होता है।
386
-
387
376
  ---
388
377
 
389
378
  ## दैनिक वर्कफ़्लो
@@ -400,7 +389,7 @@ AI claudeos-core/standard/10.backend-api/01.controller-patterns.md एडिट
400
389
  ### स्टैंडर्ड्स मैन्युअली एडिट करने के बाद
401
390
 
402
391
  ```bash
403
- # Claude Code के बाहर फाइल एडिट की है तो (hooks सिर्फ़ Claude Code के अंदर काम करते हैं):
392
+ # standard या rules फाइल एडिट करने के बाद:
404
393
  npx claudeos-core refresh
405
394
 
406
395
  # सब कुछ कंसिस्टेंट है वेरिफाई करें
package/README.ja.md CHANGED
@@ -288,7 +288,7 @@ your-project/
288
288
  │ ├── 20.frontend/
289
289
  │ ├── 30.security-db/
290
290
  │ ├── 40.infra/
291
- │ └── 50.sync/ ← 自動同期ルール
291
+ │ └── 50.sync/ ← 同期リマインダールール
292
292
 
293
293
  ├── claudeos-core/ ← メイン出力ディレクトリ
294
294
  │ ├── generated/ ← 分析 JSON + 動的プロンプト
@@ -368,22 +368,11 @@ standard-reference ルールの `DO NOT Read` セクションで明示的に除
368
368
 
369
369
  | フォルダ | 除外理由 |
370
370
  |---|---|
371
- | `claudeos-core/plan/` | Master Plan バックアップ(~340KB)。hooks で自動同期。 |
371
+ | `claudeos-core/plan/` | Master Plan バックアップ(~340KB)。`npx claudeos-core refresh` で同期。 |
372
372
  | `claudeos-core/generated/` | ビルドメタデータ JSON。コーディング参照不要。 |
373
373
  | `claudeos-core/guide/` | 人間向けオンボーディングガイド。 |
374
374
  | `claudeos-core/mcp-guide/` | MCP サーバードキュメント。コーディング参照不要。 |
375
375
 
376
- ### 自動 Plan 同期(hooks)
377
-
378
- Claude Code が standard や rules ファイルを編集すると、PostToolUse hook が自動的に Master Plan を同期します:
379
-
380
- ```
381
- AI が claudeos-core/standard/10.backend-api/01.controller-patterns.md を編集
382
- → sync-hook が自動的に plan/10.standard-master.md を更新
383
- ```
384
-
385
- 手動同期は不要です。hook は `npx claudeos-core init` 時に自動インストールされます。
386
-
387
376
  ---
388
377
 
389
378
  ## 日常ワークフロー
@@ -400,7 +389,7 @@ AI が claudeos-core/standard/10.backend-api/01.controller-patterns.md を編集
400
389
  ### 標準ファイルを手動編集した後
401
390
 
402
391
  ```bash
403
- # Claude Code の外部でファイルを編集した場合(hooks は Claude Code 内でのみ動作):
392
+ # standard rules ファイルを編集した後:
404
393
  npx claudeos-core refresh
405
394
 
406
395
  # 整合性を検証
package/README.ko.md CHANGED
@@ -288,7 +288,7 @@ your-project/
288
288
  │ ├── 20.frontend/
289
289
  │ ├── 30.security-db/
290
290
  │ ├── 40.infra/
291
- │ └── 50.sync/ ← 자동 동기화 규칙
291
+ │ └── 50.sync/ ← 동기화 리마인더 규칙
292
292
 
293
293
  ├── claudeos-core/ ← 메인 출력 디렉토리
294
294
  │ ├── generated/ ← 분석 JSON + 동적 프롬프트
@@ -386,22 +386,11 @@ standard-reference 규칙의 `DO NOT Read` 섹션으로 명시적으로 제외
386
386
 
387
387
  | 폴더 | 제외 이유 |
388
388
  |---|---|
389
- | `claudeos-core/plan/` | Master Plan 백업 (~340KB). hooks로 자동 동기화. |
389
+ | `claudeos-core/plan/` | Master Plan 백업 (~340KB). `npx claudeos-core refresh`로 동기화. |
390
390
  | `claudeos-core/generated/` | 빌드 메타데이터 JSON. 코딩 참조 아님. |
391
391
  | `claudeos-core/guide/` | 사람을 위한 온보딩 가이드. |
392
392
  | `claudeos-core/mcp-guide/` | MCP 서버 문서. 코딩 참조 아님. |
393
393
 
394
- ### 자동 Plan 동기화 (hooks)
395
-
396
- Claude Code가 standard나 rules 파일을 수정하면, PostToolUse hook이 자동으로 Master Plan을 동기화합니다:
397
-
398
- ```
399
- AI가 claudeos-core/standard/10.backend-api/01.controller-patterns.md 수정
400
- → sync-hook이 자동으로 plan/10.standard-master.md 업데이트
401
- ```
402
-
403
- 수동 동기화 불필요. hook은 `npx claudeos-core init` 시 자동 설치됩니다.
404
-
405
394
  ---
406
395
 
407
396
  ## 일상 워크플로우
@@ -418,7 +407,7 @@ AI가 claudeos-core/standard/10.backend-api/01.controller-patterns.md 수정
418
407
  ### 표준을 직접 편집한 후
419
408
 
420
409
  ```bash
421
- # Claude Code 밖에서 파일을 수정한 경우 (hooks는 Claude Code 안에서만 동작):
410
+ # standard나 rules 파일을 수정한 후:
422
411
  npx claudeos-core refresh
423
412
 
424
413
  # 전체 일관성 확인
package/README.md CHANGED
@@ -301,7 +301,7 @@ your-project/
301
301
  │ ├── 20.frontend/
302
302
  │ ├── 30.security-db/
303
303
  │ ├── 40.infra/
304
- │ └── 50.sync/ ← Auto-sync rules
304
+ │ └── 50.sync/ ← Sync reminder rules
305
305
 
306
306
  ├── claudeos-core/ ← Main output directory
307
307
  │ ├── generated/ ← Analysis JSON + dynamic prompts
@@ -399,22 +399,11 @@ These folders are explicitly excluded via the `DO NOT Read` section in the stand
399
399
 
400
400
  | Folder | Why excluded |
401
401
  |---|---|
402
- | `claudeos-core/plan/` | Master Plan backups (~340KB). Auto-synced by hooks. |
402
+ | `claudeos-core/plan/` | Master Plan backups (~340KB). Use `npx claudeos-core refresh` to sync. |
403
403
  | `claudeos-core/generated/` | Build metadata JSON. Not for coding. |
404
404
  | `claudeos-core/guide/` | Onboarding guides for humans. |
405
405
  | `claudeos-core/mcp-guide/` | MCP server docs. Not for coding. |
406
406
 
407
- ### Automatic plan sync (hooks)
408
-
409
- When Claude Code edits a standard or rules file, a PostToolUse hook automatically syncs the change to the Master Plan:
410
-
411
- ```
412
- AI edits claudeos-core/standard/10.backend-api/01.controller-patterns.md
413
- → sync-hook automatically updates plan/10.standard-master.md
414
- ```
415
-
416
- No manual sync needed. The hook is installed automatically during `npx claudeos-core init`.
417
-
418
407
  ---
419
408
 
420
409
  ## Daily Workflow
@@ -431,7 +420,7 @@ No manual sync needed. The hook is installed automatically during `npx claudeos-
431
420
  ### After Manually Editing Standards
432
421
 
433
422
  ```bash
434
- # If you edited files outside of Claude Code (hooks only trigger inside Claude Code):
423
+ # After editing standards or rules files:
435
424
  npx claudeos-core refresh
436
425
 
437
426
  # Verify everything is consistent
package/README.ru.md CHANGED
@@ -288,7 +288,7 @@ your-project/
288
288
  │ ├── 20.frontend/
289
289
  │ ├── 30.security-db/
290
290
  │ ├── 40.infra/
291
- │ └── 50.sync/ ← Правила автосинхронизации
291
+ │ └── 50.sync/ ← Правила напоминания о синхронизации
292
292
 
293
293
  ├── claudeos-core/ ← Основная директория вывода
294
294
  │ ├── generated/ ← JSON анализа + динамические промпты
@@ -368,22 +368,11 @@ npx claudeos-core restore # Восстановление Plan → Диск
368
368
 
369
369
  | Папка | Причина исключения |
370
370
  |---|---|
371
- | `claudeos-core/plan/` | Резервные копии Master Plan (~340КБ). Автосинхронизация через hooks. |
371
+ | `claudeos-core/plan/` | Резервные копии Master Plan (~340КБ). Используйте `npx claudeos-core refresh` для синхронизации. |
372
372
  | `claudeos-core/generated/` | JSON метаданных сборки. Не для кодирования. |
373
373
  | `claudeos-core/guide/` | Руководства для людей. |
374
374
  | `claudeos-core/mcp-guide/` | Документация MCP сервера. Не для кодирования. |
375
375
 
376
- ### Автоматическая синхронизация Plan (hooks)
377
-
378
- Когда Claude Code редактирует файл standard или rules, хук PostToolUse автоматически синхронизирует Master Plan:
379
-
380
- ```
381
- AI редактирует claudeos-core/standard/10.backend-api/01.controller-patterns.md
382
- → sync-hook автоматически обновляет plan/10.standard-master.md
383
- ```
384
-
385
- Ручная синхронизация не требуется. Хук устанавливается автоматически при `npx claudeos-core init`.
386
-
387
376
  ---
388
377
 
389
378
  ## Повседневный рабочий процесс
@@ -400,7 +389,7 @@ AI редактирует claudeos-core/standard/10.backend-api/01.controller-pa
400
389
  ### После ручного редактирования стандартов
401
390
 
402
391
  ```bash
403
- # Если файлы редактировались вне Claude Code (хуки работают только внутри Claude Code):
392
+ # После редактирования файлов standard или rules:
404
393
  npx claudeos-core refresh
405
394
 
406
395
  # Проверить консистентность
package/README.vi.md CHANGED
@@ -288,7 +288,7 @@ your-project/
288
288
  │ ├── 20.frontend/
289
289
  │ ├── 30.security-db/
290
290
  │ ├── 40.infra/
291
- │ └── 50.sync/ ← Rules đồng bộ tự động
291
+ │ └── 50.sync/ ← Rules nhắc nhở đồng bộ
292
292
 
293
293
  ├── claudeos-core/ ← Thư mục đầu ra chính
294
294
  │ ├── generated/ ← JSON phân tích + prompt động
@@ -368,22 +368,11 @@ Quy tắc `00.standard-reference.md` hướng dẫn Claude Code Read tài liệu
368
368
 
369
369
  | Thư mục | Lý do loại trừ |
370
370
  |---|---|
371
- | `claudeos-core/plan/` | Backup Master Plan (~340KB). Tự đồng bộ bằng hooks. |
371
+ | `claudeos-core/plan/` | Backup Master Plan (~340KB). Dùng `npx claudeos-core refresh` để đồng bộ. |
372
372
  | `claudeos-core/generated/` | JSON metadata build. Không dùng cho coding. |
373
373
  | `claudeos-core/guide/` | Hướng dẫn onboarding cho người dùng. |
374
374
  | `claudeos-core/mcp-guide/` | Tài liệu MCP server. Không dùng cho coding. |
375
375
 
376
- ### Đồng bộ Plan tự động (hooks)
377
-
378
- Khi Claude Code chỉnh sửa file standard hoặc rules, hook PostToolUse tự động đồng bộ Master Plan:
379
-
380
- ```
381
- AI chỉnh sửa claudeos-core/standard/10.backend-api/01.controller-patterns.md
382
- → sync-hook tự động cập nhật plan/10.standard-master.md
383
- ```
384
-
385
- Không cần đồng bộ thủ công. Hook được cài đặt tự động khi chạy `npx claudeos-core init`.
386
-
387
376
  ---
388
377
 
389
378
  ## Quy Trình Làm Việc Hàng Ngày
@@ -400,7 +389,7 @@ Không cần đồng bộ thủ công. Hook được cài đặt tự động kh
400
389
  ### Sau Khi Chỉnh Sửa Thủ Công Standards
401
390
 
402
391
  ```bash
403
- # Nếu bạn chỉnh sửa file bên ngoài Claude Code (hooks chỉ hoạt động bên trong Claude Code):
392
+ # Sau khi chỉnh sửa file standard hoặc rules:
404
393
  npx claudeos-core refresh
405
394
 
406
395
  # Xác minh mọi thứ nhất quán
package/README.zh-CN.md CHANGED
@@ -288,7 +288,7 @@ your-project/
288
288
  │ ├── 20.frontend/
289
289
  │ ├── 30.security-db/
290
290
  │ ├── 40.infra/
291
- │ └── 50.sync/ ← 自动同步规则
291
+ │ └── 50.sync/ ← 同步提醒规则
292
292
 
293
293
  ├── claudeos-core/ ← 主要输出目录
294
294
  │ ├── generated/ ← 分析 JSON + 动态提示
@@ -368,22 +368,11 @@ ClaudeOS-Core 生成的文档,Claude Code 实际读取方式如下:
368
368
 
369
369
  | 文件夹 | 排除原因 |
370
370
  |---|---|
371
- | `claudeos-core/plan/` | Master Plan 备份(~340KB)。由 hooks 自动同步。 |
371
+ | `claudeos-core/plan/` | Master Plan 备份(~340KB)。使用 `npx claudeos-core refresh` 同步。 |
372
372
  | `claudeos-core/generated/` | 构建元数据 JSON。非编码参考。 |
373
373
  | `claudeos-core/guide/` | 面向人类的入门指南。 |
374
374
  | `claudeos-core/mcp-guide/` | MCP 服务器文档。非编码参考。 |
375
375
 
376
- ### 自动 Plan 同步(hooks)
377
-
378
- 当 Claude Code 编辑 standard 或 rules 文件时,PostToolUse hook 自动同步 Master Plan:
379
-
380
- ```
381
- AI 编辑 claudeos-core/standard/10.backend-api/01.controller-patterns.md
382
- → sync-hook 自动更新 plan/10.standard-master.md
383
- ```
384
-
385
- 无需手动同步。hook 在 `npx claudeos-core init` 时自动安装。
386
-
387
376
  ---
388
377
 
389
378
  ## 日常工作流
@@ -400,7 +389,7 @@ AI 编辑 claudeos-core/standard/10.backend-api/01.controller-patterns.md
400
389
  ### 手动编辑标准文件后
401
390
 
402
391
  ```bash
403
- # Claude Code 外部编辑了文件时(hooks 仅在 Claude Code 内部触发):
392
+ # 编辑 standard rules 文件后:
404
393
  npx claudeos-core refresh
405
394
 
406
395
  # 验证一切一致
package/bin/cli.js CHANGED
@@ -150,64 +150,6 @@ function injectProjectRoot(text) {
150
150
  return text.replace(/\{\{PROJECT_ROOT\}\}/g, PROJECT_ROOT);
151
151
  }
152
152
 
153
- // ─── Install sync hooks into .claude/settings.json ──────
154
- function installSyncHooks() {
155
- const settingsPath = path.join(PROJECT_ROOT, ".claude/settings.json");
156
-
157
- // Determine sync-hook script path (relative to project root)
158
- // Works for both npx (node_modules) and git clone (direct path) usage
159
- let syncHookScript;
160
- const npxPath = path.join(PROJECT_ROOT, "node_modules/claudeos-core/sync-hook/index.js");
161
- const localPath = path.join(TOOLS_DIR, "sync-hook/index.js");
162
-
163
- if (fs.existsSync(npxPath)) {
164
- syncHookScript = "node node_modules/claudeos-core/sync-hook/index.js";
165
- } else if (fs.existsSync(localPath)) {
166
- const relScript = path.relative(PROJECT_ROOT, localPath).replace(/\\/g, "/");
167
- syncHookScript = `node ${relScript}`;
168
- } else {
169
- log(" ⏭️ sync-hook script not found, skipping");
170
- return;
171
- }
172
-
173
- const hookEntry = {
174
- matcher: "Edit|Write",
175
- command: `${syncHookScript} "$TOOL_INPUT_FILE"`
176
- };
177
-
178
- let settings = {};
179
- if (fs.existsSync(settingsPath)) {
180
- try {
181
- settings = JSON.parse(fs.readFileSync(settingsPath, "utf-8"));
182
- } catch {
183
- // Malformed JSON — start fresh but warn
184
- log(" ⚠️ Existing settings.json was malformed, recreating");
185
- settings = {};
186
- }
187
- }
188
-
189
- // Ensure hooks.PostToolUse array exists
190
- if (!settings.hooks) settings.hooks = {};
191
- if (!Array.isArray(settings.hooks.PostToolUse)) settings.hooks.PostToolUse = [];
192
-
193
- // Check if sync-hook is already installed (avoid duplicates)
194
- const alreadyInstalled = settings.hooks.PostToolUse.some(
195
- (h) => h.command && h.command.includes("sync-hook")
196
- );
197
-
198
- if (alreadyInstalled) {
199
- log(" ✅ Sync hooks already installed");
200
- return;
201
- }
202
-
203
- settings.hooks.PostToolUse.push(hookEntry);
204
-
205
- ensureDir(path.dirname(settingsPath));
206
- fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
207
- log(" ✅ Sync hooks installed → .claude/settings.json");
208
- log(` Hook: PostToolUse (Edit|Write) → ${syncHookScript}`);
209
- }
210
-
211
153
  // ─── Command: init ───────────────────────────────────────
212
154
  async function cmdInit() {
213
155
  // ─── Prerequisites check ───────────────────────────────────
@@ -308,11 +250,6 @@ async function cmdInit() {
308
250
  }
309
251
  log(" ✅ Done\n");
310
252
 
311
- // ─── [2.5] Install sync hooks in .claude/settings.json ────
312
- header("[2.5] Installing sync hooks...");
313
- installSyncHooks();
314
- log("");
315
-
316
253
  // ─── [3] Run plan-installer ─────────────────────────
317
254
  header("[3] Analyzing project (plan-installer)...");
318
255
  run(`node "${path.join(TOOLS_DIR, "plan-installer/index.js")}"`);
package/bootstrap.sh CHANGED
@@ -74,6 +74,7 @@ if [ "$VALID" = false ]; then
74
74
  fi
75
75
 
76
76
  export CLAUDEOS_LANG
77
+ export CLAUDEOS_ROOT="$PROJECT_ROOT"
77
78
 
78
79
  # ─── Prompt placeholder substitution helper ────────────────────
79
80
  inject_project_root() {
@@ -102,7 +102,7 @@ async function main() {
102
102
  errors.push({ file: r, type: "EMPTY", msg: "Empty file" });
103
103
  continue;
104
104
  }
105
- // All rules (except sync) must have paths: ["**/*"] frontmatter
105
+ // All rules (except sync reminders) must have paths: ["**/*"] frontmatter
106
106
  if (!r.includes("50.sync")) {
107
107
  const hasFrontmatter = c.startsWith("---");
108
108
  const hasPathsKey = c.includes("paths:");
@@ -24,14 +24,14 @@ const GEN = path.join(ROOT, "claudeos-core/generated");
24
24
 
25
25
  function run(name, script) {
26
26
  try {
27
- const output = execSync(`node ${script}`, {
27
+ const output = execSync(`node "${script}"`, {
28
28
  cwd: ROOT,
29
29
  encoding: "utf-8",
30
30
  stdio: ["pipe", "pipe", "pipe"],
31
31
  });
32
32
  return { name, ok: true, output };
33
33
  } catch (e) {
34
- return { name, ok: false, output: e.stdout || "", exitCode: e.status || 1 };
34
+ return { name, ok: false, output: e.stdout || e.stderr || e.message || "", exitCode: e.status || 1 };
35
35
  }
36
36
  }
37
37
 
@@ -3,10 +3,9 @@
3
3
  /**
4
4
  * ClaudeOS-Core — Manifest Generator
5
5
  *
6
- * Role: Generate 4 types of metadata JSON + initialize stale-report
6
+ * Role: Generate metadata JSON + initialize stale-report
7
7
  * Output (claudeos-core/generated/):
8
8
  * - rule-manifest.json : rules/standard/skills/guide file list + frontmatter
9
- * - import-graph.json : (deprecated — kept for backward compatibility, @import removed)
10
9
  * - sync-map.json : plan/ <file> block → file path mapping
11
10
  * - plan-manifest.json : plan/ file list + <file> block count
12
11
  * - stale-report.json : initialized (each verification tool appends results)
@@ -117,16 +116,7 @@ async function main() {
117
116
  fs.writeFileSync(path.join(GEN, "rule-manifest.json"), JSON.stringify(mf, null, 2));
118
117
  console.log(` ✅ rule-manifest.json — ${mf.summary.total} files indexed`);
119
118
 
120
- // ─── import-graph.json (deprecated — @import removed) ──
121
- const gr = {
122
- generatedAt: new Date().toISOString(),
123
- deprecated: true,
124
- note: "@import is not a Claude Code feature and has been removed. Rules now use paths: [\"**/*\"] frontmatter.",
125
- nodes: [], edges: [], errors: [],
126
- summary: { totalNodes: 0, totalEdges: 0, brokenImports: 0 },
127
- };
128
- fs.writeFileSync(path.join(GEN, "import-graph.json"), JSON.stringify(gr, null, 2));
129
- console.log(" ✅ import-graph.json — deprecated (no @imports)");
119
+ // import-graph.json removed — @import was never a Claude Code feature
130
120
 
131
121
  // ─── sync-map.json ─────────────────────────────────────
132
122
  const sm = { generatedAt: new Date().toISOString(), mappings: [] };
@@ -158,7 +148,7 @@ async function main() {
158
148
  JSON.stringify({ generatedAt: new Date().toISOString(), summary: { totalIssues: 0, status: "initial" } }, null, 2)
159
149
  );
160
150
  console.log(" ✅ stale-report.json — initialized");
161
- console.log("\n 📁 Output: claudeos-core/generated/ (5 files)\n");
151
+ console.log("\n 📁 Output: claudeos-core/generated/ (4 files)\n");
162
152
  }
163
153
 
164
154
  main().catch(e => { console.error(e); process.exit(1); });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudeos-core",
3
- "version": "1.2.2",
3
+ "version": "1.2.4",
4
4
  "description": "Auto-generate Claude Code documentation from your actual source code — Standards, Rules, Skills, and Guides tailored to your project",
5
5
  "main": "bin/cli.js",
6
6
  "bin": {
@@ -10,14 +10,12 @@
10
10
  "bin/",
11
11
  "content-validator/",
12
12
  "health-checker/",
13
- "import-linter/",
14
13
  "manifest-generator/",
15
14
  "pass-json-validator/",
16
15
  "pass-prompts/",
17
16
  "plan-installer/",
18
17
  "plan-validator/",
19
18
  "sync-checker/",
20
- "sync-hook/",
21
19
  "bootstrap.sh",
22
20
  "README.md",
23
21
  "README.ko.md",
@@ -215,9 +215,9 @@ async function main() {
215
215
  const normalizedKeys = keys.map(normalize);
216
216
  for (const section of sectionsToCheck) {
217
217
  const sectionNorm = normalize(section);
218
- // Exact normalized match first, then containment (only for names >= 6 chars to avoid false positives)
218
+ // Exact normalized match first, then check if any key contains the section name (one-direction only to avoid false positives)
219
219
  const found = normalizedKeys.some(k => k === sectionNorm)
220
- || (sectionNorm.length >= 6 && normalizedKeys.some(k => k.includes(sectionNorm) || sectionNorm.includes(k)));
220
+ || (sectionNorm.length >= 6 && normalizedKeys.some(k => k.includes(sectionNorm)));
221
221
  if (!found) {
222
222
  warnings.push({
223
223
  file: "pass2-merged.json",
@@ -81,8 +81,7 @@ Generation targets:
81
81
  List only the standard files that were actually generated above. Include frontend standards only if frontend was detected.
82
82
 
83
83
  4. .claude/rules/50.sync/ (3 sync rules — AI fallback reminders)
84
- - NOTE: Actual sync is handled automatically by hooks in .claude/settings.json (PostToolUse sync-hook).
85
- These rules serve as a backup reminder for AI in case hooks fail or are not installed.
84
+ - NOTE: These rules remind AI to run `npx claudeos-core refresh` after modifying standard/rules/skills files.
86
85
  - 01.standard-sync.md — Remind AI to update plan/10 when standard is modified
87
86
  - 02.rules-sync.md — Remind AI to update plan/20 when rules are modified
88
87
  - 03.skills-sync.md — Remind AI to update plan/30 when skills are modified
@@ -87,8 +87,7 @@ Generation targets:
87
87
  List only the standard files that were actually generated above. Include frontend standards only if frontend was detected.
88
88
 
89
89
  4. .claude/rules/50.sync/ (3 sync rules — AI fallback reminders)
90
- - NOTE: Actual sync is handled automatically by hooks in .claude/settings.json (PostToolUse sync-hook).
91
- These rules serve as a backup reminder for AI in case hooks fail or are not installed.
90
+ - NOTE: These rules remind AI to run `npx claudeos-core refresh` after modifying standard/rules/skills files.
92
91
  - 01.standard-sync.md — Remind AI to update plan/10 when standard is modified
93
92
  - 02.rules-sync.md — Remind AI to update plan/20 when rules is modified
94
93
  - 03.skills-sync.md — Remind AI to update plan/30 when skills is modified
@@ -80,8 +80,7 @@ Generation targets:
80
80
  List only the standard files that were actually generated above.
81
81
 
82
82
  4. .claude/rules/50.sync/ (3 sync rules — AI fallback reminders)
83
- - NOTE: Actual sync is handled automatically by hooks in .claude/settings.json (PostToolUse sync-hook).
84
- These rules serve as a backup reminder for AI in case hooks fail or are not installed.
83
+ - NOTE: These rules remind AI to run `npx claudeos-core refresh` after modifying standard/rules/skills files.
85
84
  - 01.standard-sync.md — Remind AI to update plan/10 when standard is modified
86
85
  - 02.rules-sync.md — Remind AI to update plan/20 when rules is modified
87
86
  - 03.skills-sync.md — Remind AI to update plan/30 when skills is modified
@@ -77,8 +77,7 @@ Generation targets:
77
77
  List only the standard files that were actually generated above.
78
78
 
79
79
  4. .claude/rules/50.sync/ (3 sync rules — AI fallback reminders)
80
- - NOTE: Actual sync is handled automatically by hooks in .claude/settings.json (PostToolUse sync-hook).
81
- These rules serve as a backup reminder for AI in case hooks fail or are not installed.
80
+ - NOTE: These rules remind AI to run `npx claudeos-core refresh` after modifying standard/rules/skills files.
82
81
  - 01.standard-sync.md — Remind AI to update plan/10 when standard is modified
83
82
  - 02.rules-sync.md — Remind AI to update plan/20 when rules is modified
84
83
  - 03.skills-sync.md — Remind AI to update plan/30 when skills is modified
@@ -80,8 +80,7 @@ Generation targets:
80
80
  List only the standard files that were actually generated above.
81
81
 
82
82
  4. .claude/rules/50.sync/ (3 sync rules — AI fallback reminders)
83
- - NOTE: Actual sync is handled automatically by hooks in .claude/settings.json (PostToolUse sync-hook).
84
- These rules serve as a backup reminder for AI in case hooks fail or are not installed.
83
+ - NOTE: These rules remind AI to run `npx claudeos-core refresh` after modifying standard/rules/skills files.
85
84
  - 01.standard-sync.md — Remind AI to update plan/10 when standard is modified
86
85
  - 02.rules-sync.md — Remind AI to update plan/20 when rules is modified
87
86
  - 03.skills-sync.md — Remind AI to update plan/30 when skills is modified
@@ -80,8 +80,7 @@ Generation targets:
80
80
  List only the standard files that were actually generated above.
81
81
 
82
82
  4. .claude/rules/50.sync/ (3 sync rules — AI fallback reminders)
83
- - NOTE: Actual sync is handled automatically by hooks in .claude/settings.json (PostToolUse sync-hook).
84
- These rules serve as a backup reminder for AI in case hooks fail or are not installed.
83
+ - NOTE: These rules remind AI to run `npx claudeos-core refresh` after modifying standard/rules/skills files.
85
84
  - 01.standard-sync.md — Remind AI to update plan/10 when standard is modified
86
85
  - 02.rules-sync.md — Remind AI to update plan/20 when rules is modified
87
86
  - 03.skills-sync.md — Remind AI to update plan/30 when skills is modified
@@ -197,7 +197,7 @@ async function detectStack() {
197
197
  let pkg;
198
198
  try { pkg = JSON.parse(fs.readFileSync(path.join(ROOT, "package.json"), "utf-8")); }
199
199
  catch { console.warn(" ⚠️ package.json parse error — skipping Node.js detection"); pkg = null; }
200
- if (!pkg) return stack;
200
+ if (pkg) {
201
201
  stack.detected.push("package.json");
202
202
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
203
203
 
@@ -231,6 +231,7 @@ async function detectStack() {
231
231
  : fs.existsSync(path.join(ROOT, "yarn.lock")) ? "yarn" : "npm";
232
232
 
233
233
  if (pkg.engines && pkg.engines.node && !stack.languageVersion) stack.languageVersion = pkg.engines.node;
234
+ } // end if (pkg)
234
235
  }
235
236
 
236
237
  // ── Python ──
@@ -1275,6 +1276,11 @@ async function main() {
1275
1276
  const stack = await detectStack();
1276
1277
  console.log(` Language: ${stack.language || "unknown"} ${stack.languageVersion || ""}`);
1277
1278
  console.log(` Framework: ${stack.framework || "none"} ${stack.frameworkVersion || ""}`);
1279
+ if (!stack.language && !stack.framework) {
1280
+ console.warn("\n ⚠️ No language or framework detected.");
1281
+ console.warn(" Supported: Java, Kotlin, TypeScript, JavaScript, Python");
1282
+ console.warn(" Ensure you have build.gradle, package.json, pyproject.toml, or requirements.txt in the project root.\n");
1283
+ }
1278
1284
  console.log(` Frontend: ${stack.frontend || "none"} ${stack.frontendVersion || ""}`);
1279
1285
  console.log(` Database: ${stack.database || "none"}`);
1280
1286
  console.log(` ORM: ${stack.orm || "none"}`);
@@ -1288,6 +1294,11 @@ async function main() {
1288
1294
  console.log(` Total: ${domains.length} domains`);
1289
1295
  if (rootPackage) console.log(` Package: ${rootPackage}`);
1290
1296
  if (frontend.exists) console.log(` Components: ${frontend.components} components, ${frontend.pages} pages, ${frontend.hooks} hooks`);
1297
+ if (backendDomains.length === 0 && frontendDomains.length === 0) {
1298
+ console.warn("\n ⚠️ No domains detected.");
1299
+ console.warn(" Pass 1 will be skipped. Generated output may be minimal.");
1300
+ console.warn(" Check your project structure — see README for supported patterns.\n");
1301
+ }
1291
1302
  console.log();
1292
1303
 
1293
1304
  // Phase 3: Template selection (multi-stack)
@@ -1374,4 +1385,10 @@ async function main() {
1374
1385
  console.log(" ✅ Plan Installer complete\n");
1375
1386
  }
1376
1387
 
1377
- main().catch(e => { console.error(e); process.exit(1); });
1388
+ main().catch(e => {
1389
+ console.error(`\n ❌ Plan Installer failed: ${e.message || e}`);
1390
+ if (e.code === "EACCES" || e.code === "EPERM") {
1391
+ console.error(" Check file/directory permissions.");
1392
+ }
1393
+ process.exit(1);
1394
+ });
@@ -126,6 +126,12 @@ async function main() {
126
126
  total++;
127
127
  const abs = path.join(ROOT, b.path);
128
128
 
129
+ // Block path traversal attempts
130
+ if (!path.resolve(abs).startsWith(path.resolve(ROOT))) {
131
+ console.log(` ⚠️ SKIPPED: ${b.path} (path traversal blocked)`);
132
+ continue;
133
+ }
134
+
129
135
  // File does not exist
130
136
  if (!fs.existsSync(abs)) {
131
137
  if (mode === "--execute") {
@@ -76,7 +76,10 @@ async function main() {
76
76
  // ─── [2/2] Plan → Disk: detect orphaned files ───────────────
77
77
  console.log(" [2/2] Plan → Disk...");
78
78
  for (const m of sm.mappings) {
79
- if (!fs.existsSync(path.join(ROOT, m.sourcePath))) {
79
+ const abs = path.join(ROOT, m.sourcePath);
80
+ // Skip path traversal attempts
81
+ if (!path.resolve(abs).startsWith(path.resolve(ROOT))) continue;
82
+ if (!fs.existsSync(abs)) {
80
83
  issues.orphan.push({ path: m.sourcePath, plan: m.planFile });
81
84
  }
82
85
  }
@@ -1,171 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * ClaudeOS-Core — Import Linter (DEPRECATED)
5
- *
6
- * @deprecated @import is not a real Claude Code feature and has been removed.
7
- * Rules now use paths frontmatter with wildcard glob to ensure they are always loaded.
8
- * This tool is kept for backward compatibility but is no longer run by health-checker.
9
- *
10
- * Usage: node claudeos-core-tools/import-linter/index.js
11
- */
12
-
13
- const fs = require("fs");
14
- const path = require("path");
15
- const { glob } = require("glob");
16
-
17
- const ROOT = process.env.CLAUDEOS_ROOT || path.resolve(__dirname, "../..");
18
- const SCAN = [
19
- ".claude/rules",
20
- "claudeos-core/standard",
21
- "claudeos-core/skills",
22
- "claudeos-core/guide",
23
- "claudeos-core/database",
24
- "claudeos-core/mcp-guide",
25
- ];
26
-
27
- function rel(p) {
28
- return path.relative(ROOT, p).replace(/\\/g, "/");
29
- }
30
-
31
- function extractImports(f) {
32
- const content = fs.readFileSync(f, "utf-8");
33
- const result = [];
34
- let inCodeFence = false;
35
- content.split("\n").forEach((line, i) => {
36
- // Track code fence boundaries to skip @-lines inside code blocks
37
- if (/^```/.test(line)) { inCodeFence = !inCodeFence; return; }
38
- if (inCodeFence) return;
39
- const m = line.match(/^@(\.\.?\/[^\s]+)/);
40
- if (m) {
41
- const target = path.resolve(path.dirname(f), m[1]);
42
- result.push({
43
- raw: m[0],
44
- rawPath: m[1],
45
- resolved: target,
46
- resolvedRel: rel(target),
47
- exists: fs.existsSync(target),
48
- line: i + 1,
49
- });
50
- }
51
- });
52
- return result;
53
- }
54
-
55
- function detectCycles(adj) {
56
- const cycles = [];
57
- const visited = new Set();
58
- const inStack = new Set();
59
-
60
- function dfs(n, pathSoFar) {
61
- visited.add(n);
62
- inStack.add(n);
63
- for (const nb of adj[n] || []) {
64
- if (!visited.has(nb)) {
65
- const c = dfs(nb, [...pathSoFar, nb]);
66
- if (c) return c;
67
- } else if (inStack.has(nb)) {
68
- const ci = pathSoFar.indexOf(nb);
69
- return [...pathSoFar.slice(ci), nb];
70
- }
71
- }
72
- inStack.delete(n);
73
- return null;
74
- }
75
-
76
- for (const n of Object.keys(adj)) {
77
- if (!visited.has(n)) {
78
- const c = dfs(n, [n]);
79
- if (c) cycles.push(c);
80
- }
81
- }
82
- return cycles;
83
- }
84
-
85
- async function main() {
86
- console.log("\n╔══════════════════════════════════════╗");
87
- console.log("║ ClaudeOS-Core — Import Linter ║");
88
- console.log("╚══════════════════════════════════════╝\n");
89
-
90
- const errors = [];
91
- const warnings = [];
92
- let totalImports = 0;
93
- let totalFiles = 0;
94
- const adj = {};
95
-
96
- for (const d of SCAN) {
97
- const abs = path.join(ROOT, d);
98
- if (!fs.existsSync(abs)) {
99
- console.log(` ⏭️ Skipping: ${d}`);
100
- continue;
101
- }
102
-
103
- for (const f of await glob("**/*.md", { cwd: abs, absolute: true })) {
104
- const r = rel(f);
105
- const imps = extractImports(f);
106
- if (!imps.length) continue;
107
-
108
- totalFiles++;
109
- totalImports += imps.length;
110
- adj[r] = [];
111
- const seen = new Set();
112
-
113
- for (const i of imps) {
114
- adj[r].push(i.resolvedRel);
115
-
116
- if (!i.exists) {
117
- errors.push({
118
- type: "BROKEN",
119
- file: r,
120
- line: i.line,
121
- target: i.resolvedRel,
122
- msg: `${r}:${i.line} → ${i.resolvedRel} (NOT FOUND)`,
123
- });
124
- }
125
-
126
- if (seen.has(i.resolvedRel)) {
127
- warnings.push({
128
- type: "DUP",
129
- file: r,
130
- line: i.line,
131
- target: i.resolvedRel,
132
- msg: `${r}:${i.line} → ${i.resolvedRel} (DUPLICATE)`,
133
- });
134
- }
135
- seen.add(i.resolvedRel);
136
- }
137
- }
138
- }
139
-
140
- // Cycle detection
141
- for (const c of detectCycles(adj)) {
142
- errors.push({
143
- type: "CIRCULAR",
144
- cycle: c,
145
- msg: `Circular: ${c.join(" → ")}`,
146
- });
147
- }
148
-
149
- console.log(` Scanned ${totalFiles} files, ${totalImports} @imports\n`);
150
-
151
- if (!errors.length && !warnings.length) {
152
- console.log(` ✅ ${totalImports}/${totalImports} valid\n`);
153
- process.exit(0);
154
- }
155
-
156
- if (errors.length) {
157
- console.log(` ❌ ERRORS (${errors.length}):`);
158
- errors.forEach((e) => console.log(` ${e.msg}`));
159
- console.log();
160
- }
161
- if (warnings.length) {
162
- console.log(` ⚠️ WARNINGS (${warnings.length}):`);
163
- warnings.forEach((w) => console.log(` ${w.msg}`));
164
- console.log();
165
- }
166
-
167
- console.log(` Total issues: ${errors.length + warnings.length}\n`);
168
- process.exit(errors.length ? 1 : 0);
169
- }
170
-
171
- main().catch(console.error);
@@ -1,203 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- //
4
- // ClaudeOS-Core — Sync Hook
5
- //
6
- // Role: Automatically sync disk files to Master Plan when files are modified.
7
- // Triggered by Claude Code hooks (PostToolUse) after Edit/Write operations.
8
- //
9
- // How it works:
10
- // 1. Receives the modified file path from hook environment ($TOOL_INPUT_FILE or argv)
11
- // 2. Determines which plan file(s) contain this file as a <file> block
12
- // 3. Reads the current disk content and updates the plan block in-place
13
- //
14
- // Mapping:
15
- // CLAUDE.md, claudeos-core/standard/ -> plan/10.standard-master.md
16
- // .claude/rules/ (except 50.sync/) -> plan/20.rules-master.md
17
- // .claude/rules/50.sync/ -> plan/21.sync-rules-master.md
18
- // claudeos-core/skills/10.backend-*/ -> plan/30.backend-skills-master.md
19
- // claudeos-core/skills/20.frontend-*/ -> plan/31.frontend-skills-master.md
20
- // claudeos-core/guide/ -> plan/40.guides-master.md
21
- //
22
- // Usage:
23
- // node claudeos-core-tools/sync-hook/index.js <modified-file-path>
24
- //
25
- // Or via Claude Code hooks (.claude/settings.json):
26
- // {
27
- // "hooks": {
28
- // "PostToolUse": [{
29
- // "matcher": "Edit|Write",
30
- // "command": "node claudeos-core-tools/sync-hook/index.js \"$TOOL_INPUT_FILE\""
31
- // }]
32
- // }
33
- // }
34
- //
35
-
36
- const fs = require("fs");
37
- const path = require("path");
38
-
39
- const ROOT = process.env.CLAUDEOS_ROOT || process.cwd();
40
- const PLAN_DIR = path.join(ROOT, "claudeos-core/plan");
41
-
42
- // ─── Path → Plan mapping ────────────────────────────────────
43
- const PLAN_MAP = [
44
- { pattern: /^CLAUDE\.md$/, plan: "10.standard-master.md", format: "file" },
45
- { pattern: /^claudeos-core\/standard\//, plan: "10.standard-master.md", format: "file" },
46
- { pattern: /^\.claude\/rules\/50\.sync\//, plan: "21.sync-rules-master.md", format: "code" },
47
- { pattern: /^\.claude\/rules\//, plan: "20.rules-master.md", format: "file" },
48
- { pattern: /^claudeos-core\/skills\/10\.backend/, plan: "30.backend-skills-master.md", format: "file" },
49
- { pattern: /^claudeos-core\/skills\/20\.frontend/, plan: "31.frontend-skills-master.md", format: "file" },
50
- { pattern: /^claudeos-core\/skills\/00\.shared/, plan: "30.backend-skills-master.md", format: "file" },
51
- { pattern: /^claudeos-core\/guide\//, plan: "40.guides-master.md", format: "file" },
52
- { pattern: /^claudeos-core\/database\//, plan: "10.standard-master.md", format: "file" },
53
- { pattern: /^claudeos-core\/mcp-guide\//, plan: "10.standard-master.md", format: "file" },
54
- ];
55
-
56
- function rel(filePath) {
57
- return path.relative(ROOT, path.resolve(filePath)).replace(/\\/g, "/");
58
- }
59
-
60
- // ─── Find which plan file to update ─────────────────────────
61
- function findPlanTarget(relPath) {
62
- for (const entry of PLAN_MAP) {
63
- if (entry.pattern.test(relPath)) {
64
- return entry;
65
- }
66
- }
67
- return null;
68
- }
69
-
70
- // ─── Replace <file path="..."> block in plan ────────────────
71
- function replaceFileBlock(planContent, filePath, newContent) {
72
- const escaped = filePath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
73
- const regex = new RegExp(
74
- `(<file\\s+path="${escaped}">\\s*\\n)[\\s\\S]*?(\\n</file>)`,
75
- "g"
76
- );
77
-
78
- if (!regex.test(planContent)) {
79
- return null; // block not found in plan
80
- }
81
-
82
- return planContent.replace(regex, `$1${newContent}$2`);
83
- }
84
-
85
- // ─── Replace ```markdown code block in plan ─────────────────
86
- function replaceCodeBlock(planContent, filePath, newContent) {
87
- const cleanPath = filePath.replace(/`/g, "");
88
- const headingPattern = new RegExp(
89
- `^##\\s+\\d+\\.\\s+\`?${cleanPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\`?`,
90
- "m"
91
- );
92
-
93
- const headingMatch = headingPattern.exec(planContent);
94
- if (!headingMatch) return null;
95
-
96
- const afterHeading = planContent.indexOf("```markdown\n", headingMatch.index);
97
- if (afterHeading < 0) return null;
98
-
99
- const contentStart = afterHeading + "```markdown\n".length;
100
-
101
- // Find closing ``` respecting nesting
102
- let searchPos = contentStart;
103
- let closingPos = -1;
104
- let nestDepth = 0;
105
-
106
- while (searchPos < planContent.length) {
107
- const nextFence = planContent.indexOf("\n```", searchPos);
108
- if (nextFence < 0) break;
109
-
110
- const lineAfterFence = planContent.substring(
111
- nextFence + 4,
112
- planContent.indexOf("\n", nextFence + 4)
113
- );
114
- const isOpening =
115
- lineAfterFence.trim().length > 0 && !lineAfterFence.startsWith("\n");
116
-
117
- if (isOpening) {
118
- nestDepth++;
119
- searchPos = nextFence + 4;
120
- } else if (nestDepth > 0) {
121
- nestDepth--;
122
- searchPos = nextFence + 4;
123
- } else {
124
- closingPos = nextFence + 1;
125
- break;
126
- }
127
- }
128
-
129
- if (closingPos < 0) return null;
130
-
131
- return (
132
- planContent.substring(0, contentStart) +
133
- newContent +
134
- "\n" +
135
- planContent.substring(closingPos)
136
- );
137
- }
138
-
139
- // ─── Main ───────────────────────────────────────────────────
140
- function main() {
141
- // Get modified file path from argument or environment
142
- const inputFile = process.argv[2] || process.env.TOOL_INPUT_FILE;
143
-
144
- if (!inputFile) {
145
- // Silent exit — hook may fire for non-file operations
146
- process.exit(0);
147
- }
148
-
149
- const relPath = rel(inputFile);
150
-
151
- // Skip non-.md files
152
- if (!relPath.endsWith(".md")) {
153
- process.exit(0);
154
- }
155
-
156
- // Skip files outside tracked directories
157
- const target = findPlanTarget(relPath);
158
- if (!target) {
159
- process.exit(0);
160
- }
161
-
162
- // Skip if plan directory doesn't exist (not yet initialized)
163
- if (!fs.existsSync(PLAN_DIR)) {
164
- process.exit(0);
165
- }
166
-
167
- const planFile = path.join(PLAN_DIR, target.plan);
168
-
169
- // Skip if target plan file doesn't exist
170
- if (!fs.existsSync(planFile)) {
171
- process.exit(0);
172
- }
173
-
174
- const absFile = path.join(ROOT, relPath);
175
-
176
- // Skip if source file was deleted (not our job to handle deletions)
177
- if (!fs.existsSync(absFile)) {
178
- process.exit(0);
179
- }
180
-
181
- // Read current disk content and plan content
182
- const diskContent = fs.readFileSync(absFile, "utf-8").trimEnd();
183
- const planContent = fs.readFileSync(planFile, "utf-8");
184
-
185
- // Attempt to replace the block
186
- let updated;
187
- if (target.format === "code") {
188
- updated = replaceCodeBlock(planContent, relPath, diskContent);
189
- } else {
190
- updated = replaceFileBlock(planContent, relPath, diskContent);
191
- }
192
-
193
- if (updated && updated !== planContent) {
194
- fs.writeFileSync(planFile, updated);
195
- // Brief output for hook log (visible in Claude Code)
196
- console.log(`[sync-hook] ${relPath} → ${target.plan}`);
197
- }
198
-
199
- // Silent exit if no block found (file not yet in plan) or no change
200
- process.exit(0);
201
- }
202
-
203
- main();