devloom 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/GUIDE.md +487 -0
- package/README.md +235 -0
- package/agents/devloom-analyst.md +83 -0
- package/agents/devloom-architect.md +88 -0
- package/agents/devloom-developer.md +66 -0
- package/agents/devloom-documenter.md +67 -0
- package/agents/devloom-orchestrator.md +367 -0
- package/agents/devloom-qa.md +94 -0
- package/commands/devloom-init.md +60 -0
- package/commands/devloom-resume.md +58 -0
- package/commands/devloom-status.md +23 -0
- package/commands/devloom.md +81 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin.d.ts +4 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +31 -0
- package/dist/plugin.js.map +1 -0
- package/package.json +48 -0
- package/postinstall.mjs +137 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
---
|
|
2
|
+
mode: subagent
|
|
3
|
+
model: opencode/deepseek-v4-flash-free
|
|
4
|
+
hidden: true
|
|
5
|
+
permission:
|
|
6
|
+
edit: allow
|
|
7
|
+
bash: allow
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# DevLoom QA – Quality Inspector
|
|
11
|
+
|
|
12
|
+
## Skill Auto-Detection
|
|
13
|
+
|
|
14
|
+
Read the relevant domain skill file(s) from disk based on the task type:
|
|
15
|
+
- FE task -> cat ~/.config/opencode/skills/build/frontend-development.md
|
|
16
|
+
- BE task -> cat ~/.config/opencode/skills/build/backend-development.md + cat ~/.config/opencode/skills/build/api-design.md
|
|
17
|
+
- API design -> cat ~/.config/opencode/skills/build/api-design.md
|
|
18
|
+
- Testing -> cat ~/.config/opencode/skills/build/test-driven-development.md + cat ~/.config/opencode/skills/verify/quality-assurance.md
|
|
19
|
+
- Security -> cat ~/.config/opencode/skills/review/security-review.md
|
|
20
|
+
- Performance -> cat ~/.config/opencode/skills/review/performance-review.md
|
|
21
|
+
- Debugging -> cat ~/.config/opencode/skills/verify/debugging.md
|
|
22
|
+
- Documentation -> cat ~/.config/opencode/skills/ship/documentation.md
|
|
23
|
+
- Requirements -> cat ~/.config/opencode/skills/define/requirements-analysis.md
|
|
24
|
+
- Planning -> cat ~/.config/opencode/skills/plan/architecture-planning.md
|
|
25
|
+
|
|
26
|
+
At minimum, always read:
|
|
27
|
+
cat ~/.config/opencode/skills/verify/quality-assurance.md
|
|
28
|
+
|
|
29
|
+
You are a QA engineer in the DevLoom weaving pipeline.
|
|
30
|
+
Verify that a single completed task meets its acceptance criteria, passes all
|
|
31
|
+
tests, and introduces no regressions.
|
|
32
|
+
|
|
33
|
+
## Instructions
|
|
34
|
+
|
|
35
|
+
1. Read the task to verify from your prompt. Then read its spec in `.opencode/devloom/plan.md`:
|
|
36
|
+
```bash
|
|
37
|
+
cat .opencode/devloom/plan.md
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
2. Read the files that were modified (reported by the developer in their completion message).
|
|
41
|
+
|
|
42
|
+
3. Write tests if they do not already exist:
|
|
43
|
+
- **Unit tests**: cover every new function, method, or class.
|
|
44
|
+
- **Integration tests**: cover API endpoints or cross-module interactions.
|
|
45
|
+
- **Edge cases**: null/undefined inputs, empty collections, boundary values, error paths.
|
|
46
|
+
- Place test files adjacent to source files following the project's convention
|
|
47
|
+
(e.g., `*.spec.ts`, `*_test.py`, `*_test.go`).
|
|
48
|
+
|
|
49
|
+
4. Run the linter and capture output — do NOT suppress failures with `|| true`,
|
|
50
|
+
as lint errors must be included in a `QA_FAIL` report:
|
|
51
|
+
```bash
|
|
52
|
+
LINT_RESULT=0
|
|
53
|
+
LINT_OUTPUT=$(npm run lint 2>&1) || LINT_RESULT=$?
|
|
54
|
+
if [ $LINT_RESULT -ne 0 ]; then
|
|
55
|
+
LINT_OUTPUT=$(npx eslint src --ext .ts,.js 2>&1) || LINT_RESULT=$?
|
|
56
|
+
fi
|
|
57
|
+
echo "$LINT_OUTPUT"
|
|
58
|
+
# LINT_RESULT is non-zero if linting failed — factor this into your verdict.
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
5. Run the full test suite and capture the result:
|
|
62
|
+
```bash
|
|
63
|
+
TEST_RESULT=0
|
|
64
|
+
TEST_OUTPUT=$(npm test 2>&1) || { TEST_RESULT=$?; TEST_OUTPUT=$(python -m pytest 2>&1) || { TEST_RESULT=$?; TEST_OUTPUT=$(go test ./... 2>&1) || TEST_RESULT=$?; }; }
|
|
65
|
+
echo "$TEST_OUTPUT"
|
|
66
|
+
# TEST_RESULT is non-zero if the test suite failed — factor this into your verdict.
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
6. Verify each acceptance criterion from `.opencode/devloom/plan.md` for this task is met.
|
|
70
|
+
If any criterion is unmet, it is a failure.
|
|
71
|
+
|
|
72
|
+
7. **Report the verdict exactly once** with **exactly one** of these strings:
|
|
73
|
+
|
|
74
|
+
**On success:**
|
|
75
|
+
```
|
|
76
|
+
QA_PASS: [task title]
|
|
77
|
+
Tests written: [list of test files]
|
|
78
|
+
Criteria verified: [list of AC IDs that were checked]
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**On failure:**
|
|
82
|
+
```
|
|
83
|
+
QA_FAIL: [task title]
|
|
84
|
+
Failures:
|
|
85
|
+
- [specific failure 1: file, line, error message or criterion unmet]
|
|
86
|
+
- [specific failure 2: ...]
|
|
87
|
+
Suggested fixes:
|
|
88
|
+
- [concrete fix suggestion 1]
|
|
89
|
+
- [concrete fix suggestion 2]
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**CRITICAL**: Be precise in failure reports — the developer will use them directly to fix the code.
|
|
93
|
+
Do NOT attempt to fix the code yourself or iterate. Report once and stop. The orchestrator
|
|
94
|
+
will determine if the developer retries or the task is skipped after 3 failures.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "DevLoom Init: start fresh execution, clearing any prior state"
|
|
3
|
+
agent: devloom-orchestrator
|
|
4
|
+
subtask: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Force Fresh Start
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Create .opencode/devloom directory if not exists
|
|
11
|
+
mkdir -p .opencode/devloom
|
|
12
|
+
|
|
13
|
+
# Load project config — local config.json overrides global agent models
|
|
14
|
+
# ALL models MUST use opencode/ API prefix (e.g. opencode/deepseek-v4-flash-free)
|
|
15
|
+
if [ -f ".opencode/devloom/config.json" ]; then
|
|
16
|
+
echo "📋 Applying local model config..."
|
|
17
|
+
node -e "
|
|
18
|
+
const c = JSON.parse(require('fs').readFileSync('.opencode/devloom/config.json','utf8'));
|
|
19
|
+
const m = c.models || {};
|
|
20
|
+
for (const [agent, model] of Object.entries(m)) {
|
|
21
|
+
let finalModel = model.trim();
|
|
22
|
+
if (!finalModel.startsWith('opencode/') && !finalModel.startsWith('opencode-go/')) {
|
|
23
|
+
finalModel = 'opencode/' + finalModel;
|
|
24
|
+
console.log(' ⚠️ Added opencode/ prefix to ' + agent + ': ' + model + ' -> ' + finalModel);
|
|
25
|
+
}
|
|
26
|
+
const f = require('os').homedir() + '/.config/opencode/agents/devloom-' + agent + '.md';
|
|
27
|
+
try {
|
|
28
|
+
const fs = require('fs');
|
|
29
|
+
let content = fs.readFileSync(f, 'utf8');
|
|
30
|
+
content = content.replace(/^model:.*/m, 'model: ' + finalModel);
|
|
31
|
+
fs.writeFileSync(f, content);
|
|
32
|
+
console.log(' ' + agent + ' -> ' + finalModel);
|
|
33
|
+
} catch(e) { console.error(' Failed ' + agent + ': ' + e.message); }
|
|
34
|
+
}
|
|
35
|
+
"
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
# Remove any existing state to force fresh start
|
|
39
|
+
rm -f .opencode/devloom/state.json
|
|
40
|
+
rm -f .opencode/devloom/errors.md
|
|
41
|
+
|
|
42
|
+
# Clear requirement/plan files if they exist
|
|
43
|
+
rm -f .opencode/devloom/requirements.md
|
|
44
|
+
rm -f .opencode/devloom/plan.md
|
|
45
|
+
|
|
46
|
+
echo "🔄 Clearing prior state - starting fresh"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
# Fresh DevLoom Orchestration
|
|
50
|
+
|
|
51
|
+
$ARGUMENTS
|
|
52
|
+
|
|
53
|
+
IMPORTANT: Run full workflow from PHASE 0.
|
|
54
|
+
|
|
55
|
+
1. Run PHASE 0 — detect models, ask user preference, update agent files
|
|
56
|
+
2. Invoke @devloom-analyst to create requirements
|
|
57
|
+
3. Invoke @devloom-architect to create plan
|
|
58
|
+
4. Loop through every task: developer → QA → (fix if needed) → mark [x]
|
|
59
|
+
5. Invoke @devloom-documenter and run final quality gate
|
|
60
|
+
6. Output DEVLOOM_DONE only when all tasks are [x] and build passes
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Resume DevLoom from last execution point"
|
|
3
|
+
agent: devloom-orchestrator
|
|
4
|
+
subtask: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Initialize & Dashboard Setup
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Load project config — local config.json overrides global agent models
|
|
11
|
+
# ALL models MUST use opencode/ API prefix (e.g. opencode/deepseek-v4-flash-free)
|
|
12
|
+
if [ -f ".opencode/devloom/config.json" ]; then
|
|
13
|
+
echo "📋 Applying local model config..."
|
|
14
|
+
node -e "
|
|
15
|
+
const c = JSON.parse(require('fs').readFileSync('.opencode/devloom/config.json','utf8'));
|
|
16
|
+
const m = c.models || {};
|
|
17
|
+
for (const [agent, model] of Object.entries(m)) {
|
|
18
|
+
let finalModel = model.trim();
|
|
19
|
+
if (!finalModel.startsWith('opencode/') && !finalModel.startsWith('opencode-go/')) {
|
|
20
|
+
finalModel = 'opencode/' + finalModel;
|
|
21
|
+
console.log(' ⚠️ Added opencode/ prefix to ' + agent + ': ' + model + ' -> ' + finalModel);
|
|
22
|
+
}
|
|
23
|
+
const f = require('os').homedir() + '/.config/opencode/agents/devloom-' + agent + '.md';
|
|
24
|
+
try {
|
|
25
|
+
const fs = require('fs');
|
|
26
|
+
let content = fs.readFileSync(f, 'utf8');
|
|
27
|
+
content = content.replace(/^model:.*/m, 'model: ' + finalModel);
|
|
28
|
+
fs.writeFileSync(f, content);
|
|
29
|
+
console.log(' ' + agent + ' -> ' + finalModel);
|
|
30
|
+
} catch(e) { console.error(' Failed ' + agent + ': ' + e.message); }
|
|
31
|
+
}
|
|
32
|
+
"
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
# Check state file
|
|
36
|
+
STATE_FILE=".opencode/devloom/state.json"
|
|
37
|
+
|
|
38
|
+
if [ -f "$STATE_FILE" ]; then
|
|
39
|
+
PHASE=$(grep -o '"phase":"[^"]*"' "$STATE_FILE" | cut -d'"' -f4)
|
|
40
|
+
echo "Resuming from $PHASE"
|
|
41
|
+
else
|
|
42
|
+
echo "No execution state found. Use /devloom [prompt] to start new execution."
|
|
43
|
+
exit 1
|
|
44
|
+
fi
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
# Resume DevLoom Orchestration
|
|
48
|
+
|
|
49
|
+
RESUME MODE ACTIVE: Execute PRE-PHASE 0 resume detection.
|
|
50
|
+
|
|
51
|
+
1. Check for existing `.opencode/devloom/state.json`
|
|
52
|
+
2. If found: Load phase, completedPhases, tasks.completed, requirements, plan
|
|
53
|
+
3. Skip all completed phases
|
|
54
|
+
4. Jump to next pending phase
|
|
55
|
+
5. Resume execution from that point with existing models and configuration
|
|
56
|
+
6. Do NOT run PHASE 0 (model selection) during resume
|
|
57
|
+
|
|
58
|
+
Execute all remaining tasks until complete, then PHASE 3 delivery and quality gate.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "DevLoom: show the current weaving progress — tasks done, in progress, and any errors"
|
|
3
|
+
agent: devloom-orchestrator
|
|
4
|
+
subtask: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Setup
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
mkdir -p .opencode/devloom
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
# Status Report
|
|
14
|
+
|
|
15
|
+
Read `.opencode/devloom/plan.md` and `.opencode/devloom/errors.md` (if they exist) and report:
|
|
16
|
+
|
|
17
|
+
1. **Progress**: total tasks, completed ([x]), pending ([ ]), completion percentage
|
|
18
|
+
2. **Current task**: the first unchecked task in `.opencode/devloom/plan.md` (if any)
|
|
19
|
+
3. **Errors**: any failed or skipped tasks listed in `.opencode/devloom/errors.md`
|
|
20
|
+
4. **Phase**: which phase the weave is in (Planning / Weaving / Documenting / Done)
|
|
21
|
+
|
|
22
|
+
Format the output as a clean status report. If `.opencode/devloom/plan.md` does not exist,
|
|
23
|
+
report that no weaving session has been started yet.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "DevLoom: weave a full software feature from a single prompt — requirements, code, tests, and docs"
|
|
3
|
+
agent: devloom-orchestrator
|
|
4
|
+
subtask: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Smart Resume Detection
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Create .opencode/devloom directory if not exists
|
|
11
|
+
mkdir -p .opencode/devloom
|
|
12
|
+
|
|
13
|
+
# Load project config — local config.json overrides global agent models
|
|
14
|
+
# ALL models MUST use opencode/ API prefix (e.g. opencode/deepseek-v4-flash-free)
|
|
15
|
+
if [ -f ".opencode/devloom/config.json" ]; then
|
|
16
|
+
echo "📋 Applying local model config..."
|
|
17
|
+
node -e "
|
|
18
|
+
const c = JSON.parse(require('fs').readFileSync('.opencode/devloom/config.json','utf8'));
|
|
19
|
+
const m = c.models || {};
|
|
20
|
+
for (const [agent, model] of Object.entries(m)) {
|
|
21
|
+
// Ensure model has opencode/ or opencode-go/ prefix
|
|
22
|
+
let finalModel = model.trim();
|
|
23
|
+
if (!finalModel.startsWith('opencode/') && !finalModel.startsWith('opencode-go/')) {
|
|
24
|
+
finalModel = 'opencode/' + finalModel;
|
|
25
|
+
console.log(' ⚠️ Added opencode/ prefix to ' + agent + ': ' + model + ' -> ' + finalModel);
|
|
26
|
+
}
|
|
27
|
+
const f = require('os').homedir() + '/.config/opencode/agents/devloom-' + agent + '.md';
|
|
28
|
+
try {
|
|
29
|
+
const fs = require('fs');
|
|
30
|
+
let content = fs.readFileSync(f, 'utf8');
|
|
31
|
+
content = content.replace(/^model:.*/m, 'model: ' + finalModel);
|
|
32
|
+
fs.writeFileSync(f, content);
|
|
33
|
+
console.log(' ' + agent + ' -> ' + finalModel);
|
|
34
|
+
} catch(e) { console.error(' Failed ' + agent + ': ' + e.message); }
|
|
35
|
+
}
|
|
36
|
+
"
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
# Check if state exists
|
|
40
|
+
if [ -f ".opencode/devloom/state.json" ]; then
|
|
41
|
+
PHASE=$(grep -o '"phase":"[^"]*"' .opencode/devloom/state.json | cut -d'"' -f4)
|
|
42
|
+
COMPLETED=$(grep -o '"completed":\[' .opencode/devloom/state.json | wc -l)
|
|
43
|
+
|
|
44
|
+
# If no arguments provided, RESUME existing execution
|
|
45
|
+
if [ -z "$ARGUMENTS" ]; then
|
|
46
|
+
echo "📋 Found existing execution at phase: $PHASE"
|
|
47
|
+
echo "🔄 Resuming from saved state..."
|
|
48
|
+
|
|
49
|
+
# Delegate to orchestrator resume logic (PRE-PHASE 0)
|
|
50
|
+
echo "RESUMING_FROM_STATE"
|
|
51
|
+
else
|
|
52
|
+
# If prompt provided, treat as new execution with same project
|
|
53
|
+
echo "ℹ️ Existing state found. Starting fresh execution with new prompt..."
|
|
54
|
+
fi
|
|
55
|
+
else
|
|
56
|
+
# No prior state
|
|
57
|
+
if [ -z "$ARGUMENTS" ]; then
|
|
58
|
+
echo "❌ No prior execution found. Use: /devloom [description]"
|
|
59
|
+
echo " Or use: /devloom init [description] to start fresh"
|
|
60
|
+
exit 1
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
echo "✨ Starting fresh DevLoom execution..."
|
|
64
|
+
fi
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
# Orchestrator Direction
|
|
68
|
+
|
|
69
|
+
$ARGUMENTS
|
|
70
|
+
|
|
71
|
+
IMPORTANT:
|
|
72
|
+
- If RESUMING_FROM_STATE: Use PRE-PHASE 0 resume detection. Skip completed phases.
|
|
73
|
+
- Otherwise: Run full PHASE 0 → PHASE 1 → PHASE 2 → PHASE 3 workflow.
|
|
74
|
+
|
|
75
|
+
Full workflow:
|
|
76
|
+
1. Run PHASE 0 — detect models, ask user preference, update agent files
|
|
77
|
+
2. Invoke @devloom-analyst to create requirements
|
|
78
|
+
3. Invoke @devloom-architect to create plan
|
|
79
|
+
4. Loop through every task: developer → QA → (fix if needed) → mark [x]
|
|
80
|
+
5. Invoke @devloom-documenter and run final quality gate
|
|
81
|
+
6. Output DEVLOOM_DONE only when all tasks are [x] and build passes
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAGjD,eAAO,MAAM,aAAa,EAAE,MAE3B,CAAA;AAED,eAAe,aAAa,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAElD,MAAM,CAAC,MAAM,aAAa,GAAW,KAAK,EAAE,GAAG,EAAE,EAAE;IACjD,OAAO,oBAAoB,CAAC,GAAG,CAAC,CAAA;AAClC,CAAC,CAAA;AAED,eAAe,aAAa,CAAA"}
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAI7D,iBAAS,oBAAoB,CAAC,IAAI,EAAE,WAAW,GAAG,KAAK,CAkCtD;AAED,OAAO,EAAE,oBAAoB,EAAE,CAAA"}
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { env } from "node:process";
|
|
2
|
+
const PLUGIN_NAME = "devloom";
|
|
3
|
+
function createLifecycleHooks(_ctx) {
|
|
4
|
+
const debug = env.DEVLOOM_DEBUG === "1";
|
|
5
|
+
const log = (message, data) => {
|
|
6
|
+
if (debug) {
|
|
7
|
+
console.log(`[${new Date().toISOString()}] [${PLUGIN_NAME}]`, message, data ? JSON.stringify(data, null, 2) : "");
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
return {
|
|
11
|
+
event: async ({ event }) => {
|
|
12
|
+
log("Event received", {
|
|
13
|
+
type: event.type,
|
|
14
|
+
properties: Object.keys(event.properties ?? {}),
|
|
15
|
+
});
|
|
16
|
+
},
|
|
17
|
+
"tool.execute.before": async ({ tool, sessionID }) => {
|
|
18
|
+
log("Tool executing", { tool, sessionID });
|
|
19
|
+
},
|
|
20
|
+
"tool.execute.after": async ({ tool, sessionID }, output) => {
|
|
21
|
+
log("Tool completed", {
|
|
22
|
+
tool,
|
|
23
|
+
sessionID,
|
|
24
|
+
title: output?.title,
|
|
25
|
+
outputLength: output?.output?.length ?? 0,
|
|
26
|
+
});
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export { createLifecycleHooks };
|
|
31
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AAGlC,MAAM,WAAW,GAAG,SAAS,CAAA;AAE7B,SAAS,oBAAoB,CAAC,IAAiB;IAC7C,MAAM,KAAK,GAAG,GAAG,CAAC,aAAa,KAAK,GAAG,CAAA;IAEvC,MAAM,GAAG,GAAG,CAAC,OAAe,EAAE,IAA8B,EAAE,EAAE;QAC9D,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,GAAG,CACT,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,MAAM,WAAW,GAAG,EAChD,OAAO,EACP,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAC1C,CAAA;QACH,CAAC;IACH,CAAC,CAAA;IAED,OAAO;QACL,KAAK,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;YACzB,GAAG,CAAC,gBAAgB,EAAE;gBACpB,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,IAAI,EAAE,CAAC;aAChD,CAAC,CAAA;QACJ,CAAC;QAED,qBAAqB,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE;YACnD,GAAG,CAAC,gBAAgB,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAA;QAC5C,CAAC;QAED,oBAAoB,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,EAAE;YAC1D,GAAG,CAAC,gBAAgB,EAAE;gBACpB,IAAI;gBACJ,SAAS;gBACT,KAAK,EAAE,MAAM,EAAE,KAAK;gBACpB,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,IAAI,CAAC;aAC1C,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC;AAED,OAAO,EAAE,oBAAoB,EAAE,CAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "devloom",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "DevLoom – Autonomous Development Weaver for OpenCode. Transforms a single prompt into fully tested, documented software.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"agents",
|
|
11
|
+
"commands",
|
|
12
|
+
"postinstall.mjs",
|
|
13
|
+
"README.md",
|
|
14
|
+
"GUIDE.md"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc",
|
|
18
|
+
"dev": "tsc --watch",
|
|
19
|
+
"postinstall": "node postinstall.mjs"
|
|
20
|
+
},
|
|
21
|
+
"peerDependencies": {
|
|
22
|
+
"@opencode-ai/plugin": ">=0.6.0"
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@opencode-ai/plugin": "^1.15.7",
|
|
27
|
+
"@types/node": "^25.9.1",
|
|
28
|
+
"typescript": "^5.4.0"
|
|
29
|
+
},
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/nsrau/devloom.git"
|
|
33
|
+
},
|
|
34
|
+
"bugs": {
|
|
35
|
+
"url": "https://github.com/nsrau/devloom/issues"
|
|
36
|
+
},
|
|
37
|
+
"homepage": "https://github.com/nsrau/devloom#readme",
|
|
38
|
+
"keywords": [
|
|
39
|
+
"opencode",
|
|
40
|
+
"opencode-plugin",
|
|
41
|
+
"devloom",
|
|
42
|
+
"autonomous",
|
|
43
|
+
"agent-loop",
|
|
44
|
+
"weaver",
|
|
45
|
+
"code-generation"
|
|
46
|
+
],
|
|
47
|
+
"license": "MIT"
|
|
48
|
+
}
|
package/postinstall.mjs
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// postinstall.mjs — Installs DevLoom agents, commands, and skills into OpenCode's global config dirs.
|
|
3
|
+
|
|
4
|
+
import { copyFileSync, mkdirSync, existsSync, readdirSync, statSync } from "fs"
|
|
5
|
+
import { resolve, dirname, join, relative } from "path"
|
|
6
|
+
import { fileURLToPath } from "url"
|
|
7
|
+
import { homedir, platform } from "os"
|
|
8
|
+
|
|
9
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
10
|
+
|
|
11
|
+
// ── Config dir resolution (cross-platform) ────────────────────────────────────
|
|
12
|
+
function getConfigDir() {
|
|
13
|
+
const os = platform()
|
|
14
|
+
if (os === "win32") {
|
|
15
|
+
return resolve(process.env.APPDATA ?? homedir(), "opencode")
|
|
16
|
+
}
|
|
17
|
+
if (os === "darwin") {
|
|
18
|
+
return resolve(homedir(), "Library", "Application Support", "opencode")
|
|
19
|
+
}
|
|
20
|
+
return resolve(
|
|
21
|
+
process.env.XDG_CONFIG_HOME ?? join(homedir(), ".config"),
|
|
22
|
+
"opencode"
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const CONFIG_DIR = getConfigDir()
|
|
27
|
+
const AGENTS_DIR = resolve(CONFIG_DIR, "agents")
|
|
28
|
+
const COMMANDS_DIR = resolve(CONFIG_DIR, "commands")
|
|
29
|
+
const SKILLS_DIR = resolve(CONFIG_DIR, "skills")
|
|
30
|
+
|
|
31
|
+
const AGENTS = [
|
|
32
|
+
"devloom-orchestrator",
|
|
33
|
+
"devloom-analyst",
|
|
34
|
+
"devloom-architect",
|
|
35
|
+
"devloom-developer",
|
|
36
|
+
"devloom-qa",
|
|
37
|
+
"devloom-documenter",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
const COMMANDS = ["devloom", "devloom-status", "devloom-resume", "devloom-init"]
|
|
41
|
+
|
|
42
|
+
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
43
|
+
function ensureDir(dir) {
|
|
44
|
+
if (!existsSync(dir)) {
|
|
45
|
+
mkdirSync(dir, { recursive: true })
|
|
46
|
+
console.log(` Created: ${dir}`)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let installFailed = false
|
|
51
|
+
|
|
52
|
+
function installFile(src, dest, label) {
|
|
53
|
+
if (!existsSync(src)) {
|
|
54
|
+
console.error(` Source file not found: ${src}`)
|
|
55
|
+
installFailed = true
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
copyFileSync(src, dest)
|
|
60
|
+
console.log(` ${label}`)
|
|
61
|
+
} catch (err) {
|
|
62
|
+
console.error(` Failed -- ${label}: ${err.message}`)
|
|
63
|
+
installFailed = true
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function installDirRecursive(srcDir, destDir, labelPrefix) {
|
|
68
|
+
if (!existsSync(srcDir)) {
|
|
69
|
+
console.error(` Source dir not found: ${srcDir}`)
|
|
70
|
+
installFailed = true
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
const entries = readdirSync(srcDir)
|
|
74
|
+
ensureDir(destDir)
|
|
75
|
+
for (const entry of entries) {
|
|
76
|
+
const srcPath = join(srcDir, entry)
|
|
77
|
+
const destPath = join(destDir, entry)
|
|
78
|
+
const stat = statSync(srcPath)
|
|
79
|
+
if (stat.isDirectory()) {
|
|
80
|
+
installDirRecursive(srcPath, destPath, `${labelPrefix}/${entry}`)
|
|
81
|
+
} else {
|
|
82
|
+
installFile(srcPath, destPath, `${labelPrefix}/${entry}`)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// ── Main ──────────────────────────────────────────────────────────────────────
|
|
88
|
+
console.log("\nDevLoom -- post-install\n")
|
|
89
|
+
console.log(` Config dir : ${CONFIG_DIR}`)
|
|
90
|
+
console.log(` Agents dir : ${AGENTS_DIR}`)
|
|
91
|
+
console.log(` Commands dir: ${COMMANDS_DIR}`)
|
|
92
|
+
console.log(` Skills dir : ${SKILLS_DIR}\n`)
|
|
93
|
+
|
|
94
|
+
ensureDir(AGENTS_DIR)
|
|
95
|
+
ensureDir(COMMANDS_DIR)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
console.log("Installing agents:")
|
|
99
|
+
for (const name of AGENTS) {
|
|
100
|
+
installFile(
|
|
101
|
+
resolve(__dirname, "agents", `${name}.md`),
|
|
102
|
+
resolve(AGENTS_DIR, `${name}.md`),
|
|
103
|
+
`Agent: ${name}`
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
console.log("\nInstalling commands:")
|
|
108
|
+
for (const name of COMMANDS) {
|
|
109
|
+
installFile(
|
|
110
|
+
resolve(__dirname, "commands", `${name}.md`),
|
|
111
|
+
resolve(COMMANDS_DIR, `${name}.md`),
|
|
112
|
+
`Command: /${name}`
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
console.log("\nInstalling skills:")
|
|
117
|
+
installDirRecursive(
|
|
118
|
+
resolve(__dirname, "skills"),
|
|
119
|
+
SKILLS_DIR,
|
|
120
|
+
"Skill"
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
if (!installFailed) {
|
|
124
|
+
console.log(`
|
|
125
|
+
DevLoom installed successfully!
|
|
126
|
+
|
|
127
|
+
Start weaving:
|
|
128
|
+
/devloom Build a REST API for user management with JWT auth
|
|
129
|
+
/devloom-status
|
|
130
|
+
|
|
131
|
+
Debug mode:
|
|
132
|
+
DEVLOOM_DEBUG=1 opencode @devloom-orchestrator
|
|
133
|
+
`)
|
|
134
|
+
} else {
|
|
135
|
+
console.error("\nSome files could not be installed. See errors above.")
|
|
136
|
+
process.exit(1)
|
|
137
|
+
}
|