javi-forge 0.1.0 → 1.1.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 (159) hide show
  1. package/.releaserc +2 -1
  2. package/README.md +143 -31
  3. package/ai-config/commands/workflows/diagnose.md +70 -0
  4. package/ai-config/commands/workflows/discover.md +86 -0
  5. package/ci-local/ci-local.sh +18 -0
  6. package/ci-local/docker/node.Dockerfile +7 -0
  7. package/ci-local/hooks/commit-msg +0 -0
  8. package/ci-local/hooks/pre-commit +0 -0
  9. package/ci-local/hooks/pre-push +0 -0
  10. package/ci-local/install.sh +0 -0
  11. package/dist/commands/doctor.js +24 -1
  12. package/dist/commands/init.js +48 -1
  13. package/dist/commands/llmstxt.d.ts +9 -0
  14. package/dist/commands/llmstxt.js +93 -0
  15. package/dist/commands/llmstxt.test.d.ts +2 -0
  16. package/dist/commands/plugin.d.ts +24 -0
  17. package/dist/commands/plugin.js +78 -0
  18. package/dist/commands/plugin.test.d.ts +2 -0
  19. package/dist/constants.d.ts +8 -0
  20. package/dist/constants.js +8 -0
  21. package/dist/index.js +33 -4
  22. package/dist/lib/plugin.d.ts +39 -0
  23. package/dist/lib/plugin.js +228 -0
  24. package/dist/lib/plugin.test.d.ts +2 -0
  25. package/dist/types/index.d.ts +42 -0
  26. package/dist/ui/App.d.ts +2 -1
  27. package/dist/ui/App.js +2 -1
  28. package/dist/ui/LlmsTxt.d.ts +8 -0
  29. package/dist/ui/LlmsTxt.js +48 -0
  30. package/dist/ui/Plugin.d.ts +9 -0
  31. package/dist/ui/Plugin.js +96 -0
  32. package/lib/common.sh +183 -0
  33. package/modules/obsidian-brain/README.md +32 -0
  34. package/modules/obsidian-brain/core/templates/braindump.md +15 -0
  35. package/modules/obsidian-brain/core/templates/consolidation.md +42 -0
  36. package/modules/obsidian-brain/core/templates/daily-note.md +18 -0
  37. package/modules/obsidian-brain/core/templates/resource-capture.md +14 -0
  38. package/modules/obsidian-brain/developer/templates/adr.md +40 -0
  39. package/modules/obsidian-brain/developer/templates/coding-session.md +24 -0
  40. package/modules/obsidian-brain/developer/templates/debug-journal.md +22 -0
  41. package/modules/obsidian-brain/developer/templates/sdd-feedback.md +27 -0
  42. package/modules/obsidian-brain/developer/templates/tech-debt.md +20 -0
  43. package/modules/obsidian-brain/pm-lead/templates/daily-brief.md +25 -0
  44. package/modules/obsidian-brain/pm-lead/templates/meeting-notes.md +24 -0
  45. package/modules/obsidian-brain/pm-lead/templates/risk-registry.md +12 -0
  46. package/modules/obsidian-brain/pm-lead/templates/sprint-review.md +27 -0
  47. package/modules/obsidian-brain/pm-lead/templates/stakeholder-update.md +24 -0
  48. package/modules/obsidian-brain/pm-lead/templates/team-intelligence.md +19 -0
  49. package/modules/obsidian-brain/pm-lead/templates/weekly-brief.md +29 -0
  50. package/package.json +12 -12
  51. package/schemas/plugin.schema.json +62 -0
  52. package/dist/commands/analyze.d.ts.map +0 -1
  53. package/dist/commands/analyze.js.map +0 -1
  54. package/dist/commands/analyze.test.d.ts.map +0 -1
  55. package/dist/commands/analyze.test.js +0 -145
  56. package/dist/commands/analyze.test.js.map +0 -1
  57. package/dist/commands/doctor.d.ts.map +0 -1
  58. package/dist/commands/doctor.js.map +0 -1
  59. package/dist/commands/doctor.test.d.ts.map +0 -1
  60. package/dist/commands/doctor.test.js +0 -200
  61. package/dist/commands/doctor.test.js.map +0 -1
  62. package/dist/commands/init.d.ts.map +0 -1
  63. package/dist/commands/init.js.map +0 -1
  64. package/dist/commands/init.test.d.ts.map +0 -1
  65. package/dist/commands/init.test.js +0 -271
  66. package/dist/commands/init.test.js.map +0 -1
  67. package/dist/commands/sync.d.ts.map +0 -1
  68. package/dist/commands/sync.js.map +0 -1
  69. package/dist/constants.d.ts.map +0 -1
  70. package/dist/constants.js.map +0 -1
  71. package/dist/e2e/aggressive.e2e.test.d.ts.map +0 -1
  72. package/dist/e2e/aggressive.e2e.test.js +0 -350
  73. package/dist/e2e/aggressive.e2e.test.js.map +0 -1
  74. package/dist/e2e/commands.e2e.test.d.ts.map +0 -1
  75. package/dist/e2e/commands.e2e.test.js +0 -213
  76. package/dist/e2e/commands.e2e.test.js.map +0 -1
  77. package/dist/index.d.ts.map +0 -1
  78. package/dist/index.js.map +0 -1
  79. package/dist/lib/common.d.ts.map +0 -1
  80. package/dist/lib/common.js.map +0 -1
  81. package/dist/lib/common.test.d.ts.map +0 -1
  82. package/dist/lib/common.test.js +0 -316
  83. package/dist/lib/common.test.js.map +0 -1
  84. package/dist/lib/frontmatter.d.ts.map +0 -1
  85. package/dist/lib/frontmatter.js.map +0 -1
  86. package/dist/lib/frontmatter.test.d.ts.map +0 -1
  87. package/dist/lib/frontmatter.test.js +0 -257
  88. package/dist/lib/frontmatter.test.js.map +0 -1
  89. package/dist/lib/template.d.ts.map +0 -1
  90. package/dist/lib/template.js.map +0 -1
  91. package/dist/lib/template.test.d.ts.map +0 -1
  92. package/dist/lib/template.test.js +0 -201
  93. package/dist/lib/template.test.js.map +0 -1
  94. package/dist/types/index.d.ts.map +0 -1
  95. package/dist/types/index.js.map +0 -1
  96. package/dist/ui/AnalyzeUI.d.ts.map +0 -1
  97. package/dist/ui/AnalyzeUI.js.map +0 -1
  98. package/dist/ui/App.d.ts.map +0 -1
  99. package/dist/ui/App.js.map +0 -1
  100. package/dist/ui/CIContext.d.ts.map +0 -1
  101. package/dist/ui/CIContext.js.map +0 -1
  102. package/dist/ui/CISelector.d.ts.map +0 -1
  103. package/dist/ui/CISelector.js.map +0 -1
  104. package/dist/ui/Doctor.d.ts.map +0 -1
  105. package/dist/ui/Doctor.js.map +0 -1
  106. package/dist/ui/Header.d.ts.map +0 -1
  107. package/dist/ui/Header.js.map +0 -1
  108. package/dist/ui/MemorySelector.d.ts.map +0 -1
  109. package/dist/ui/MemorySelector.js.map +0 -1
  110. package/dist/ui/NameInput.d.ts.map +0 -1
  111. package/dist/ui/NameInput.js.map +0 -1
  112. package/dist/ui/OptionSelector.d.ts.map +0 -1
  113. package/dist/ui/OptionSelector.js.map +0 -1
  114. package/dist/ui/Progress.d.ts.map +0 -1
  115. package/dist/ui/Progress.js.map +0 -1
  116. package/dist/ui/StackSelector.d.ts.map +0 -1
  117. package/dist/ui/StackSelector.js.map +0 -1
  118. package/dist/ui/Summary.d.ts.map +0 -1
  119. package/dist/ui/Summary.js.map +0 -1
  120. package/dist/ui/SyncUI.d.ts.map +0 -1
  121. package/dist/ui/SyncUI.js.map +0 -1
  122. package/dist/ui/Welcome.d.ts.map +0 -1
  123. package/dist/ui/Welcome.js.map +0 -1
  124. package/dist/ui/theme.d.ts.map +0 -1
  125. package/dist/ui/theme.js.map +0 -1
  126. package/src/commands/analyze.test.ts +0 -145
  127. package/src/commands/analyze.ts +0 -69
  128. package/src/commands/doctor.test.ts +0 -208
  129. package/src/commands/doctor.ts +0 -163
  130. package/src/commands/init.test.ts +0 -298
  131. package/src/commands/init.ts +0 -285
  132. package/src/constants.ts +0 -69
  133. package/src/e2e/aggressive.e2e.test.ts +0 -557
  134. package/src/e2e/commands.e2e.test.ts +0 -298
  135. package/src/index.tsx +0 -106
  136. package/src/lib/common.test.ts +0 -318
  137. package/src/lib/common.ts +0 -127
  138. package/src/lib/frontmatter.test.ts +0 -291
  139. package/src/lib/frontmatter.ts +0 -77
  140. package/src/lib/template.test.ts +0 -226
  141. package/src/lib/template.ts +0 -99
  142. package/src/types/index.ts +0 -53
  143. package/src/ui/AnalyzeUI.tsx +0 -133
  144. package/src/ui/App.tsx +0 -175
  145. package/src/ui/CIContext.tsx +0 -25
  146. package/src/ui/CISelector.tsx +0 -72
  147. package/src/ui/Doctor.tsx +0 -122
  148. package/src/ui/Header.tsx +0 -48
  149. package/src/ui/MemorySelector.tsx +0 -73
  150. package/src/ui/NameInput.tsx +0 -82
  151. package/src/ui/OptionSelector.tsx +0 -100
  152. package/src/ui/Progress.tsx +0 -88
  153. package/src/ui/StackSelector.tsx +0 -101
  154. package/src/ui/Summary.tsx +0 -134
  155. package/src/ui/Welcome.tsx +0 -54
  156. package/src/ui/theme.ts +0 -10
  157. package/stryker.config.json +0 -19
  158. package/tsconfig.json +0 -19
  159. package/vitest.config.ts +0 -16
