javi-forge 1.3.0 → 1.5.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 (121) hide show
  1. package/ci-local/ci-local.sh +9 -1
  2. package/ci-local/hooks/commit-msg +0 -0
  3. package/ci-local/hooks/pre-commit +1 -1
  4. package/ci-local/hooks/pre-push +0 -0
  5. package/ci-local/install.sh +0 -0
  6. package/ci-local/lib/common.sh +183 -0
  7. package/dist/__integration__/helpers.d.ts +20 -0
  8. package/dist/__integration__/helpers.d.ts.map +1 -0
  9. package/dist/__integration__/helpers.js +31 -0
  10. package/dist/__integration__/helpers.js.map +1 -0
  11. package/dist/commands/analyze.d.ts.map +1 -0
  12. package/dist/commands/analyze.js.map +1 -0
  13. package/dist/commands/ci.d.ts +4 -0
  14. package/dist/commands/ci.d.ts.map +1 -0
  15. package/dist/commands/ci.js +110 -8
  16. package/dist/commands/ci.js.map +1 -0
  17. package/dist/commands/doctor.d.ts.map +1 -0
  18. package/dist/commands/doctor.js +1 -3
  19. package/dist/commands/doctor.js.map +1 -0
  20. package/dist/commands/init.d.ts.map +1 -0
  21. package/dist/commands/init.js +14 -6
  22. package/dist/commands/init.js.map +1 -0
  23. package/dist/commands/llmstxt.d.ts.map +1 -0
  24. package/dist/commands/llmstxt.js.map +1 -0
  25. package/dist/commands/plugin.d.ts.map +1 -0
  26. package/dist/commands/plugin.js.map +1 -0
  27. package/dist/constants.d.ts +0 -4
  28. package/dist/constants.d.ts.map +1 -0
  29. package/dist/constants.js +0 -4
  30. package/dist/constants.js.map +1 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +37 -11
  33. package/dist/index.js.map +1 -0
  34. package/dist/lib/common.d.ts.map +1 -0
  35. package/dist/lib/common.js.map +1 -0
  36. package/dist/lib/docker.d.ts +2 -0
  37. package/dist/lib/docker.d.ts.map +1 -0
  38. package/dist/lib/docker.js +2 -1
  39. package/dist/lib/docker.js.map +1 -0
  40. package/dist/lib/frontmatter.d.ts.map +1 -0
  41. package/dist/lib/frontmatter.js.map +1 -0
  42. package/dist/lib/plugin.d.ts.map +1 -0
  43. package/dist/lib/plugin.js.map +1 -0
  44. package/dist/lib/template.d.ts.map +1 -0
  45. package/dist/lib/template.js.map +1 -0
  46. package/dist/types/index.d.ts.map +1 -0
  47. package/dist/types/index.js.map +1 -0
  48. package/dist/ui/AnalyzeUI.d.ts.map +1 -0
  49. package/dist/ui/AnalyzeUI.js.map +1 -0
  50. package/dist/ui/App.d.ts.map +1 -0
  51. package/dist/ui/App.js.map +1 -0
  52. package/dist/ui/CI.d.ts.map +1 -0
  53. package/dist/ui/CI.js.map +1 -0
  54. package/dist/ui/CIContext.d.ts.map +1 -0
  55. package/dist/ui/CIContext.js.map +1 -0
  56. package/dist/ui/CISelector.d.ts.map +1 -0
  57. package/dist/ui/CISelector.js.map +1 -0
  58. package/dist/ui/Doctor.d.ts.map +1 -0
  59. package/dist/ui/Doctor.js +1 -1
  60. package/dist/ui/Doctor.js.map +1 -0
  61. package/dist/ui/Header.d.ts.map +1 -0
  62. package/dist/ui/Header.js.map +1 -0
  63. package/dist/ui/LlmsTxt.d.ts.map +1 -0
  64. package/dist/ui/LlmsTxt.js.map +1 -0
  65. package/dist/ui/MemorySelector.d.ts.map +1 -0
  66. package/dist/ui/MemorySelector.js.map +1 -0
  67. package/dist/ui/NameInput.d.ts.map +1 -0
  68. package/dist/ui/NameInput.js.map +1 -0
  69. package/dist/ui/OptionSelector.d.ts.map +1 -0
  70. package/dist/ui/OptionSelector.js +1 -1
  71. package/dist/ui/OptionSelector.js.map +1 -0
  72. package/dist/ui/Plugin.d.ts.map +1 -0
  73. package/dist/ui/Plugin.js.map +1 -0
  74. package/dist/ui/Progress.d.ts.map +1 -0
  75. package/dist/ui/Progress.js.map +1 -0
  76. package/dist/ui/StackSelector.d.ts.map +1 -0
  77. package/dist/ui/StackSelector.js.map +1 -0
  78. package/dist/ui/Summary.d.ts.map +1 -0
  79. package/dist/ui/Summary.js.map +1 -0
  80. package/dist/ui/Welcome.d.ts.map +1 -0
  81. package/dist/ui/Welcome.js.map +1 -0
  82. package/dist/ui/theme.d.ts.map +1 -0
  83. package/dist/ui/theme.js.map +1 -0
  84. package/lib/common.sh +2 -2
  85. package/modules/ghagga/README.md +2 -2
  86. package/modules/ghagga/setup-ghagga.sh +1 -1
  87. package/package.json +25 -12
  88. package/templates/github/ci-go.yml +1 -1
  89. package/templates/github/ci-java.yml +2 -2
  90. package/templates/github/ci-node.yml +1 -1
  91. package/templates/github/ci-python.yml +1 -1
  92. package/templates/github/ci-rust.yml +1 -1
  93. package/templates/github/ghagga-review.yml +28 -0
  94. package/workflows/reusable-build-go.yml +1 -1
  95. package/workflows/reusable-build-java.yml +1 -1
  96. package/workflows/reusable-build-node.yml +1 -1
  97. package/workflows/reusable-build-python.yml +1 -1
  98. package/workflows/reusable-build-rust.yml +1 -1
  99. package/workflows/reusable-docker.yml +1 -1
  100. package/workflows/reusable-ghagga-review.yml +1 -1
  101. package/workflows/reusable-release.yml +1 -1
  102. package/.releaserc +0 -45
  103. package/dist/commands/analyze.test.d.ts +0 -2
  104. package/dist/commands/doctor.test.d.ts +0 -2
  105. package/dist/commands/init.test.d.ts +0 -2
  106. package/dist/commands/llmstxt.test.d.ts +0 -2
  107. package/dist/commands/plugin.test.d.ts +0 -2
  108. package/dist/commands/sync.d.ts +0 -8
  109. package/dist/commands/sync.js +0 -201
  110. package/dist/e2e/aggressive.e2e.test.d.ts +0 -2
  111. package/dist/e2e/commands.e2e.test.d.ts +0 -2
  112. package/dist/lib/common.test.d.ts +0 -2
  113. package/dist/lib/frontmatter.test.d.ts +0 -2
  114. package/dist/lib/plugin.test.d.ts +0 -2
  115. package/dist/lib/template.test.d.ts +0 -2
  116. package/dist/ui/SyncUI.d.ts +0 -10
  117. package/dist/ui/SyncUI.js +0 -64
  118. package/tasks/_TEMPLATE/files-edited.md +0 -3
  119. package/tasks/_TEMPLATE/plan.md +0 -3
  120. package/tasks/_TEMPLATE/research.md +0 -3
  121. package/tasks/_TEMPLATE/verification.md +0 -5
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../src/ui/theme.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,KAAK;;;;;;;CAOR,CAAA;AAEV,MAAM,MAAM,UAAU,GAAG,OAAO,KAAK,CAAC,MAAM,OAAO,KAAK,CAAC,CAAA"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme.js","sourceRoot":"","sources":["../../src/ui/theme.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,OAAO,EAAG,SAAS,EAAG,SAAS;IAC/B,OAAO,EAAG,OAAO;IACjB,OAAO,EAAG,QAAQ;IAClB,KAAK,EAAK,KAAK;IACf,KAAK,EAAK,MAAM;IAChB,MAAM,EAAI,SAAS;CACX,CAAA"}
package/lib/common.sh CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/bin/bash
2
2
  # =============================================================================
