dark-factory 0.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.
- package/README.md +276 -0
- package/bin/cli.js +284 -0
- package/package.json +28 -0
- package/template/.claude/agents/architect-agent.md +140 -0
- package/template/.claude/agents/code-agent.md +72 -0
- package/template/.claude/agents/debug-agent.md +193 -0
- package/template/.claude/agents/onboard-agent.md +216 -0
- package/template/.claude/agents/promote-agent.md +78 -0
- package/template/.claude/agents/spec-agent.md +262 -0
- package/template/.claude/agents/test-agent.md +160 -0
- package/template/.claude/rules/dark-factory.md +83 -0
- package/template/.claude/skills/df/SKILL.md +55 -0
- package/template/.claude/skills/df-cleanup/SKILL.md +49 -0
- package/template/.claude/skills/df-debug/SKILL.md +110 -0
- package/template/.claude/skills/df-intake/SKILL.md +153 -0
- package/template/.claude/skills/df-onboard/SKILL.md +34 -0
- package/template/.claude/skills/df-orchestrate/SKILL.md +196 -0
- package/template/.claude/skills/df-scenario/SKILL.md +71 -0
- package/template/.claude/skills/df-spec/SKILL.md +69 -0
package/README.md
ADDED
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
# Dark Factory
|
|
2
|
+
|
|
3
|
+
**Specs in, production-grade features out.**
|
|
4
|
+
|
|
5
|
+
Dark Factory is an open-source multi-agent framework for Claude Code. Feed it a raw idea or a bug report — it assembles a team of AI specialists (BA, principal engineer, developer, QA) who research, challenge, implement, and validate autonomously. No agent can cut corners because no agent has the full picture.
|
|
6
|
+
|
|
7
|
+
> Inspired by [The Dark Factory Pattern](https://hackernoon.com/the-dark-factory-pattern-moving-from-ai-assisted-to-fully-autonomous-coding) — moving from AI-assisted to fully autonomous coding.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
┌─────────────┐
|
|
11
|
+
/df-onboard ──────▶│ Onboard │──▶ project-profile.md
|
|
12
|
+
└─────────────┘
|
|
13
|
+
┌─────────────┐ ┌───────────────┐
|
|
14
|
+
/df-intake ──────▶│ Spec Agent │────▶│ Architect │──▶ APPROVED
|
|
15
|
+
│ (BA) │◀────│ (Principal) │ │
|
|
16
|
+
└─────────────┘ 3+ │ 3+ rounds │ │
|
|
17
|
+
rounds └──────────────┘ ▼
|
|
18
|
+
┌─────────────┐ ┌─────────────┐ ┌──────────┐
|
|
19
|
+
│ Code Agent │────▶│ Test Agent │──▶│ Promote │──▶ Archive
|
|
20
|
+
│ (Dev) │◀────│ (QA) │ │ + Archive│
|
|
21
|
+
└─────────────┘ max└─────────────┘ └──────────┘
|
|
22
|
+
3 rounds
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
**Prerequisites**: [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code) installed + Node.js 18+
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npx dark-factory init
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Then open Claude Code and run `/df-onboard` to map your project.
|
|
36
|
+
|
|
37
|
+
To update to the latest version later:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx dark-factory update
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Usage
|
|
46
|
+
|
|
47
|
+
### 1. Onboard your project (once)
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
/df-onboard
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Maps your tech stack, architecture, conventions, and quality bar into `dark-factory/project-profile.md`. Every agent reads this before starting work.
|
|
54
|
+
|
|
55
|
+
### 2. Add a feature
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
/df-intake I need an API endpoint that lets users export their data as CSV
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
1. **Spec-agent** researches the codebase, asks focused questions, proposes scope (IN/OUT), writes spec + scenarios
|
|
62
|
+
2. You review holdout scenarios in `dark-factory/scenarios/holdout/`
|
|
63
|
+
3. `/df-orchestrate user-csv-export` — architect reviews (3+ rounds), code-agent implements, test-agent validates
|
|
64
|
+
4. On success: holdout tests promoted into your permanent test suite, artifacts archived
|
|
65
|
+
|
|
66
|
+
### 3. Fix a bug
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
/df-debug Users get 500 errors when exporting CSV with special characters in the filename
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
1. **Debug-agent** traces root cause (not just the symptom), maps impact, writes debug report
|
|
73
|
+
2. You confirm the diagnosis
|
|
74
|
+
3. `/df-orchestrate csv-special-chars-fix` — architect reviews, then strict red-green cycle:
|
|
75
|
+
- Write a failing test that **proves** the bug (no source code changes)
|
|
76
|
+
- Implement the minimal fix (no test changes)
|
|
77
|
+
- Failing test now passes, all existing tests still pass
|
|
78
|
+
4. Holdout validation, promote, archive
|
|
79
|
+
|
|
80
|
+
### 4. Maintenance
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
/df-cleanup
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Retries stuck promotions, completes archival, lists stale features.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Why Dark Factory?
|
|
91
|
+
|
|
92
|
+
AI coding assistants write code fast, but fast code on a flawed spec is fast failure. They skip architecture review, miss security concerns, and can't validate their own work honestly — they wrote both the code and the tests.
|
|
93
|
+
|
|
94
|
+
Dark Factory separates concerns into independent agents with strict information barriers:
|
|
95
|
+
|
|
96
|
+
| What goes wrong without it | How Dark Factory prevents it |
|
|
97
|
+
|---|---|
|
|
98
|
+
| AI guesses the scope instead of asking | Spec-agent runs structured discovery — asks focused questions, proposes IN/OUT scope, waits for confirmation |
|
|
99
|
+
| AI skips architecture review | Architect-agent reviews every spec for security, performance, data integrity — 3+ rounds before any code |
|
|
100
|
+
| AI writes tests that match its own implementation | Test-agent uses **holdout scenarios** the code-agent has never seen — can't teach to the test |
|
|
101
|
+
| Bug fixes that mask symptoms | Debug-agent traces root cause forensically; code-agent must write a failing test FIRST, then fix WITHOUT changing the test |
|
|
102
|
+
| AI doesn't understand the existing codebase | Onboard-agent maps architecture, conventions, and quality bar before any work begins |
|
|
103
|
+
| Specs and test artifacts pile up forever | Auto-promote holdout tests into permanent suite, then archive artifacts |
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## How It Works
|
|
108
|
+
|
|
109
|
+
### The 7 Agents
|
|
110
|
+
|
|
111
|
+
| Agent | Role | Analogy |
|
|
112
|
+
|-------|------|---------|
|
|
113
|
+
| **Onboard** | Maps the project before any work begins | New team lead's first week |
|
|
114
|
+
| **Spec** | Discovers scope, challenges assumptions, writes specs | Senior BA who asks hard questions |
|
|
115
|
+
| **Debug** | Forensic root cause analysis, impact assessment | The engineer who reads stack traces for breakfast |
|
|
116
|
+
| **Architect** | Reviews specs for architecture, security, performance | Principal engineer who blocks bad designs |
|
|
117
|
+
| **Code** | Implements features and fixes | Senior dev who follows the spec exactly |
|
|
118
|
+
| **Test** | Validates with hidden scenarios | QA who writes tests the dev has never seen |
|
|
119
|
+
| **Promote** | Moves holdout tests into permanent test suite | Release engineer |
|
|
120
|
+
|
|
121
|
+
### Information Barriers
|
|
122
|
+
|
|
123
|
+
The key innovation. Each agent has **strict boundaries** on what it can see:
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
┌─────────────────────────────────────────────┐
|
|
127
|
+
│ Project Profile │
|
|
128
|
+
│ (all agents except test/promote can read) │
|
|
129
|
+
└─────────────────────────────────────────────┘
|
|
130
|
+
|
|
131
|
+
┌──────────┐ ┌──────────┐ ┌──────────┐
|
|
132
|
+
│ Spec │ │ Code │ │ Test │
|
|
133
|
+
│ Agent │ │ Agent │ │ Agent │
|
|
134
|
+
│ │ │ │ │ │
|
|
135
|
+
│ Sees: │ │ Sees: │ │ Sees: │
|
|
136
|
+
│ codebase │ │ spec, │ │ spec, │
|
|
137
|
+
│ docs │ │ PUBLIC │ │ HOLDOUT │
|
|
138
|
+
│ │ │ scenarios│ │ scenarios│
|
|
139
|
+
│ Cannot: │ │ │ │ │
|
|
140
|
+
│ holdout │ │ Cannot: │ │ Cannot: │
|
|
141
|
+
│ results │ │ HOLDOUT │ │ PUBLIC │
|
|
142
|
+
└──────────┘ │ results │ │ scenarios│
|
|
143
|
+
└──────────┘ └──────────┘
|
|
144
|
+
|
|
145
|
+
┌──────────┐
|
|
146
|
+
│Architect │ Can see: spec, codebase, project profile
|
|
147
|
+
│ Agent │ CANNOT see: ANY scenarios (public or holdout)
|
|
148
|
+
│ │ CANNOT discuss tests with other agents
|
|
149
|
+
└──────────┘
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
The code-agent can't "teach to the test" because it never sees the holdout scenarios. The architect can't compromise test coverage because it never sees tests at all. The test-agent can't soften its validation because it doesn't know what the code-agent was told to build.
|
|
153
|
+
|
|
154
|
+
### Red-Green Cycle (Bugfixes)
|
|
155
|
+
|
|
156
|
+
Dark Factory enforces strict discipline that prevents the most common AI failure mode: fixing the symptom instead of the root cause.
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
Phase 1 (Red): Write test → Test FAILS ✓ (bug is real)
|
|
160
|
+
⚠ Zero source code changes allowed
|
|
161
|
+
|
|
162
|
+
Phase 2 (Green): Implement fix → Test PASSES ✓ (fix works)
|
|
163
|
+
⚠ Zero test file changes allowed
|
|
164
|
+
⚠ All existing tests must still pass
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
If the test doesn't fail in Phase 1, the test is wrong — not the bug. If existing tests break in Phase 2, the fix has regression — revise the fix, not the tests.
|
|
168
|
+
|
|
169
|
+
### Feature Lifecycle
|
|
170
|
+
|
|
171
|
+
Every feature is tracked in `dark-factory/manifest.json`:
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
active → passed → promoted → archived
|
|
175
|
+
│ │ │ │
|
|
176
|
+
│ │ │ └── Specs + scenarios in dark-factory/archive/
|
|
177
|
+
│ │ └── Holdout tests in permanent test suite
|
|
178
|
+
│ └── All holdout tests passed
|
|
179
|
+
└── Spec created, awaiting implementation
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
`/df-cleanup` recovers features stuck in intermediate states.
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Reference
|
|
187
|
+
|
|
188
|
+
### Commands
|
|
189
|
+
|
|
190
|
+
| Command | What it does |
|
|
191
|
+
|---------|-------------|
|
|
192
|
+
| `/df-onboard` | Map project architecture, conventions, quality bar |
|
|
193
|
+
| `/df-intake {desc}` | Create feature spec (discovers scope, writes scenarios) |
|
|
194
|
+
| `/df-debug {desc}` | Investigate bug (root cause, impact, debug report) |
|
|
195
|
+
| `/df-orchestrate {name}` | Implement (architect review → code → test → promote → archive) |
|
|
196
|
+
| `/df-cleanup` | Recover stuck features, list stale work |
|
|
197
|
+
| `/df-spec` | Show spec templates for manual writing |
|
|
198
|
+
| `/df-scenario` | Show scenario templates for manual writing |
|
|
199
|
+
|
|
200
|
+
### Project Structure
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
your-project/
|
|
204
|
+
├── .claude/
|
|
205
|
+
│ ├── agents/ # 7 agent definitions
|
|
206
|
+
│ │ ├── onboard-agent.md
|
|
207
|
+
│ │ ├── spec-agent.md
|
|
208
|
+
│ │ ├── debug-agent.md
|
|
209
|
+
│ │ ├── architect-agent.md
|
|
210
|
+
│ │ ├── code-agent.md
|
|
211
|
+
│ │ ├── test-agent.md
|
|
212
|
+
│ │ └── promote-agent.md
|
|
213
|
+
│ └── skills/ # 7 slash commands
|
|
214
|
+
│ ├── df-onboard/SKILL.md
|
|
215
|
+
│ ├── df-intake/SKILL.md
|
|
216
|
+
│ ├── df-debug/SKILL.md
|
|
217
|
+
│ ├── df-orchestrate/SKILL.md
|
|
218
|
+
│ ├── df-spec/SKILL.md
|
|
219
|
+
│ ├── df-scenario/SKILL.md
|
|
220
|
+
│ └── df-cleanup/SKILL.md
|
|
221
|
+
├── dark-factory/
|
|
222
|
+
│ ├── project-profile.md # Project map (from /df-onboard)
|
|
223
|
+
│ ├── manifest.json # Feature lifecycle tracking
|
|
224
|
+
│ ├── specs/features/ # Feature specs
|
|
225
|
+
│ ├── specs/bugfixes/ # Debug reports
|
|
226
|
+
│ ├── scenarios/public/ # Visible to code-agent
|
|
227
|
+
│ ├── scenarios/holdout/ # Hidden from code-agent
|
|
228
|
+
│ ├── results/ # Test output (gitignored)
|
|
229
|
+
│ └── archive/ # Completed feature artifacts
|
|
230
|
+
└── CLAUDE.md # Project instructions (auto-updated)
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Configuration
|
|
234
|
+
|
|
235
|
+
The init script auto-detects your project type:
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
# Force a project type
|
|
239
|
+
node scripts/init-dark-factory.js --dir . --project-type nestjs
|
|
240
|
+
node scripts/init-dark-factory.js --dir . --project-type node
|
|
241
|
+
node scripts/init-dark-factory.js --dir . --project-type generic
|
|
242
|
+
|
|
243
|
+
# Scaffold a first feature
|
|
244
|
+
node scripts/init-dark-factory.js --dir . --feature user-auth
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Supported project types affect agent prompts (e.g., NestJS agents know about modules, decorators, and DTOs).
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## Design Decisions
|
|
252
|
+
|
|
253
|
+
**Why holdout scenarios?** — Without them, the AI writes code and tests from the same understanding. Holdout scenarios are written by the spec-agent (who understands the requirements) and validated by the test-agent (who never talks to the code-agent). The code-agent must implement correctly to pass tests it's never seen.
|
|
254
|
+
|
|
255
|
+
**Why architect review?** — A spec written by a BA may miss performance concerns, security gaps, or architectural inconsistencies. The architect-agent reviews every spec with principal-engineer rigor — but is banned from seeing tests, so it can't influence what gets tested.
|
|
256
|
+
|
|
257
|
+
**Why strict red-green for bugs?** — The most dangerous AI bug fix is one that makes the test pass by changing the test. Dark Factory enforces: write the test first (Phase 1, no code changes allowed), then fix the code (Phase 2, no test changes allowed). If the test doesn't fail, the test is wrong.
|
|
258
|
+
|
|
259
|
+
**Why project onboarding?** — An AI dropped into an unknown codebase will follow "best practices" instead of "this project's practices." The onboard-agent maps reality — messy or clean — so every agent works WITH the existing patterns instead of against them.
|
|
260
|
+
|
|
261
|
+
**Why auto-promote and archive?** — Dark Factory artifacts (specs, scenarios) accumulate forever. After holdout tests pass, they're automatically promoted into the permanent test suite (preserving regression coverage) and artifacts are archived.
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## Contributing
|
|
266
|
+
|
|
267
|
+
Contributions welcome. The test suite is the source of truth — if the tests pass, the pipeline is intact.
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
# Run all tests (no dependencies — uses Node.js built-in test runner)
|
|
271
|
+
node --test tests/dark-factory-setup.test.js
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## License
|
|
275
|
+
|
|
276
|
+
MIT
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Dark Factory CLI
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* npx dark-factory init Install Dark Factory into current project
|
|
8
|
+
* npx dark-factory update Update agents/skills/rules to latest version
|
|
9
|
+
* npx dark-factory init --dir /path/to/project
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const fs = require("fs");
|
|
13
|
+
const path = require("path");
|
|
14
|
+
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Helpers
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
|
|
19
|
+
const RESET = "\x1b[0m";
|
|
20
|
+
const BOLD = "\x1b[1m";
|
|
21
|
+
const DIM = "\x1b[2m";
|
|
22
|
+
const GREEN = "\x1b[32m";
|
|
23
|
+
const YELLOW = "\x1b[33m";
|
|
24
|
+
const CYAN = "\x1b[36m";
|
|
25
|
+
|
|
26
|
+
function log(msg) { console.log(msg); }
|
|
27
|
+
function info(msg) { console.log(` ${GREEN}+${RESET} ${msg}`); }
|
|
28
|
+
function update(msg) { console.log(` ${YELLOW}~${RESET} ${msg}`); }
|
|
29
|
+
function skip(msg) { console.log(` ${DIM}-${RESET} ${DIM}${msg}${RESET}`); }
|
|
30
|
+
|
|
31
|
+
function ensureDir(dirPath) {
|
|
32
|
+
if (!fs.existsSync(dirPath)) {
|
|
33
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function touchGitkeep(dirPath) {
|
|
40
|
+
ensureDir(dirPath);
|
|
41
|
+
const keepPath = path.join(dirPath, ".gitkeep");
|
|
42
|
+
if (!fs.existsSync(keepPath)) {
|
|
43
|
+
fs.writeFileSync(keepPath, "", "utf8");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function copyFileWithLog(src, dest) {
|
|
48
|
+
const rel = path.relative(process.cwd(), dest);
|
|
49
|
+
ensureDir(path.dirname(dest));
|
|
50
|
+
|
|
51
|
+
if (fs.existsSync(dest)) {
|
|
52
|
+
const existing = fs.readFileSync(dest, "utf8");
|
|
53
|
+
const incoming = fs.readFileSync(src, "utf8");
|
|
54
|
+
if (existing === incoming) {
|
|
55
|
+
skip(`${rel} (unchanged)`);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
update(rel);
|
|
59
|
+
} else {
|
|
60
|
+
info(rel);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
fs.copyFileSync(src, dest);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function copyDirRecursive(src, dest) {
|
|
67
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
68
|
+
for (const entry of entries) {
|
|
69
|
+
const srcPath = path.join(src, entry.name);
|
|
70
|
+
const destPath = path.join(dest, entry.name);
|
|
71
|
+
if (entry.isDirectory()) {
|
|
72
|
+
copyDirRecursive(srcPath, destPath);
|
|
73
|
+
} else {
|
|
74
|
+
copyFileWithLog(srcPath, destPath);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
// .gitignore management
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
|
|
83
|
+
function updateGitignore(dir) {
|
|
84
|
+
const gitignorePath = path.join(dir, ".gitignore");
|
|
85
|
+
let content = "";
|
|
86
|
+
if (fs.existsSync(gitignorePath)) {
|
|
87
|
+
content = fs.readFileSync(gitignorePath, "utf8");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
let modified = false;
|
|
91
|
+
|
|
92
|
+
// .claude selective tracking
|
|
93
|
+
const claudeEntries = [
|
|
94
|
+
"/.claude/*",
|
|
95
|
+
"!/.claude/agents/",
|
|
96
|
+
"!/.claude/rules/",
|
|
97
|
+
"!/.claude/skills/",
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
const claudeLineRegex = /^[/#]*\s*\.?\/?\.claude\s*$/m;
|
|
101
|
+
if (claudeLineRegex.test(content)) {
|
|
102
|
+
content = content.replace(claudeLineRegex, claudeEntries.join("\n"));
|
|
103
|
+
modified = true;
|
|
104
|
+
} else if (!content.includes("/.claude/*")) {
|
|
105
|
+
content += "\n# Claude Code — selectively track agents, rules, and skills\n" + claudeEntries.join("\n") + "\n";
|
|
106
|
+
modified = true;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Ensure !/.claude/rules/ is present (may be missing from older installs)
|
|
110
|
+
if (content.includes("/.claude/*") && !content.includes("!/.claude/rules/")) {
|
|
111
|
+
content = content.replace("!/.claude/skills/", "!/.claude/rules/\n!/.claude/skills/");
|
|
112
|
+
modified = true;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// dark-factory/results
|
|
116
|
+
if (!content.includes("dark-factory/results")) {
|
|
117
|
+
content += "\n# Dark Factory results (local test output)\ndark-factory/results/\n";
|
|
118
|
+
modified = true;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (modified) {
|
|
122
|
+
fs.writeFileSync(gitignorePath, content, "utf8");
|
|
123
|
+
update(".gitignore");
|
|
124
|
+
} else {
|
|
125
|
+
skip(".gitignore (already configured)");
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
// Commands
|
|
131
|
+
// ---------------------------------------------------------------------------
|
|
132
|
+
|
|
133
|
+
function cmdInit(targetDir, opts = {}) {
|
|
134
|
+
const templateDir = path.join(__dirname, "..", "template");
|
|
135
|
+
|
|
136
|
+
log("");
|
|
137
|
+
log(`${BOLD}Dark Factory${RESET} — installing into ${CYAN}${targetDir}${RESET}`);
|
|
138
|
+
log("");
|
|
139
|
+
|
|
140
|
+
// 1. Copy .claude/ (agents, skills, rules) — always overwrite to latest
|
|
141
|
+
log(`${BOLD}Agents & Skills${RESET}`);
|
|
142
|
+
copyDirRecursive(
|
|
143
|
+
path.join(templateDir, ".claude"),
|
|
144
|
+
path.join(targetDir, ".claude"),
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
// 2. Create dark-factory/ working directories — never overwrite existing content
|
|
148
|
+
log("");
|
|
149
|
+
log(`${BOLD}Working directories${RESET}`);
|
|
150
|
+
const dfDir = path.join(targetDir, "dark-factory");
|
|
151
|
+
const dirs = [
|
|
152
|
+
"specs/features",
|
|
153
|
+
"specs/bugfixes",
|
|
154
|
+
"scenarios/public",
|
|
155
|
+
"scenarios/holdout",
|
|
156
|
+
"results",
|
|
157
|
+
"archive",
|
|
158
|
+
];
|
|
159
|
+
for (const d of dirs) {
|
|
160
|
+
const full = path.join(dfDir, d);
|
|
161
|
+
if (ensureDir(full)) {
|
|
162
|
+
info(`dark-factory/${d}/`);
|
|
163
|
+
} else {
|
|
164
|
+
skip(`dark-factory/${d}/ (exists)`);
|
|
165
|
+
}
|
|
166
|
+
touchGitkeep(full);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// 3. Create manifest.json if missing
|
|
170
|
+
const manifestPath = path.join(dfDir, "manifest.json");
|
|
171
|
+
if (!fs.existsSync(manifestPath)) {
|
|
172
|
+
fs.writeFileSync(manifestPath, JSON.stringify({ version: 1, features: {} }, null, 2) + "\n", "utf8");
|
|
173
|
+
info("dark-factory/manifest.json");
|
|
174
|
+
} else {
|
|
175
|
+
skip("dark-factory/manifest.json (exists)");
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// 4. Update .gitignore
|
|
179
|
+
log("");
|
|
180
|
+
log(`${BOLD}Git config${RESET}`);
|
|
181
|
+
updateGitignore(targetDir);
|
|
182
|
+
|
|
183
|
+
// Done
|
|
184
|
+
log("");
|
|
185
|
+
log(`${GREEN}${BOLD}Done!${RESET} Dark Factory is ready.`);
|
|
186
|
+
log("");
|
|
187
|
+
log(`${BOLD}Next steps:${RESET}`);
|
|
188
|
+
log(` 1. Run ${CYAN}/df-onboard${RESET} in Claude Code to map your project`);
|
|
189
|
+
log(` 2. Describe a feature or bug — Dark Factory activates automatically`);
|
|
190
|
+
log(` 3. Or use ${CYAN}/df {description}${RESET} explicitly`);
|
|
191
|
+
log("");
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function cmdUpdate(targetDir) {
|
|
195
|
+
const templateDir = path.join(__dirname, "..", "template");
|
|
196
|
+
|
|
197
|
+
log("");
|
|
198
|
+
log(`${BOLD}Dark Factory${RESET} — updating agents, skills & rules in ${CYAN}${targetDir}${RESET}`);
|
|
199
|
+
log("");
|
|
200
|
+
|
|
201
|
+
log(`${BOLD}Agents & Skills${RESET}`);
|
|
202
|
+
copyDirRecursive(
|
|
203
|
+
path.join(templateDir, ".claude"),
|
|
204
|
+
path.join(targetDir, ".claude"),
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
// Also update .gitignore in case new entries were added
|
|
208
|
+
log("");
|
|
209
|
+
log(`${BOLD}Git config${RESET}`);
|
|
210
|
+
updateGitignore(targetDir);
|
|
211
|
+
|
|
212
|
+
log("");
|
|
213
|
+
log(`${GREEN}${BOLD}Updated!${RESET} Agents, skills, and rules are now at the latest version.`);
|
|
214
|
+
log(` Your specs, scenarios, and manifest were not touched.`);
|
|
215
|
+
log("");
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function cmdHelp() {
|
|
219
|
+
log(`
|
|
220
|
+
${BOLD}Dark Factory${RESET} — AI-powered development pipeline for Claude Code
|
|
221
|
+
|
|
222
|
+
${BOLD}Usage:${RESET}
|
|
223
|
+
npx dark-factory init Install into current project
|
|
224
|
+
npx dark-factory update Update agents/skills/rules to latest
|
|
225
|
+
npx dark-factory help Show this help
|
|
226
|
+
|
|
227
|
+
${BOLD}Options:${RESET}
|
|
228
|
+
--dir <path> Target directory (default: current dir)
|
|
229
|
+
|
|
230
|
+
${BOLD}What gets installed:${RESET}
|
|
231
|
+
.claude/agents/ 7 specialized AI agents
|
|
232
|
+
.claude/skills/ 8 slash command skills (/df, /df-intake, etc.)
|
|
233
|
+
.claude/rules/ Auto-detection rules
|
|
234
|
+
dark-factory/ Working directory (specs, scenarios, results)
|
|
235
|
+
|
|
236
|
+
${BOLD}After install:${RESET}
|
|
237
|
+
1. Open Claude Code in your project
|
|
238
|
+
2. Run /df-onboard to map your project
|
|
239
|
+
3. Just describe what you need — Dark Factory activates automatically
|
|
240
|
+
`);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// ---------------------------------------------------------------------------
|
|
244
|
+
// Main
|
|
245
|
+
// ---------------------------------------------------------------------------
|
|
246
|
+
|
|
247
|
+
function main() {
|
|
248
|
+
const args = process.argv.slice(2);
|
|
249
|
+
let command = null;
|
|
250
|
+
let targetDir = process.cwd();
|
|
251
|
+
|
|
252
|
+
for (let i = 0; i < args.length; i++) {
|
|
253
|
+
if (args[i] === "--dir" && args[i + 1]) {
|
|
254
|
+
targetDir = path.resolve(args[++i]);
|
|
255
|
+
} else if (args[i] === "--help" || args[i] === "-h") {
|
|
256
|
+
command = "help";
|
|
257
|
+
} else if (!args[i].startsWith("-")) {
|
|
258
|
+
command = args[i];
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
switch (command) {
|
|
263
|
+
case "init":
|
|
264
|
+
cmdInit(targetDir);
|
|
265
|
+
break;
|
|
266
|
+
case "update":
|
|
267
|
+
cmdUpdate(targetDir);
|
|
268
|
+
break;
|
|
269
|
+
case "help":
|
|
270
|
+
cmdHelp();
|
|
271
|
+
break;
|
|
272
|
+
default:
|
|
273
|
+
// No command = init (most common use case)
|
|
274
|
+
if (!command) {
|
|
275
|
+
cmdInit(targetDir);
|
|
276
|
+
} else {
|
|
277
|
+
log(`Unknown command: ${command}`);
|
|
278
|
+
log(`Run 'npx dark-factory help' for usage.`);
|
|
279
|
+
process.exit(1);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
main();
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dark-factory",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "AI-powered development pipeline for Claude Code — specs in, production-grade features out",
|
|
5
|
+
"bin": {
|
|
6
|
+
"dark-factory": "bin/cli.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"bin/",
|
|
10
|
+
"template/"
|
|
11
|
+
],
|
|
12
|
+
"keywords": [
|
|
13
|
+
"claude",
|
|
14
|
+
"claude-code",
|
|
15
|
+
"ai",
|
|
16
|
+
"development",
|
|
17
|
+
"pipeline",
|
|
18
|
+
"agents",
|
|
19
|
+
"spec",
|
|
20
|
+
"testing"
|
|
21
|
+
],
|
|
22
|
+
"author": "",
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/nguyenhuynhkhanh/dark-factory.git"
|
|
27
|
+
}
|
|
28
|
+
}
|