package/.releaserc CHANGED
@@ -35,8 +35,9 @@
35
35
  ["@semantic-release/exec", {
36
36
  "prepareCmd": "echo ${nextRelease.version} > .framework-version"
37
37
  }],
38
+ "@semantic-release/npm",
38
39
  ["@semantic-release/git", {
39
- "assets": ["CHANGELOG.md", ".framework-version"],
40
+ "assets": ["CHANGELOG.md", "package.json", ".framework-version"],
40
41
  "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
41
42
  }],
42
43
  "@semantic-release/github"
package/README.md CHANGED
@@ -1,45 +1,157 @@
1
1
  # javi-forge
2
2
 
3
- Project scaffolding and AI-ready CI bootstrap tool.
3
+ > Project scaffolding AI-ready CI bootstrap with templates for Go, Java, Node, Python, Rust
4
4
 
5
- **javi-forge** generates production-ready project structures with CI/CD pipelines, AI agent configurations, and developer tooling — all from a single command.
5
+ [![npm version](https://img.shields.io/npm/v/javi-forge.svg)](https://www.npmjs.com/package/javi-forge)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
6
7
 
7
- ## Directory Structure
8
+ ## Quick Start
8
9
 
10
+ ```bash
11
+ npx javi-forge init
9
12
  ```
10
- javi-forge/
11
- ├── README.md # This file
12
- ├── .gitignore # Standard ignores
13
- ├── package.json # Package metadata and scripts
14
- ├── templates/ # CI/CD pipeline templates
15
- │ ├── github/ # GitHub Actions workflows
16
- │ ├── gitlab/ # GitLab CI pipelines
17
- │ ├── woodpecker/ # Woodpecker CI pipelines
18
- │ ├── common/ # Shared config (dependabot fragments)
19
- │ └── global/ # AI tool configs (Claude, Copilot, Gemini, etc.)
20
- ├── workflows/ # Reusable GitHub Actions workflows
21
- ├── modules/ # Optional integration modules
22
- │ ├── engram/ # Persistent memory via Engram MCP
23
- │ ├── obsidian-brain/ # Obsidian-based project memory
24
- │ ├── ghagga/ # Multi-agent code review system
25
- │ └── memory-simple/ # Minimal file-based project memory
26
- ├── ai-config/ # AI agent and skill library
27
- │ ├── agents/ # Agent definitions (by domain)
28
- │ ├── skills/ # Skill definitions (by domain)
29
- │ ├── commands/ # Slash-command definitions
30
- │ ├── hooks/ # Pre/post tool-use hooks
31
- │ └── prompts/ # System prompts and modes
32
- ├── schemas/ # JSON schemas for validation
33
- ├── tasks/ # Task templates
34
- └── src/ # CLI source code
13
+
14
+ An interactive TUI guides you through project setup: pick a stack, CI provider, memory module, and get a production-ready project structure in seconds.
15
+
16
+ ## What It Creates
17
+
18
+ `javi-forge init` bootstraps a complete project with 10 sequential steps:
19
+
20
+ ```mermaid
21
+ flowchart LR
22
+ A["javi-forge init"] --> B["git init"]
23
+ B --> C["CI workflow"]
24
+ C --> D[".gitignore"]
25
+ D --> E["dependabot.yml"]
26
+ E --> F["Memory module"]
27
+ F --> G["javi-ai sync"]
28
+ G --> H["openspec/ (SDD)"]
29
+ H --> I["GHAGGA review"]
30
+ I --> J["Manifest"]
35
31
  ```
36
32
 
37
- ## Quick Start
33
+ ### Step-by-Step
34
+
35
+ | Step | What it does |
36
+ |------|-------------|
37
+ | 1 | Initialize git repository |
38
+ | 2 | Configure git hooks path (`ci-local/hooks`) |
39
+ | 3 | Copy CI workflow for your stack and provider |
40
+ | 4 | Generate `.gitignore` from template |
41
+ | 5 | Generate `dependabot.yml` (GitHub only) |
42
+ | 6 | Install memory module (engram, obsidian-brain, or memory-simple) |
43
+ | 7 | Sync AI config via `javi-ai sync --target all` |
44
+ | 8 | Set up SDD with `openspec/` directory |
45
+ | 9 | Install GHAGGA review system (optional) |
46
+ | 10 | Write forge manifest to `.javi-forge/manifest.json` |
47
+
48
+ ## Templates
49
+
50
+ | Stack | CI Templates | Dependabot |
51
+ |-------|-------------|------------|
52
+ | **node** | GitHub Actions, GitLab CI, Woodpecker | npm |
53
+ | **python** | GitHub Actions, GitLab CI, Woodpecker | pip |
54
+ | **go** | GitHub Actions, GitLab CI, Woodpecker | gomod |
55
+ | **java-gradle** | GitHub Actions, GitLab CI, Woodpecker | gradle |
56
+ | **java-maven** | GitHub Actions, GitLab CI, Woodpecker | maven |
57
+ | **rust** | GitHub Actions, GitLab CI, Woodpecker | cargo |
58
+ | **elixir** | GitHub Actions, GitLab CI, Woodpecker | — |
59
+
60
+ ## CI Providers
61
+
62
+ | Provider | Workflow location | Dependabot |
63
+ |----------|------------------|------------|
64
+ | **GitHub Actions** | `.github/workflows/ci.yml` | `.github/dependabot.yml` |
65
+ | **GitLab CI** | `.gitlab-ci.yml` | — |
66
+ | **Woodpecker** | `.woodpecker.yml` | — |
67
+
68
+ ## Memory Modules
69
+
70
+ | Module | Description |
71
+ |--------|-------------|
72
+ | **engram** | Persistent AI memory via MCP server. Best for cross-session context |
73
+ | **obsidian-brain** | Obsidian-based project memory with Kanban, Dataview, and session tracking |
74
+ | **memory-simple** | Minimal file-based project memory |
75
+ | **none** | Skip memory module |
76
+
77
+ ## Commands
78
+
79
+ | Command | Description |
80
+ |---------|-------------|
81
+ | `init` | Bootstrap a new project (default) |
82
+ | `analyze` | Run repoforge skills analysis on current project |
83
+ | `doctor` | Show comprehensive health report |
38
84
 
39
85
  ```bash
40
- npx javi-forge init my-project --stack node --ci github
86
+ npx javi-forge init
87
+ npx javi-forge init --stack node --ci github
88
+ npx javi-forge analyze
89
+ npx javi-forge doctor
41
90
  ```
42
91
 
92
+ ### CLI Flags
93
+
94
+ | Flag | Type | Default | Description |
95
+ |------|------|---------|-------------|
96
+ | `--dry-run` | boolean | `false` | Preview without writing files |
97
+ | `--stack` | string | — | Project stack |
98
+ | `--ci` | string | — | CI provider |
99
+ | `--memory` | string | — | Memory module |
100
+ | `--project-name` | string | — | Project name (skips name prompt) |
101
+ | `--ghagga` | boolean | `false` | Enable GHAGGA review system |
102
+ | `--batch` | boolean | `false` | Non-interactive mode |
103
+
104
+ ## AI Config
105
+
106
+ `javi-forge` ships with a comprehensive `.ai-config/` library:
107
+
108
+ | Category | Count | Description |
109
+ |----------|-------|-------------|
110
+ | **Agents** | 8 groups | Domain-specific agent definitions |
111
+ | **Skills** | 84 skills | Organized by domain (backend, frontend, infra, etc.) |
112
+ | **Commands** | 20 | Slash-command definitions for Claude |
113
+ | **Hooks** | 11 | Pre/post tool-use automation hooks |
114
+
115
+ The AI config is synced into your project via `javi-ai sync` during init.
116
+
117
+ ## RepoForge Integration
118
+
119
+ The `analyze` command wraps [repoforge](https://github.com/Gentleman-Programming/repoforge) to run skills analysis on your project:
120
+
121
+ ```bash
122
+ npx javi-forge analyze
123
+ ```
124
+
125
+ This requires `repoforge` to be installed (`pip install repoforge`). It analyzes your codebase and generates skill recommendations.
126
+
127
+ ## Doctor
128
+
129
+ The `doctor` command runs comprehensive health checks:
130
+
131
+ ```bash
132
+ npx javi-forge doctor
133
+ ```
134
+
135
+ ### What it checks
136
+
137
+ - **System Tools** — git, docker, semgrep, node, pnpm
138
+ - **Framework Structure** — templates/, modules/, ai-config/, workflows/, schemas/, ci-local/
139
+ - **Stack Detection** — Detects project type from files (package.json, go.mod, Cargo.toml, etc.)
140
+ - **Project Manifest** — Reads `.javi-forge/manifest.json`
141
+ - **Installed Modules** — engram, obsidian-brain, memory-simple, ghagga
142
+
143
+ ## Requirements
144
+
145
+ - **Node.js** >= 18
146
+
147
+ ## Ecosystem
148
+
149
+ | Package | Description |
150
+ |---------|-------------|
151
+ | [javi-dots](https://github.com/JNZader/javi-dots) | Workstation setup (top-level orchestrator) |
152
+ | [javi-ai](https://github.com/JNZader/javi-ai) | AI development layer (called by forge during sync) |
153
+ | **javi-forge** | Project scaffolding (this package) |
154
+
43
155
  ## License
44
156
 
45
- MIT
157
+ [MIT](LICENSE)
@@ -0,0 +1,70 @@
1
+ ---
2
+ name: diagnose
3
+ description: Chained diagnosis workflow — investigate issue, verify with devil's advocate, then solve. Uses ACH (Analysis of Competing Hypotheses).
4
+ category: workflows
5
+ chain:
6
+ - investigate
7
+ - verify
8
+ - solve
9
+ suggests_next:
10
+ - /workflows:compound
11
+ - /workflows:review
12
+ ---
13
+
14
+ # /workflows:diagnose
15
+
16
+ Structured diagnosis workflow for complex bugs and issues.
17
+
18
+ ## Usage
19
+
20
+ ```
21
+ /workflows:diagnose <issue-description>
22
+ ```
23
+
24
+ ## Chain Steps
25
+
26
+ ### Step 1: Investigate
27
+ Gather evidence and generate hypotheses using the debug-mode skill.
28
+
29
+ 1. Reproduce the issue (or understand the reproduction steps)
30
+ 2. Gather context: error messages, stack traces, recent changes, logs
31
+ 3. Generate 3-5 competing hypotheses ranked by likelihood
32
+ 4. Map evidence to hypotheses (which evidence supports/contradicts each)
33
+
34
+ Output: ACH matrix
35
+
36
+ ```
37
+ ## ACH Matrix: <issue>
38
+ | Evidence | H1 (70%) | H2 (20%) | H3 (10%) |
39
+ |----------|----------|----------|----------|
40
+ | Error at line 42 | Consistent | Inconsistent | Neutral |
41
+ | Works in staging | Inconsistent | Consistent | Consistent |
42
+ ```
43
+
44
+ **After completion, suggest**: "Investigation complete. Run step 2 for devil's advocate verification, or jump to step 3 if confident."
45
+
46
+ ### Step 2: Verify (Devil's Advocate)
47
+ Challenge the leading hypothesis:
48
+
49
+ 1. **Assume H1 is wrong** — what evidence would you expect to see?
50
+ 2. **Check for that evidence** — does it exist?
51
+ 3. **Try to reproduce with H1 fixed** — does the fix actually work?
52
+ 4. If H1 survives the challenge, proceed to fix. Otherwise, promote H2.
53
+
54
+ **After completion, suggest**: "Verification complete. H[N] confirmed. Run step 3 to implement the fix."
55
+
56
+ ### Step 3: Solve
57
+ Implement the fix based on the verified hypothesis:
58
+
59
+ 1. Write the fix
60
+ 2. Verify the original reproduction steps pass
61
+ 3. Run the full test suite
62
+ 4. Document what was wrong and why (for Engram)
63
+
64
+ **After completion, suggest**: "Fix applied. Next: `/workflows:compound` to capture learnings, or `/workflows:review` for code review."
65
+
66
+ ## Rules
67
+
68
+ 1. Never skip step 2 for Medium+ complexity issues
69
+ 2. Always document the root cause in Engram
70
+ 3. If 3 rounds of investigation don't converge, escalate to user
@@ -0,0 +1,86 @@
1
+ ---
2
+ name: discover
3
+ description: Chained discovery workflow — brainstorm ideas, identify assumptions, prioritize experiments, then execute. Progressive suggestions after each step.
4
+ category: workflows
5
+ chain:
6
+ - brainstorm
7
+ - identify-assumptions
8
+ - prioritize
9
+ - experiment
10
+ suggests_next:
11
+ - /workflows:plan
12
+ - /workflows:work
13
+ ---
14
+
15
+ # /workflows:discover
16
+
17
+ End-to-end discovery workflow that chains 4 steps with progressive suggestions.
18
+
19
+ ## Usage
20
+
21
+ ```
22
+ /workflows:discover <topic>
23
+ ```
24
+
25
+ ## Chain Steps
26
+
27
+ ### Step 1: Brainstorm
28
+ Generate 5-10 ideas related to the topic. No filtering, quantity over quality.
29
+
30
+ Output format:
31
+ ```
32
+ ## Ideas for: <topic>
33
+ 1. [idea] — [one-line rationale]
34
+ 2. [idea] — [one-line rationale]
35
+ ...
36
+ ```
37
+
38
+ **After completion, suggest**: "Ideas generated. Run step 2 to identify assumptions, or pick specific ideas to explore."
39
+
40
+ ### Step 2: Identify Assumptions
41
+ For the top 3-5 ideas, list the key assumptions that must be true for each to work.
42
+
43
+ Output format:
44
+ ```
45
+ ## Assumptions
46
+ ### Idea 1: [name]
47
+ - [assumption] — risk: high/medium/low
48
+ - [assumption] — risk: high/medium/low
49
+ ```
50
+
51
+ **After completion, suggest**: "Assumptions mapped. Run step 3 to prioritize by risk, or go back to brainstorm more."
52
+
53
+ ### Step 3: Prioritize
54
+ Rank ideas by: (1) impact, (2) effort, (3) assumption risk. Create a 2x2 matrix.
55
+
56
+ Output format:
57
+ ```
58
+ ## Priority Matrix
59
+ | Idea | Impact | Effort | Risk | Priority |
60
+ |------|--------|--------|------|----------|
61
+ ```
62
+
63
+ **After completion, suggest**: "Priority matrix ready. Run step 4 to design experiments for the top picks."
64
+
65
+ ### Step 4: Experiment Design
66
+ For the top 2-3 ideas, design a minimal experiment to validate the riskiest assumption.
67
+
68
+ Output format:
69
+ ```
70
+ ## Experiments
71
+ ### Experiment 1: [name]
72
+ - Validates: [assumption]
73
+ - Method: [how to test]
74
+ - Success criteria: [what proves it works]
75
+ - Effort: [time estimate]
76
+ ```
77
+
78
+ **After completion, suggest**: "Experiments designed. Next steps: `/workflows:plan` to plan implementation, or `/workflows:work` to start building."
79
+
80
+ ## Chaining Rules
81
+
82
+ 1. Each step can be run independently or as part of the chain
83
+ 2. Output of each step is input context for the next
84
+ 3. Progressive suggestions appear after every step completion
85
+ 4. User can skip steps or go back at any point
86
+ 5. The full chain takes ~15 minutes of agent time
@@ -74,6 +74,12 @@ setup_ci_commands() {
74
74
  esac
75
75
  }
76
76
 
77
+ # Check if GHAGGA is available on the host
78
+ GHAGGA_AVAILABLE=false
79
+ if command -v ghagga >/dev/null 2>&1; then
80
+ GHAGGA_AVAILABLE=true
81
+ fi
82
+
77
83
  # =============================================================================
78
84
  # DOCKER
79
85
  # =============================================================================
@@ -270,6 +276,7 @@ case "$MODE" in
270
276
  [[ -n "$LINT_CMD" ]] && total=$((total + 1))
271
277
  [[ -n "$COMPILE_CMD" ]] && total=$((total + 1))
272
278
  [[ -n "$TEST_CMD" ]] && total=$((total + 1))
279
+ if $GHAGGA_AVAILABLE; then total=$((total + 1)); fi
273
280
 
274
281
  if [[ -n "$LINT_CMD" ]]; then
275
282
  echo -e "\n${YELLOW}Step $step/$total: Lint${NC}"
@@ -289,6 +296,17 @@ case "$MODE" in
289
296
  echo -e "\n${YELLOW}Step $step/$total: Test${NC}"
290
297
  echo -e " ${CYAN}$TEST_CMD${NC}"
291
298
  run_in_ci "cd /home/runner/work && $TEST_CMD"
299
+ step=$((step + 1))
300
+ fi
301
+
302
+ if $GHAGGA_AVAILABLE; then
303
+ echo -e "\n${YELLOW}Step $step/$total: GHAGGA Review${NC}"
304
+ echo -e " ${CYAN}ghagga review --plain --exit-on-issues${NC}"
305
+ if ! ghagga review --plain --exit-on-issues; then
306
+ echo -e "${RED}GHAGGA review found issues!${NC}"
307
+ exit 1
308
+ fi
309
+ step=$((step + 1))
292
310
  fi
293
311
  ;;
294
312
  esac
@@ -0,0 +1,7 @@
1
+ FROM node:22-slim
2
+ RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*
3
+ RUN npm install -g pnpm
4
+ RUN useradd -m -s /bin/bash runner
5
+ USER runner
6
+ WORKDIR /home/runner/work
7
+ ENTRYPOINT ["/bin/bash", "-c"]
File without changes
File without changes
File without changes
File without changes
@@ -3,7 +3,8 @@ import path from 'path';
3
3
  import { execFile } from 'child_process';
4
4
  import { promisify } from 'util';
5
5
  import { detectStack } from '../lib/common.js';
6
- import { FORGE_ROOT, TEMPLATES_DIR, MODULES_DIR, AI_CONFIG_DIR } from '../constants.js';
6
+ import { listInstalledPlugins } from '../lib/plugin.js';
7
+ import { FORGE_ROOT, TEMPLATES_DIR, MODULES_DIR, AI_CONFIG_DIR, PLUGINS_DIR } from '../constants.js';
7
8
  const execFileAsync = promisify(execFile);
8
9
  /** Resolve a binary name to its full path, returns null if not found */
9
10
  async function which(bin) {
@@ -153,6 +154,28 @@ export async function runDoctor(projectDir) {
153
154
  }
154
155
  }
155
156
  sections.push({ title: 'Installed Modules', checks: moduleChecks });
157
+ // ── 6. Plugins ─────────────────────────────────────────────────────────────
158
+ const pluginChecks = [];
159
+ const pluginsDirExists = await fs.pathExists(PLUGINS_DIR);
160
+ if (pluginsDirExists) {
161
+ const plugins = await listInstalledPlugins();
162
+ if (plugins.length > 0) {
163
+ for (const plugin of plugins) {
164
+ pluginChecks.push({
165
+ label: plugin.name,
166
+ status: 'ok',
167
+ detail: `v${plugin.version} from ${plugin.source}`,
168
+ });
169
+ }
170
+ }
171
+ else {
172
+ pluginChecks.push({ label: 'Plugins', status: 'skip', detail: 'none installed' });
173
+ }
174
+ }
175
+ else {
176
+ pluginChecks.push({ label: 'Plugins directory', status: 'skip', detail: 'not created yet' });
177
+ }
178
+ sections.push({ title: 'Plugins', checks: pluginChecks });
156
179
  return { sections };
157
180
  }
158
181
  //# sourceMappingURL=doctor.js.map
@@ -250,7 +250,54 @@ export async function initProject(options, onStep) {
250
250
  catch (e) {
251
251
  report(onStep, stepGhagga, 'Install GHAGGA review system', 'error', String(e));
252
252
  }
253
- // ── Step 10: Write manifest ───────────────────────────────────────────────
253
+ // ── Step 10: Mock-first mode ───────────────────────────────────────────────
254
+ const stepMock = 'mock';
255
+ if (options.mock) {
256
+ report(onStep, stepMock, 'Configure mock-first mode', 'running');
257
+ try {
258
+ if (!dryRun) {
259
+ // Create .env.example with mock values
260
+ const envExample = `# Mock environment — no real API keys required
261
+ # Copy to .env to use: cp .env.example .env
262
+
263
+ # Database
264
+ DATABASE_URL=postgresql://mock:mock@localhost:5432/mock_db
265
+
266
+ # Auth
267
+ JWT_SECRET=mock-jwt-secret-for-local-development
268
+ SESSION_SECRET=mock-session-secret
269
+
270
+ # External APIs (mock mode — no real calls)
271
+ MOCK_MODE=true
272
+ API_KEY=mock-api-key-not-real
273
+ STRIPE_KEY=sk_test_mock_not_real
274
+ SENDGRID_KEY=SG.mock_not_real
275
+
276
+ # Feature flags
277
+ ENABLE_ANALYTICS=false
278
+ ENABLE_EMAILS=false
279
+ ENABLE_WEBHOOKS=false
280
+ `;
281
+ const envExamplePath = path.join(projectDir, '.env.example');
282
+ if (!await fs.pathExists(envExamplePath)) {
283
+ await fs.writeFile(envExamplePath, envExample, 'utf-8');
284
+ }
285
+ // Create .env from example
286
+ const envPath = path.join(projectDir, '.env');
287
+ if (!await fs.pathExists(envPath)) {
288
+ await fs.writeFile(envPath, envExample, 'utf-8');
289
+ }
290
+ }
291
+ report(onStep, stepMock, 'Configure mock-first mode', 'done', '.env.example + .env with mock values');
292
+ }
293
+ catch (e) {
294
+ report(onStep, stepMock, 'Configure mock-first mode', 'error', String(e));
295
+ }
296
+ }
297
+ else {
298
+ report(onStep, stepMock, 'Configure mock-first mode', 'skipped', 'not selected');
299
+ }
300
+ // ── Step 11: Write manifest ───────────────────────────────────────────────
254
301
  const stepManifest = 'manifest';
255
302
  report(onStep, stepManifest, 'Write forge manifest', 'running');
256
303
  try {
@@ -0,0 +1,9 @@
1
+ import type { InitStep } from '../types/index.js';
2
+ type StepCallback = (step: InitStep) => void;
3
+ /**
4
+ * Generate an llms.txt file — compact AI-friendly project notation.
5
+ * Reduces token usage by ~75% compared to full README + docs.
6
+ */
7
+ export declare function generateLlmsTxt(projectDir: string, dryRun: boolean, onStep: StepCallback): Promise<void>;
8
+ export {};
9
+ //# sourceMappingURL=llmstxt.d.ts.map
@@ -0,0 +1,93 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import { glob } from 'glob';
4
+ import { detectStack } from '../lib/common.js';
5
+ function report(onStep, id, label, status, detail) {
6
+ onStep({ id, label, status, detail });
7
+ }
8
+ /**
9
+ * Generate an llms.txt file — compact AI-friendly project notation.
10
+ * Reduces token usage by ~75% compared to full README + docs.
11
+ */
12
+ export async function generateLlmsTxt(projectDir, dryRun, onStep) {
13
+ report(onStep, 'scan', 'Scan project structure', 'running');
14
+ const detection = await detectStack(projectDir);
15
+ const stackLabel = detection?.stackType ?? 'unknown';
16
+ // Gather project info
17
+ const name = path.basename(projectDir);
18
+ let description = '';
19
+ let version = '';
20
+ let entryPoints = [];
21
+ let dependencies = [];
22
+ // Try package.json (Node)
23
+ const pkgPath = path.join(projectDir, 'package.json');
24
+ if (await fs.pathExists(pkgPath)) {
25
+ try {
26
+ const pkg = await fs.readJson(pkgPath);
27
+ description = pkg.description ?? '';
28
+ version = pkg.version ?? '';
29
+ entryPoints = pkg.main ? [pkg.main] : [];
30
+ dependencies = Object.keys(pkg.dependencies ?? {}).slice(0, 15);
31
+ }
32
+ catch { /* ignore */ }
33
+ }
34
+ // Scan source files
35
+ const sourceFiles = await glob('src/**/*.{ts,tsx,js,jsx,py,go,rs}', {
36
+ cwd: projectDir,
37
+ ignore: ['**/node_modules/**', '**/dist/**', '**/.git/**'],
38
+ });
39
+ // Scan test files
40
+ const testFiles = await glob('**/*.{test,spec}.{ts,tsx,js,jsx,py}', {
41
+ cwd: projectDir,
42
+ ignore: ['**/node_modules/**', '**/dist/**'],
43
+ });
44
+ report(onStep, 'scan', 'Scan project structure', 'done', `${sourceFiles.length} source, ${testFiles.length} test files`);
45
+ // Build llms.txt content
46
+ report(onStep, 'generate', 'Generate llms.txt', 'running');
47
+ const lines = [
48
+ `# ${name}`,
49
+ '',
50
+ `> ${description || 'No description'}`,
51
+ '',
52
+ `- stack: ${stackLabel}${detection?.buildTool ? ` (${detection.buildTool})` : ''}`,
53
+ `- version: ${version || 'unknown'}`,
54
+ `- files: ${sourceFiles.length} source, ${testFiles.length} tests`,
55
+ '',
56
+ ];
57
+ // Structure summary (compact)
58
+ if (sourceFiles.length > 0) {
59
+ lines.push('## Structure');
60
+ const dirs = new Map();
61
+ for (const f of sourceFiles) {
62
+ const dir = path.dirname(f);
63
+ dirs.set(dir, (dirs.get(dir) ?? 0) + 1);
64
+ }
65
+ for (const [dir, count] of [...dirs.entries()].sort().slice(0, 20)) {
66
+ lines.push(`- ${dir}/ (${count})`);
67
+ }
68
+ lines.push('');
69
+ }
70
+ // Dependencies (compact — name only, no versions)
71
+ if (dependencies.length > 0) {
72
+ lines.push('## Dependencies');
73
+ lines.push(dependencies.join(', '));
74
+ lines.push('');
75
+ }
76
+ // Entry points
77
+ if (entryPoints.length > 0) {
78
+ lines.push('## Entry');
79
+ for (const ep of entryPoints) {
80
+ lines.push(`- ${ep}`);
81
+ }
82
+ lines.push('');
83
+ }
84
+ const content = lines.join('\n');
85
+ const tokenEstimate = Math.ceil(content.length / 4);
86
+ if (!dryRun) {
87
+ await fs.writeFile(path.join(projectDir, 'llms.txt'), content, 'utf-8');
88
+ }
89
+ report(onStep, 'generate', 'Generate llms.txt', 'done', dryRun
90
+ ? `dry-run: ~${tokenEstimate} tokens (${content.length} chars)`
91
+ : `written — ~${tokenEstimate} tokens (${content.length} chars)`);
92
+ }
93
+ //# sourceMappingURL=llmstxt.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=llmstxt.test.d.ts.map
@@ -0,0 +1,24 @@
1
+ import type { InitStep } from '../types/index.js';
2
+ type StepCallback = (step: InitStep) => void;
3
+ /**
4
+ * Add (install) a plugin from a GitHub source.
5
+ */
6
+ export declare function runPluginAdd(source: string, dryRun: boolean, onStep: StepCallback): Promise<void>;
7
+ /**
8
+ * Remove an installed plugin by name.
9
+ */
10
+ export declare function runPluginRemove(name: string, dryRun: boolean, onStep: StepCallback): Promise<void>;
11
+ /**
12
+ * List all installed plugins.
13
+ */
14
+ export declare function runPluginList(onStep: StepCallback): Promise<void>;
15
+ /**
16
+ * Search the remote plugin registry.
17
+ */
18
+ export declare function runPluginSearch(query: string | undefined, onStep: StepCallback): Promise<void>;
19
+ /**
20
+ * Validate a local plugin directory.
21
+ */
22
+ export declare function runPluginValidate(pluginDir: string, onStep: StepCallback): Promise<void>;
23
+ export {};
24
+ //# sourceMappingURL=plugin.d.ts.map