3
- # lib/common.sh - Shared functions for project-starter-framework
3
+ # lib/common.sh - Shared functions for javi-forge
4
4
  # =============================================================================
5
5
  # Source from scripts: source "$(dirname "$0")/../lib/common.sh"
6
6
  # Source from ci-local: source "$(dirname "$0")/../lib/common.sh"
@@ -161,7 +161,7 @@ detect_stack() {
161
161
  }
162
162
 
163
163
  # =============================================================================
164
- # detect_framework - Locate the project-starter-framework directory
164
+ # detect_framework - Locate the javi-forge directory
165
165
  # =============================================================================
166
166
  # Sets: FRAMEWORK_DIR (path to framework root, or empty string)
167
167
  # HAS_OPTIONAL (true/false if optional/ dir exists)
@@ -60,7 +60,7 @@ En tu `.github/workflows/ci.yml`:
60
60
  ```yaml
61
61
  jobs:
62
62
  review:
63
- uses: JNZader/project-starter-framework/.github/workflows/reusable-ghagga-review.yml@main
63
+ uses: JNZader/javi-forge/.github/workflows/reusable-ghagga-review.yml@main
64
64
  with:
65
65
  ghagga-url: ${{ vars.GHAGGA_URL }}
66
66
  secrets:
@@ -142,7 +142,7 @@ Ejecuta reglas Semgrep como complemento al analisis LLM, cubriendo patrones de s
142
142
 
143
143
  ## Integracion con el Framework
144
144
 
145
- Cuando usas GHAGGA con project-starter-framework:
145
+ Cuando usas GHAGGA con javi-forge:
146
146
 
147
147
  - **CI-Local** valida codigo antes del push (pre-commit, pre-push)
148
148
  - **GHAGGA** revisa el PR despues del push (review automatico)
@@ -50,7 +50,7 @@ concurrency:
50
50
 
51
51
  jobs:
52
52
  review:
53
- uses: JNZader/project-starter-framework/.github/workflows/reusable-ghagga-review.yml@main
53
+ uses: JNZader/javi-forge/.github/workflows/reusable-ghagga-review.yml@main
54
54
  with:
55
55
  ghagga-url: ${{ vars.GHAGGA_URL }}
56
56
  review-mode: simple
package/package.json CHANGED
@@ -1,11 +1,34 @@
1
1
  {
2
2
  "name": "javi-forge",
3
- "version": "1.3.0",
3
+ "version": "1.5.0",
4
4
  "description": "Project scaffolding and AI-ready CI bootstrap",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "javi-forge": "./dist/index.js"
8
8
  },
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "dev": "tsx watch src/index.tsx",
12
+ "start": "node dist/index.js",
13
+ "typecheck": "tsc --noEmit",
14
+ "test": "vitest run",
15
+ "test:watch": "vitest",
16
+ "test:coverage": "vitest run --coverage",
17
+ "test:mutation": "stryker run"
18
+ },
19
+ "files": [
20
+ "dist/",
21
+ "ci-local/",
22
+ "modules/",
23
+ "templates/",
24
+ "workflows/",
25
+ "lib/",
26
+ "!dist/**/*.test.*",
27
+ "!dist/**/__snapshots__",
28
+ "package.json",
29
+ "README.md",
30
+ ".gitignore.template"
31
+ ],
9
32
  "author": "JNZader",
10
33
  "license": "MIT",
11
34
  "repository": {
@@ -45,15 +68,5 @@
45
68
  "tsx": "^4.21.0",
46
69
  "typescript": "^5.9.3",
47
70
  "vitest": "^4.1.0"
48
- },
49
- "scripts": {
50
- "build": "tsc",
51
- "dev": "tsx watch src/index.tsx",
52
- "start": "node dist/index.js",
53
- "typecheck": "tsc --noEmit",
54
- "test": "vitest run",
55
- "test:watch": "vitest",
56
- "test:coverage": "vitest run --coverage",
57
- "test:mutation": "stryker run"
58
71
  }
59
- }
72
+ }
@@ -34,7 +34,7 @@ concurrency:
34
34
 
35
35
  jobs:
36
36
  build:
37
- uses: JNZader/project-starter-framework/.github/workflows/reusable-build-go.yml@main
37
+ uses: JNZader/javi-forge/.github/workflows/reusable-build-go.yml@main
38
38
  with:
39
39
  go-version: '1.23' # Change to: 1.22, 1.23
40
40
  run-lint: true
@@ -3,7 +3,7 @@
3
3
  # ===========================================
4
4
  # Copy to: .github/workflows/ci.yml
5
5
  #
6
- # This uses reusable workflows from project-starter-framework.
6
+ # This uses reusable workflows from javi-forge.
7
7
  # Runs on pushes to main, PRs, and manual triggers.
8
8
  # ===========================================
9
9
 
@@ -37,7 +37,7 @@ concurrency:
37
37
 
38
38
  jobs:
39
39
  build:
40
- uses: JNZader/project-starter-framework/.github/workflows/reusable-build-java.yml@main
40
+ uses: JNZader/javi-forge/.github/workflows/reusable-build-java.yml@main
41
41
  with:
42
42
  java-version: '21' # Change to your version: 17, 21, 25
43
43
  run-spotless: true
@@ -34,7 +34,7 @@ concurrency:
34
34
 
35
35
  jobs:
36
36
  build:
37
- uses: JNZader/project-starter-framework/.github/workflows/reusable-build-node.yml@main
37
+ uses: JNZader/javi-forge/.github/workflows/reusable-build-node.yml@main
38
38
  with:
39
39
  node-version: '20' # Change to: 18, 20, 22
40
40
  package-manager: 'npm' # Change to: npm, yarn, pnpm
@@ -34,7 +34,7 @@ concurrency:
34
34
 
35
35
  jobs:
36
36
  build:
37
- uses: JNZader/project-starter-framework/.github/workflows/reusable-build-python.yml@main
37
+ uses: JNZader/javi-forge/.github/workflows/reusable-build-python.yml@main
38
38
  with:
39
39
  python-version: '3.12' # Change to: 3.10, 3.11, 3.12
40
40
  package-manager: 'pip' # Change to: pip, poetry, uv
@@ -34,7 +34,7 @@ concurrency:
34
34
 
35
35
  jobs:
36
36
  build:
37
- uses: JNZader/project-starter-framework/.github/workflows/reusable-build-rust.yml@main
37
+ uses: JNZader/javi-forge/.github/workflows/reusable-build-rust.yml@main
38
38
  with:
39
39
  toolchain: 'stable' # Change to: stable, beta, nightly
40
40
  run-clippy: true
@@ -0,0 +1,28 @@
1
+ # ===========================================
2
+ # GHAGGA AI Code Review
3
+ # ===========================================
4
+ # Triggers AI code review on pull requests.
5
+ # Requires: GHAGGA GitHub Action (JNZader/ghagga@v1)
6
+ #
7
+ # Modes: simple (default), workflow, consensus
8
+ # ===========================================
9
+
10
+ name: Code Review
11
+
12
+ on:
13
+ pull_request:
14
+ types: [opened, synchronize, reopened]
15
+
16
+ permissions:
17
+ pull-requests: write
18
+ contents: read
19
+
20
+ jobs:
21
+ review:
22
+ runs-on: ubuntu-latest
23
+ steps:
24
+ - uses: actions/checkout@v4
25
+ - uses: JNZader/ghagga@v1
26
+ with:
27
+ mode: simple
28
+ provider: github
@@ -6,7 +6,7 @@
6
6
  # Usage:
7
7
  # jobs:
8
8
  # build:
9
- # uses: JNZader/project-starter-framework/.github/workflows/reusable-build-go.yml@main
9
+ # uses: JNZader/javi-forge/.github/workflows/reusable-build-go.yml@main
10
10
  # with:
11
11
  # go-version: '1.23'
12
12
  # ===========================================
@@ -6,7 +6,7 @@
6
6
  # Usage in your project:
7
7
  # jobs:
8
8
  # build:
9
- # uses: JNZader/project-starter-framework/.github/workflows/reusable-build-java.yml@main
9
+ # uses: JNZader/javi-forge/.github/workflows/reusable-build-java.yml@main
10
10
  # with:
11
11
  # java-version: '21'
12
12
  # ===========================================
@@ -6,7 +6,7 @@
6
6
  # Usage:
7
7
  # jobs:
8
8
  # build:
9
- # uses: JNZader/project-starter-framework/.github/workflows/reusable-build-node.yml@main
9
+ # uses: JNZader/javi-forge/.github/workflows/reusable-build-node.yml@main
10
10
  # with:
11
11
  # node-version: '20'
12
12
  # ===========================================
@@ -6,7 +6,7 @@
6
6
  # Usage:
7
7
  # jobs:
8
8
  # build:
9
- # uses: JNZader/project-starter-framework/.github/workflows/reusable-build-python.yml@main
9
+ # uses: JNZader/javi-forge/.github/workflows/reusable-build-python.yml@main
10
10
  # with:
11
11
  # python-version: '3.12'
12
12
  # ===========================================
@@ -6,7 +6,7 @@
6
6
  # Usage:
7
7
  # jobs:
8
8
  # build:
9
- # uses: JNZader/project-starter-framework/.github/workflows/reusable-build-rust.yml@main
9
+ # uses: JNZader/javi-forge/.github/workflows/reusable-build-rust.yml@main
10
10
  # ===========================================
11
11
 
12
12
  name: Rust Build (Reusable)
@@ -6,7 +6,7 @@
6
6
  # Usage:
7
7
  # jobs:
8
8
  # docker:
9
- # uses: JNZader/project-starter-framework/.github/workflows/reusable-docker.yml@main
9
+ # uses: JNZader/javi-forge/.github/workflows/reusable-docker.yml@main
10
10
  # with:
11
11
  # dockerfile: './Dockerfile'
12
12
  # ===========================================
@@ -6,7 +6,7 @@
6
6
  # Usage:
7
7
  # jobs:
8
8
  # review:
9
- # uses: JNZader/project-starter-framework/.github/workflows/reusable-ghagga-review.yml@main
9
+ # uses: JNZader/javi-forge/.github/workflows/reusable-ghagga-review.yml@main
10
10
  # with:
11
11
  # ghagga-url: ${{ vars.GHAGGA_URL }}
12
12
  # secrets:
@@ -6,7 +6,7 @@
6
6
  # Usage:
7
7
  # jobs:
8
8
  # release:
9
- # uses: JNZader/project-starter-framework/.github/workflows/reusable-release.yml@main
9
+ # uses: JNZader/javi-forge/.github/workflows/reusable-release.yml@main
10
10
  # secrets:
11
11
  # token: ${{ secrets.GITHUB_TOKEN }}
12
12
  # ===========================================
package/.releaserc DELETED
@@ -1,45 +0,0 @@
1
- {
2
- "branches": ["main"],
3
- "tagFormat": "v${version}",
4
- "plugins": [
5
- ["@semantic-release/commit-analyzer", {
6
- "preset": "conventionalcommits",
7
- "releaseRules": [
8
- {"type": "feat", "release": "minor"},
9
- {"type": "fix", "release": "patch"},
10
- {"type": "perf", "release": "patch"},
11
- {"type": "refactor", "release": "patch"},
12
- {"type": "docs", "release": false},
13
- {"type": "style", "release": false},
14
- {"type": "chore", "release": false},
15
- {"type": "test", "release": false},
16
- {"breaking": true, "release": "major"}
17
- ]
18
- }],
19
- ["@semantic-release/release-notes-generator", {
20
- "preset": "conventionalcommits",
21
- "presetConfig": {
22
- "types": [
23
- {"type": "feat", "section": "Features"},
24
- {"type": "fix", "section": "Bug Fixes"},
25
- {"type": "perf", "section": "Performance"},
26
- {"type": "refactor", "section": "Refactoring"},
27
- {"type": "docs", "section": "Documentation", "hidden": true},
28
- {"type": "chore", "section": "Maintenance", "hidden": true}
29
- ]
30
- }
31
- }],
32
- ["@semantic-release/changelog", {
33
- "changelogFile": "CHANGELOG.md"
34
- }],
35
- ["@semantic-release/exec", {
36
- "prepareCmd": "echo ${nextRelease.version} > .framework-version"
37
- }],
38
- "@semantic-release/npm",
39
- ["@semantic-release/git", {
40
- "assets": ["CHANGELOG.md", "package.json", ".framework-version"],
41
- "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
42
- }],
43
- "@semantic-release/github"
44
- ]
45
- }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=analyze.test.d.ts.map
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=doctor.test.d.ts.map
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=init.test.d.ts.map
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=llmstxt.test.d.ts.map
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=plugin.test.d.ts.map
@@ -1,8 +0,0 @@
1
- import type { SyncOptions, InitStep } from '../types/index.js';
2
- type StepCallback = (step: InitStep) => void;
3
- /**
4
- * Sync AI config to a project directory, generating CLI-specific config files.
5
- */
6
- export declare function syncAIConfig(options: SyncOptions, onStep: StepCallback): Promise<void>;
7
- export {};
8
- //# sourceMappingURL=sync.d.ts.map
@@ -1,201 +0,0 @@
1
- import fs from 'fs-extra';
2
- import path from 'path';
3
- import { ensureDirExists } from '../lib/common.js';
4
- import { parseFrontmatter } from '../lib/frontmatter.js';
5
- import { AI_CONFIG_DIR, AI_CLI_CONFIG_FILES, MARKER_START, MARKER_END, } from '../constants.js';
6
- const ALL_TARGETS = ['claude', 'opencode', 'gemini', 'qwen', 'codex', 'copilot'];
7
- function report(onStep, id, label, status, detail) {
8
- onStep({ id, label, status, detail });
9
- }
10
- /** Read .skillignore and parse exclusion rules */
11
- async function loadSkillIgnore(configDir) {
12
- const globalExcludes = new Set();
13
- const targetExcludes = new Map();
14
- const ignorePath = path.join(configDir, '.skillignore');
15
- if (!await fs.pathExists(ignorePath)) {
16
- return { globalExcludes, targetExcludes };
17
- }
18
- const content = await fs.readFile(ignorePath, 'utf-8');
19
- for (const rawLine of content.split('\n')) {
20
- const line = rawLine.trim();
21
- if (!line || line.startsWith('#'))
22
- continue;
23
- if (line.includes(':')) {
24
- const [target, skill] = line.split(':', 2);
25
- if (target && skill) {
26
- if (!targetExcludes.has(target))
27
- targetExcludes.set(target, new Set());
28
- targetExcludes.get(target).add(skill);
29
- }
30
- }
31
- else {
32
- globalExcludes.add(line);
33
- }
34
- }
35
- return { globalExcludes, targetExcludes };
36
- }
37
- /** Recursively collect agent/skill markdown files from a directory */
38
- async function collectMarkdownEntries(baseDir, prefix = '') {
39
- const entries = [];
40
- if (!await fs.pathExists(baseDir))
41
- return entries;
42
- const items = await fs.readdir(baseDir, { withFileTypes: true });
43
- for (const item of items) {
44
- if (item.name.startsWith('_') || item.name.startsWith('.'))
45
- continue;
46
- const itemPath = path.join(baseDir, item.name);
47
- const relPath = prefix ? `${prefix}/${item.name}` : item.name;
48
- if (item.isDirectory()) {
49
- // Look for SKILL.md or agent markdown inside
50
- const skillMd = path.join(itemPath, 'SKILL.md');
51
- if (await fs.pathExists(skillMd)) {
52
- const content = await fs.readFile(skillMd, 'utf-8');
53
- entries.push({ relativePath: relPath, name: item.name, content });
54
- }
55
- else {
56
- // Recurse into subcategory directories
57
- const subEntries = await collectMarkdownEntries(itemPath, relPath);
58
- entries.push(...subEntries);
59
- }
60
- }
61
- else if (item.name.endsWith('.md') && item.name !== 'README.md') {
62
- const content = await fs.readFile(itemPath, 'utf-8');
63
- const name = item.name.replace('.md', '');
64
- entries.push({ relativePath: relPath, name, content });
65
- }
66
- }
67
- return entries;
68
- }
69
- /** Build a CLAUDE.md / GEMINI.md / etc from agents + skills */
70
- function buildConfigContent(target, agents, skills) {
71
- const lines = [];
72
- lines.push(`# AI Configuration for ${target}`);
73
- lines.push('');
74
- lines.push(`Auto-generated by javi-forge sync. Do not edit between markers.`);
75
- lines.push('');
76
- if (agents.length > 0) {
77
- lines.push('## Agents');
78
- lines.push('');
79
- for (const agent of agents) {
80
- const fm = parseFrontmatter(agent.content);
81
- if (fm?.data) {
82
- const desc = fm.data['description'] ?? '';
83
- lines.push(`- **${agent.name}**: ${desc}`);
84
- }
85
- else {
86
- lines.push(`- **${agent.name}**`);
87
- }
88
- }
89
- lines.push('');
90
- }
91
- if (skills.length > 0) {
92
- lines.push('## Available Skills');
93
- lines.push('');
94
- for (const skill of skills) {
95
- const fm = parseFrontmatter(skill.content);
96
- if (fm?.data) {
97
- const desc = fm.data['description'] ?? '';
98
- lines.push(`- **${skill.name}**: ${desc}`);
99
- }
100
- else {
101
- lines.push(`- **${skill.name}**`);
102
- }
103
- }
104
- lines.push('');
105
- }
106
- return lines.join('\n');
107
- }
108
- /** Merge generated content into an existing file using markers */
109
- function mergeWithMarkers(existingContent, generatedContent) {
110
- const startIdx = existingContent.indexOf(MARKER_START);
111
- const endIdx = existingContent.indexOf(MARKER_END);
112
- const markerBlock = `${MARKER_START}\n${generatedContent}\n${MARKER_END}`;
113
- if (startIdx !== -1 && endIdx !== -1) {
114
- // Replace existing marker block
115
- return existingContent.slice(0, startIdx) + markerBlock + existingContent.slice(endIdx + MARKER_END.length);
116
- }
117
- // Append marker block
118
- return existingContent.trimEnd() + '\n\n' + markerBlock + '\n';
119
- }
120
- /**
121
- * Sync AI config to a project directory, generating CLI-specific config files.
122
- */
123
- export async function syncAIConfig(options, onStep) {
124
- const { target, mode, projectDir, dryRun } = options;
125
- const targets = target === 'all' ? ALL_TARGETS : [target];
126
- const configDir = AI_CONFIG_DIR;
127
- // Load exclusions
128
- const { globalExcludes, targetExcludes } = await loadSkillIgnore(configDir);
129
- // Collect agents and skills
130
- const agentsDir = path.join(configDir, 'agents');
131
- const skillsDir = path.join(configDir, 'skills');
132
- const allAgents = await collectMarkdownEntries(agentsDir);
133
- const allSkills = await collectMarkdownEntries(skillsDir);
134
- for (const cli of targets) {
135
- const stepId = `sync-${cli}`;
136
- report(onStep, stepId, `Sync config for ${cli}`, 'running');
137
- try {
138
- // Filter out excluded skills
139
- const cliExcludes = targetExcludes.get(cli) ?? new Set();
140
- const filteredSkills = allSkills.filter(s => {
141
- const nameWithoutExt = s.name;
142
- const relWithoutExt = s.relativePath.replace(/\.md$/, '').replace(/\/SKILL\.md$/, '');
143
- return !globalExcludes.has(nameWithoutExt)
144
- && !globalExcludes.has(relWithoutExt)
145
- && !cliExcludes.has(nameWithoutExt)
146
- && !cliExcludes.has(relWithoutExt);
147
- });
148
- const filteredAgents = allAgents.filter(a => {
149
- return !globalExcludes.has(a.name) && !cliExcludes.has(a.name);
150
- });
151
- // Build the config content
152
- const generatedContent = buildConfigContent(cli, filteredAgents, filteredSkills);
153
- // Determine destination
154
- const configFileName = AI_CLI_CONFIG_FILES[cli];
155
- if (!configFileName) {
156
- report(onStep, stepId, `Sync config for ${cli}`, 'skipped', 'no config file mapping');
157
- continue;
158
- }
159
- const destPath = path.join(projectDir, configFileName);
160
- if (!dryRun) {
161
- await ensureDirExists(path.dirname(destPath));
162
- if (mode === 'merge' && await fs.pathExists(destPath)) {
163
- const existing = await fs.readFile(destPath, 'utf-8');
164
- const merged = mergeWithMarkers(existing, generatedContent);
165
- await fs.writeFile(destPath, merged, 'utf-8');
166
- }
167
- else {
168
- await fs.writeFile(destPath, generatedContent, 'utf-8');
169
- }
170
- }
171
- report(onStep, stepId, `Sync config for ${cli}`, 'done', `${filteredAgents.length} agents, ${filteredSkills.length} skills → ${configFileName}`);
172
- // Sync Claude commands if target is claude
173
- if (cli === 'claude') {
174
- const cmdStepId = `sync-${cli}-commands`;
175
- report(onStep, cmdStepId, 'Sync Claude commands', 'running');
176
- try {
177
- const commandsSrc = path.join(configDir, 'commands');
178
- if (await fs.pathExists(commandsSrc)) {
179
- const commandsDest = path.join(projectDir, '.claude', 'commands');
180
- if (!dryRun) {
181
- await ensureDirExists(commandsDest);
182
- await fs.copy(commandsSrc, commandsDest, { overwrite: true });
183
- }
184
- const cmdFiles = await fs.readdir(commandsSrc);
185
- report(onStep, cmdStepId, 'Sync Claude commands', 'done', `${cmdFiles.length} commands`);
186
- }
187
- else {
188
- report(onStep, cmdStepId, 'Sync Claude commands', 'skipped', 'no commands dir');
189
- }
190
- }
191
- catch (e) {
192
- report(onStep, cmdStepId, 'Sync Claude commands', 'error', String(e));
193
- }
194
- }
195
- }
196
- catch (e) {
197
- report(onStep, stepId, `Sync config for ${cli}`, 'error', String(e));
198
- }
199
- }
200
- }
201
- //# sourceMappingURL=sync.js.map
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=aggressive.e2e.test.d.ts.map
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=commands.e2e.test.d.ts.map
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=common.test.d.ts.map
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=frontmatter.test.d.ts.map
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=plugin.test.d.ts.map
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=template.test.d.ts.map
@@ -1,10 +0,0 @@
1
- import React from 'react';
2
- import type { AI_CLI } from '../types/index.js';
3
- interface Props {
4
- target: AI_CLI | 'all';
5
- mode: 'overwrite' | 'merge';
6
- dryRun: boolean;
7
- }
8
- export default function SyncUI({ target, mode, dryRun }: Props): React.JSX.Element;
9
- export {};
10
- //# sourceMappingURL=SyncUI.d.ts.map