devloom 1.0.0 → 1.2.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/.ai/core.dsl +44 -0
- package/.ai/skills.dsl +39 -0
- package/.ai/verify.dsl +97 -0
- package/.ai/workflow.dsl +81 -0
- package/.opencode/themes/devloom-night-owl.json +103 -0
- package/GUIDE.md +572 -115
- package/README.md +583 -109
- package/SECURITY.md +93 -0
- package/agents/devloom-developer-flash.md +31 -0
- package/agents/devloom-developer-senior.md +32 -0
- package/agents/devloom-developer.md +21 -55
- package/agents/devloom-documenter-flash.md +28 -0
- package/agents/devloom-documenter.md +17 -56
- package/agents/devloom-orchestrator.md +236 -356
- package/agents/devloom-planner-flash.md +34 -0
- package/agents/devloom-planner-senior.md +35 -0
- package/agents/devloom-planner.md +36 -0
- package/agents/devloom-qa-flash.md +32 -0
- package/agents/devloom-qa.md +21 -83
- package/agents/devloom-security-senior.md +35 -0
- package/agents/devloom-security.md +34 -0
- package/agents/devloom-verifier.md +33 -0
- package/agents/devloom-vision.md +113 -0
- package/agents/devloom-visual-critic.md +102 -0
- package/agents/devloom-visual-director.md +84 -0
- package/commands/devloom-agents.md +49 -0
- package/commands/devloom-auto.md +11 -0
- package/commands/devloom-context.md +82 -0
- package/commands/devloom-deepseek-mimo.md +11 -0
- package/commands/devloom-deepseek.md +11 -0
- package/commands/devloom-free.md +11 -0
- package/commands/devloom-go-economy.md +11 -0
- package/commands/devloom-go-flash.md +11 -0
- package/commands/devloom-go.md +11 -0
- package/commands/devloom-init.md +28 -50
- package/commands/devloom-loop-status.md +25 -0
- package/commands/devloom-loop.md +36 -0
- package/commands/devloom-mimo.md +11 -0
- package/commands/devloom-plan.md +13 -0
- package/commands/devloom-refresh.md +22 -0
- package/commands/devloom-resume.md +30 -49
- package/commands/devloom-save.md +69 -0
- package/commands/devloom-status.md +9 -18
- package/commands/devloom.md +99 -67
- package/dist/agents.d.ts +30 -0
- package/dist/agents.d.ts.map +1 -0
- package/dist/agents.js +139 -0
- package/dist/agents.js.map +1 -0
- package/dist/bootstrap.d.ts +56 -0
- package/dist/bootstrap.d.ts.map +1 -0
- package/dist/bootstrap.js +116 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/constraints.d.ts +5 -0
- package/dist/constraints.d.ts.map +1 -0
- package/dist/constraints.js +45 -0
- package/dist/constraints.js.map +1 -0
- package/dist/context.d.ts +42 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +636 -0
- package/dist/context.js.map +1 -0
- package/dist/guard.d.ts +19 -0
- package/dist/guard.d.ts.map +1 -0
- package/dist/guard.js +418 -0
- package/dist/guard.js.map +1 -0
- package/dist/loop.d.ts +64 -0
- package/dist/loop.d.ts.map +1 -0
- package/dist/loop.js +164 -0
- package/dist/loop.js.map +1 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +101 -1
- package/dist/plugin.js.map +1 -1
- package/dist/tui-agents.d.ts +61 -0
- package/dist/tui-agents.d.ts.map +1 -0
- package/dist/tui-agents.js +89 -0
- package/dist/tui-agents.js.map +1 -0
- package/dist/tui.d.ts +6 -0
- package/dist/tui.d.ts.map +1 -0
- package/dist/tui.js +92 -0
- package/dist/tui.js.map +1 -0
- package/dist/worktree.d.ts +46 -0
- package/dist/worktree.d.ts.map +1 -0
- package/dist/worktree.js +272 -0
- package/dist/worktree.js.map +1 -0
- package/package.json +46 -6
- package/patterns/changelog-drafter.md +38 -0
- package/patterns/ci-sweeper.md +40 -0
- package/patterns/daily-triage.md +37 -0
- package/patterns/dependency-sweeper.md +40 -0
- package/patterns/design-audit.md +63 -0
- package/patterns/issue-triage.md +37 -0
- package/patterns/post-merge-cleanup.md +34 -0
- package/patterns/pr-babysitter.md +37 -0
- package/patterns/registry.yaml +52 -0
- package/postinstall.mjs +264 -64
- package/project/README.md +29 -0
- package/protocol/agent-contracts.md +27 -0
- package/protocol/artifact-system.md +53 -0
- package/protocol/model-routing.md +194 -0
- package/protocol/orchestrator-core.md +43 -0
- package/protocol/project-system.md +45 -0
- package/protocol/rules.md +18 -0
- package/protocol/verification-policy.md +48 -0
- package/scripts/briefing.mjs +192 -0
- package/scripts/loop-run.mjs +205 -0
- package/scripts/model-capabilities.mjs +194 -0
- package/scripts/plugin-cache.mjs +269 -0
- package/scripts/profile.mjs +755 -0
- package/scripts/visual-benchmark.mjs +149 -0
- package/scripts/worktree.mjs +445 -0
- package/skills/build/development.md +33 -0
- package/skills/build/live-docs.md +38 -0
- package/skills/build/simplify.md +50 -0
- package/skills/build/vision-analysis.md +98 -0
- package/skills/design/app-design.md +31 -0
- package/skills/design/design-grounding.md +30 -0
- package/skills/design/design-system.md +27 -0
- package/skills/design/game-design.md +35 -0
- package/skills/design/motion-design.md +34 -0
- package/skills/design/visual-direction.md +32 -0
- package/skills/design/web-design.md +33 -0
- package/skills/loop/changelog-drafter.md +32 -0
- package/skills/loop/ci-sweeper.md +24 -0
- package/skills/loop/constraints.md +21 -0
- package/skills/loop/dependency-sweeper.md +24 -0
- package/skills/loop/design-audit.md +67 -0
- package/skills/loop/issue-triage.md +27 -0
- package/skills/loop/post-merge-cleanup.md +24 -0
- package/skills/loop/pr-babysitter.md +26 -0
- package/skills/loop/triage.md +25 -0
- package/skills/loop/verifier.md +20 -0
- package/skills/meta/skill-discovery.md +23 -0
- package/skills/plan/planning.md +27 -0
- package/skills/plan/verification-planning.md +40 -0
- package/skills/review/security-review.md +63 -0
- package/skills/ship/documentation.md +11 -0
- package/skills/verify/app-verification.md +19 -0
- package/skills/verify/quality-assurance.md +17 -0
- package/skills/verify/visual-critique.md +30 -0
- package/skills/verify/visual-quality-gate.md +29 -0
- package/skills/verify/visual-regression.md +25 -0
- package/agents/devloom-analyst.md +0 -83
- package/agents/devloom-architect.md +0 -88
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "DevLoom: persist current project state and pause"
|
|
3
|
+
agent: devloom-orchestrator
|
|
4
|
+
subtask: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Save
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
mkdir -p .opencode/devloom/project/{stories,tasks,bugs,decisions,reports}
|
|
11
|
+
|
|
12
|
+
node -e "
|
|
13
|
+
const fs = require('fs');
|
|
14
|
+
const p = '.opencode/devloom/project';
|
|
15
|
+
const readJson = (f, fb) => {
|
|
16
|
+
try { return JSON.parse(fs.readFileSync(f, 'utf8')); } catch { return fb; }
|
|
17
|
+
};
|
|
18
|
+
const cfg = readJson(p + '/config.json', {});
|
|
19
|
+
const board = readJson(p + '/board.json', {});
|
|
20
|
+
const state = readJson(p + '/state.json', {});
|
|
21
|
+
const now = new Date().toISOString();
|
|
22
|
+
const next = {
|
|
23
|
+
v: 1,
|
|
24
|
+
phase: state.phase || 'paused',
|
|
25
|
+
prompt: state.prompt || '',
|
|
26
|
+
ticket: state.ticket || board.active || '',
|
|
27
|
+
next: 'user-command',
|
|
28
|
+
updatedAt: now,
|
|
29
|
+
notes: Array.isArray(state.notes) ? state.notes : []
|
|
30
|
+
};
|
|
31
|
+
const normalizedCfg = {
|
|
32
|
+
v: 1,
|
|
33
|
+
lang: 'en',
|
|
34
|
+
tracker: cfg.tracker === 'github' ? 'github' : 'local',
|
|
35
|
+
gh: {
|
|
36
|
+
enabled: !!cfg.gh?.enabled,
|
|
37
|
+
owner: cfg.gh?.owner || '',
|
|
38
|
+
repo: cfg.gh?.repo || '',
|
|
39
|
+
project: cfg.gh?.project || ''
|
|
40
|
+
},
|
|
41
|
+
rules: { flow: ['analysis','documentation','implementation','verification','regression','done'], tests: 'required', regression: 'required', queue: 'single', docs: 'official', delegation: 'required', skills: 'required', memory: 'load', save: 'always', promptTask: 'append-last' }
|
|
42
|
+
};
|
|
43
|
+
fs.writeFileSync(p + '/config.json', JSON.stringify(normalizedCfg));
|
|
44
|
+
fs.writeFileSync(p + '/board.json', JSON.stringify({
|
|
45
|
+
v: 1,
|
|
46
|
+
tracker: normalizedCfg.tracker,
|
|
47
|
+
active: board.active || next.ticket || '',
|
|
48
|
+
cols: {
|
|
49
|
+
backlog: Array.isArray(board.cols?.backlog) ? board.cols.backlog : [],
|
|
50
|
+
ready: Array.isArray(board.cols?.ready) ? board.cols.ready : [],
|
|
51
|
+
doing: Array.isArray(board.cols?.doing) ? board.cols.doing.slice(0, 1) : (board.active ? [board.active] : []),
|
|
52
|
+
review: Array.isArray(board.cols?.review) ? board.cols.review : [],
|
|
53
|
+
blocked: Array.isArray(board.cols?.blocked) ? board.cols.blocked : [],
|
|
54
|
+
done: Array.isArray(board.cols?.done) ? board.cols.done : []
|
|
55
|
+
},
|
|
56
|
+
updatedAt: now
|
|
57
|
+
}));
|
|
58
|
+
fs.writeFileSync(p + '/state.json', JSON.stringify(next));
|
|
59
|
+
fs.writeFileSync(p + '/README.md', '# DevLoom Project Workspace\\nAll artifacts in this workspace must be written in English.\\nAI-only state files use minified JSON to reduce token usage.\\n');
|
|
60
|
+
"
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
MODE: Pause
|
|
64
|
+
LOAD: `.opencode/devloom/project/config.json|board.json|state.json`
|
|
65
|
+
OUT:
|
|
66
|
+
- state persisted
|
|
67
|
+
- ticket/todo/plan context preserved for the next prompt
|
|
68
|
+
- next=user-command
|
|
69
|
+
- resume with `/devloom-resume` or new `/devloom ...` prompt
|
|
@@ -1,23 +1,14 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: "DevLoom: show
|
|
2
|
+
description: "DevLoom: show progress, active ticket, and phase"
|
|
3
3
|
agent: devloom-orchestrator
|
|
4
4
|
subtask: false
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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.
|
|
7
|
+
LOAD: `.opencode/devloom/plan.md|.opencode/devloom/errors.md|.opencode/devloom/project/board.json|.opencode/devloom/project/state.json`
|
|
8
|
+
REPORT:
|
|
9
|
+
- progress: total|done|pending|pct
|
|
10
|
+
- active: current ticket (in doing)
|
|
11
|
+
- queued: count of items in backlog (waiting behind active work)
|
|
12
|
+
- blocked: blocked tickets
|
|
13
|
+
- errors: failed/skipped work
|
|
14
|
+
- phase: analysis|documentation|implementation|verification|regression|queued|done
|
package/commands/devloom.md
CHANGED
|
@@ -1,81 +1,113 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: "DevLoom:
|
|
2
|
+
description: "DevLoom: autonomous delivery from one prompt"
|
|
3
3
|
agent: devloom-orchestrator
|
|
4
4
|
subtask: false
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
#
|
|
7
|
+
# Boot
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
|
|
11
|
-
mkdir -p .opencode/devloom
|
|
10
|
+
mkdir -p .opencode/devloom/project/{stories,tasks,bugs,decisions,reports}
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
|
12
|
+
export SANITIZED_PROMPT="$(node -e "
|
|
13
|
+
let p = process.argv[1] || '';
|
|
14
|
+
p = p.slice(0, 4000).replace(/[\x00-\x08\x0E-\x1F\x7F]/g, '');
|
|
15
|
+
process.stdout.write(p);
|
|
16
|
+
" -- "$ARGUMENTS")"
|
|
38
17
|
|
|
39
|
-
|
|
40
|
-
|
|
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..."
|
|
18
|
+
if [ -z "$SANITIZED_PROMPT" ] && [ -n "$ARGUMENTS" ]; then
|
|
19
|
+
SANITIZED_PROMPT="$ARGUMENTS"
|
|
64
20
|
fi
|
|
65
|
-
```
|
|
66
21
|
|
|
67
|
-
|
|
22
|
+
DEVLOOM_PROMPT="$SANITIZED_PROMPT" node -e "
|
|
23
|
+
const fs = require('fs');
|
|
24
|
+
const p = '.opencode/devloom/project';
|
|
25
|
+
const readJson = (f, fb) => {
|
|
26
|
+
try { return JSON.parse(fs.readFileSync(f, 'utf8')); } catch { return fb; }
|
|
27
|
+
};
|
|
28
|
+
const prompt = (process.env.DEVLOOM_PROMPT || '').trim();
|
|
29
|
+
const cfg = readJson(p + '/config.json', {});
|
|
30
|
+
const board = readJson(p + '/board.json', {});
|
|
31
|
+
const state = readJson(p + '/state.json', {});
|
|
32
|
+
const now = new Date().toISOString();
|
|
33
|
+
const taskId = prompt ? 'PROMPT-' + now.replace(/[-:.TZ]/g, '').slice(0, 14) : '';
|
|
34
|
+
const todoPath = p + '/tasks/TODO.md';
|
|
35
|
+
const normalizedCfg = {
|
|
36
|
+
v: 1,
|
|
37
|
+
lang: 'en',
|
|
38
|
+
tracker: cfg.tracker === 'github' ? 'github' : 'local',
|
|
39
|
+
gh: {
|
|
40
|
+
enabled: !!cfg.gh?.enabled,
|
|
41
|
+
owner: cfg.gh?.owner || '',
|
|
42
|
+
repo: cfg.gh?.repo || '',
|
|
43
|
+
project: cfg.gh?.project || ''
|
|
44
|
+
},
|
|
45
|
+
rules: { flow: ['analysis','documentation','implementation','verification','regression','done'], tests: 'required', regression: 'required', queue: 'single', docs: 'official', delegation: 'required', skills: 'required', memory: 'load', save: 'always', promptTask: 'append-last' }
|
|
46
|
+
};
|
|
47
|
+
const active = typeof board.active === 'string' ? board.active : '';
|
|
48
|
+
const backlog = Array.isArray(board.cols?.backlog) ? board.cols.backlog : [];
|
|
49
|
+
const nextBacklog = taskId ? [...backlog, taskId] : backlog;
|
|
50
|
+
const todoHeader = '# DevLoom Prompt Tasks\nEvery /devloom prompt is appended here as the last todo before execution routing.\n\n';
|
|
51
|
+
if (!fs.existsSync(todoPath)) fs.writeFileSync(todoPath, todoHeader);
|
|
52
|
+
if (taskId) fs.appendFileSync(todoPath, '- [ ] ' + taskId + ' :: ' + prompt.replace(/\\s+/g, ' ') + '\n');
|
|
53
|
+
const normalizedBoard = {
|
|
54
|
+
v: 1,
|
|
55
|
+
tracker: normalizedCfg.tracker,
|
|
56
|
+
active,
|
|
57
|
+
cols: {
|
|
58
|
+
backlog: nextBacklog,
|
|
59
|
+
ready: Array.isArray(board.cols?.ready) ? board.cols.ready : [],
|
|
60
|
+
doing: Array.isArray(board.cols?.doing) ? board.cols.doing.slice(0, 1) : (active ? [active] : []),
|
|
61
|
+
review: Array.isArray(board.cols?.review) ? board.cols.review : [],
|
|
62
|
+
blocked: Array.isArray(board.cols?.blocked) ? board.cols.blocked : [],
|
|
63
|
+
done: Array.isArray(board.cols?.done) ? board.cols.done : []
|
|
64
|
+
},
|
|
65
|
+
updatedAt: now
|
|
66
|
+
};
|
|
67
|
+
const normalizedState = {
|
|
68
|
+
v: 1,
|
|
69
|
+
phase: typeof state.phase === 'string' ? state.phase : 'idle',
|
|
70
|
+
prompt: prompt || (typeof state.prompt === 'string' ? state.prompt : ''),
|
|
71
|
+
ticket: typeof state.ticket === 'string' ? state.ticket : active,
|
|
72
|
+
next: typeof state.next === 'string' ? state.next : 'analysis',
|
|
73
|
+
updatedAt: now,
|
|
74
|
+
notes: Array.isArray(state.notes) ? state.notes : []
|
|
75
|
+
};
|
|
76
|
+
fs.writeFileSync(p + '/README.md', '# DevLoom Project Workspace\\nAll artifacts in this workspace must be written in English.\\nAI-only state files use minified JSON to reduce token usage.\\n');
|
|
77
|
+
fs.writeFileSync(p + '/config.json', JSON.stringify(normalizedCfg));
|
|
78
|
+
fs.writeFileSync(p + '/board.json', JSON.stringify(normalizedBoard));
|
|
79
|
+
fs.writeFileSync(p + '/state.json', JSON.stringify(normalizedState));
|
|
80
|
+
"
|
|
81
|
+
|
|
82
|
+
if [ -f ".opencode/devloom/config.json" ]; then
|
|
83
|
+
echo "Applying local model config..."
|
|
68
84
|
|
|
69
|
-
$
|
|
85
|
+
PROFILE_MJS="$(node -e 'const fs=require("fs"),p=require("path");console.log(p.join(p.dirname(fs.realpathSync(process.argv[1])),"profile.mjs"))' "$0" 2>/dev/null)"
|
|
86
|
+
[ -f "$PROFILE_MJS" ] || PROFILE_MJS="$HOME/.config/opencode/devloom-scripts/profile.mjs"
|
|
87
|
+
[ -f "$PROFILE_MJS" ] || PROFILE_MJS="$HOME/.config/opencode/commands/profile.mjs"
|
|
88
|
+
[ -f "$PROFILE_MJS" ] || { echo "profile.mjs not found - reinstall DevLoom"; exit 1; }
|
|
89
|
+
|
|
90
|
+
INIT_PROFILE="$(node -e "const c=require('./.opencode/devloom/config.json'); process.stdout.write(c.profile||'auto')" 2>/dev/null || echo auto)"
|
|
91
|
+
|
|
92
|
+
node "$PROFILE_MJS" set "$INIT_PROFILE" 2>&1
|
|
93
|
+
node "$PROFILE_MJS" apply 2>&1
|
|
94
|
+
fi
|
|
95
|
+
```
|
|
70
96
|
|
|
71
|
-
|
|
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.
|
|
97
|
+
# Run
|
|
74
98
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
99
|
+
PROMPT: `$SANITIZED_PROMPT`
|
|
100
|
+
LOAD: `.opencode/devloom/project/config.json|.opencode/devloom/project/board.json|.opencode/devloom/project/state.json`
|
|
101
|
+
RULES:
|
|
102
|
+
- English-only artifacts
|
|
103
|
+
- normalize existing project files to canonical JSONM/English format before execution
|
|
104
|
+
- load memory and relevant skills before planning new work
|
|
105
|
+
- append every prompt as the last task/todo in `.opencode/devloom/project/tasks/TODO.md`
|
|
106
|
+
- auto-create or update tickets, todos, and plan entries for the prompt
|
|
107
|
+
- persist board+state every phase
|
|
108
|
+
- IF board.cols.doing is non-empty: queue the prompt to backlog, do NOT start new work — the orchestrator will see the queue and exit
|
|
109
|
+
- continue pending work first (only when doing is empty) unless user reprioritizes
|
|
110
|
+
- one active ticket by default — new prompts are queued when doing is occupied
|
|
111
|
+
- delegate specialist work to DevLoom subagents by default
|
|
112
|
+
- triage first: pick the minimal agent chain for the prompt intent (see workflow.dsl CHAINS); never run the full pipeline by default
|
|
113
|
+
- DEVLOOM_DONE only when the chosen chain's gates pass
|
package/dist/agents.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface ActiveProfile {
|
|
2
|
+
profile?: string;
|
|
3
|
+
resolvedProfile?: string;
|
|
4
|
+
models?: Record<string, string>;
|
|
5
|
+
tier?: string | null;
|
|
6
|
+
}
|
|
7
|
+
export declare function readActiveProfile(rootDir: string): ActiveProfile | null;
|
|
8
|
+
export declare function profileLabel(profile: ActiveProfile | null): string;
|
|
9
|
+
export declare function agentVariantVisible(_profile: ActiveProfile | null, variant: string): boolean;
|
|
10
|
+
export interface DevloomAgentMeta {
|
|
11
|
+
name: string;
|
|
12
|
+
role: string;
|
|
13
|
+
description: string;
|
|
14
|
+
mode: "subagent" | "primary" | "all";
|
|
15
|
+
color: string;
|
|
16
|
+
model: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function listDevloomAgents(profile: ActiveProfile | null): DevloomAgentMeta[];
|
|
19
|
+
export interface DevloomAgentConfig {
|
|
20
|
+
description?: string;
|
|
21
|
+
mode?: "subagent" | "primary" | "all";
|
|
22
|
+
model?: string;
|
|
23
|
+
color?: string;
|
|
24
|
+
hidden?: boolean;
|
|
25
|
+
}
|
|
26
|
+
export declare function buildAgentConfigs(rootDir: string): Record<string, DevloomAgentConfig>;
|
|
27
|
+
export declare function injectDevloomAgents(opencodeConfig: {
|
|
28
|
+
agent?: Record<string, DevloomAgentConfig | undefined>;
|
|
29
|
+
}, rootDir: string): void;
|
|
30
|
+
//# sourceMappingURL=agents.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../src/agents.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACrB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAQvE;AAKD,wBAAgB,YAAY,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,GAAG,MAAM,CAKlE;AAQD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAE5F;AAeD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,UAAU,GAAG,SAAS,GAAG,KAAK,CAAA;IACpC,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;CACd;AAgDD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,GAAG,gBAAgB,EAAE,CAmBnF;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,CAAC,EAAE,UAAU,GAAG,SAAS,GAAG,KAAK,CAAA;IACrC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAiBrF;AAED,wBAAgB,mBAAmB,CACjC,cAAc,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,GAAG,SAAS,CAAC,CAAA;CAAE,EAC1E,OAAO,EAAE,MAAM,GACd,IAAI,CAUN"}
|
package/dist/agents.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
export function readActiveProfile(rootDir) {
|
|
4
|
+
const p = join(rootDir, ".opencode", "devloom", "config.json");
|
|
5
|
+
if (!existsSync(p))
|
|
6
|
+
return null;
|
|
7
|
+
try {
|
|
8
|
+
return JSON.parse(readFileSync(p, "utf8"));
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
// Human-readable label shown in the sidebar so the current DevLoom profile is
|
|
15
|
+
// visible at a glance (e.g. "DevLoom Orchestrator: ... (profile: go-flash)").
|
|
16
|
+
// With a senior tier override the label is extended to "(profile: go, tier: senior)".
|
|
17
|
+
export function profileLabel(profile) {
|
|
18
|
+
const name = profile?.resolvedProfile ?? profile?.profile;
|
|
19
|
+
if (!name)
|
|
20
|
+
return "";
|
|
21
|
+
const tier = profile?.tier === "senior" ? ", tier: senior" : "";
|
|
22
|
+
return ` (profile: ${name}${tier})`;
|
|
23
|
+
}
|
|
24
|
+
// Whether a given agent variant should be surfaced in the sidebar / @-menu.
|
|
25
|
+
// Only base and non-tiered variants (orchestrator, developer, planner, qa,
|
|
26
|
+
// security, verifier, documenter, vision) are shown — flash and senior variants
|
|
27
|
+
// are always hidden regardless of the active profile. Non-matching variants
|
|
28
|
+
// stay registered so orchestrator task() routing keeps working; they are only
|
|
29
|
+
// hidden from the UI. Pure function, no fs access.
|
|
30
|
+
export function agentVariantVisible(_profile, variant) {
|
|
31
|
+
return !variant.endsWith("-flash") && !variant.endsWith("-senior");
|
|
32
|
+
}
|
|
33
|
+
const AGENT_VARIANTS = {
|
|
34
|
+
developer: ["developer", "developer-flash", "developer-senior"],
|
|
35
|
+
planner: ["planner", "planner-flash", "planner-senior"],
|
|
36
|
+
qa: ["qa", "qa-flash"],
|
|
37
|
+
verifier: ["verifier"],
|
|
38
|
+
security: ["security", "security-senior"],
|
|
39
|
+
documenter: ["documenter", "documenter-flash"],
|
|
40
|
+
orchestrator: ["orchestrator"],
|
|
41
|
+
vision: ["vision"],
|
|
42
|
+
"visual-director": ["visual-director"],
|
|
43
|
+
"visual-critic": ["visual-critic"],
|
|
44
|
+
};
|
|
45
|
+
const ROLE_COLORS = {
|
|
46
|
+
orchestrator: "#7fdbca",
|
|
47
|
+
planner: "#c792ea",
|
|
48
|
+
developer: "#addb67",
|
|
49
|
+
qa: "#ecc48d",
|
|
50
|
+
verifier: "#82aaff",
|
|
51
|
+
security: "#ff5874",
|
|
52
|
+
documenter: "#f07178",
|
|
53
|
+
vision: "#f78c6c",
|
|
54
|
+
"visual-director": "#c3e88d",
|
|
55
|
+
"visual-critic": "#89ddff",
|
|
56
|
+
};
|
|
57
|
+
const DESCRIPTIONS = {
|
|
58
|
+
"devloom-orchestrator": "DevLoom Orchestrator: autonomous multi-agent delivery",
|
|
59
|
+
"devloom-planner": "DevLoom Planner: callable by the orchestrator for requirements and architecture planning",
|
|
60
|
+
"devloom-planner-senior": "DevLoom Planner Senior: callable by the orchestrator for complex requirements and architecture planning",
|
|
61
|
+
"devloom-planner-flash": "DevLoom Planner Flash: callable by the orchestrator for lightweight requirements and planning",
|
|
62
|
+
"devloom-developer": "DevLoom Developer: callable by the orchestrator for ticket implementation and defect fixes",
|
|
63
|
+
"devloom-developer-senior": "DevLoom Developer Senior: callable by the orchestrator for complex ticket implementation and defect fixes",
|
|
64
|
+
"devloom-developer-flash": "DevLoom Developer Flash: callable by the orchestrator for simple ticket implementation and defect fixes",
|
|
65
|
+
"devloom-qa": "DevLoom QA: callable by the orchestrator for verification, code review, and regression",
|
|
66
|
+
"devloom-qa-flash": "DevLoom QA Flash: callable by the orchestrator for lightweight verification, code review, and regression",
|
|
67
|
+
"devloom-verifier": "DevLoom Verifier: callable by the orchestrator for runtime app verification across scopes",
|
|
68
|
+
"devloom-security": "DevLoom Security: callable by the orchestrator for CRUD endpoint and exposure-surface review",
|
|
69
|
+
"devloom-security-senior": "DevLoom Security Senior: callable by the orchestrator for deep CRUD endpoint and exposure-surface review",
|
|
70
|
+
"devloom-documenter": "DevLoom Documenter: callable by the orchestrator for documentation and state updates",
|
|
71
|
+
"devloom-documenter-flash": "DevLoom Documenter Flash: callable by the orchestrator for lightweight documentation and state updates",
|
|
72
|
+
"devloom-vision": "DevLoom Vision: read-only image description specialist. Takes an image, returns structured description. Nothing else.",
|
|
73
|
+
"devloom-visual-director": "DevLoom Visual Director: read-only design brief writer. Emits DESIGN_FILE spec for UI work.",
|
|
74
|
+
"devloom-visual-critic": "DevLoom Visual Critic: read-only visual reviewer. Scores screenshots against the design contract and issues a delta verdict.",
|
|
75
|
+
};
|
|
76
|
+
const DEFAULT_MODELS = {
|
|
77
|
+
orchestrator: "opencode-go/deepseek-v4-flash",
|
|
78
|
+
planner: "opencode-go/qwen3.7-max",
|
|
79
|
+
developer: "opencode-go/kimi-k2.7-code",
|
|
80
|
+
qa: "opencode-go/deepseek-v4-flash",
|
|
81
|
+
verifier: "opencode-go/deepseek-v4-flash",
|
|
82
|
+
security: "opencode-go/deepseek-v4-flash",
|
|
83
|
+
documenter: "opencode-go/deepseek-v4-flash",
|
|
84
|
+
vision: "opencode-go/qwen3.6-plus",
|
|
85
|
+
"visual-director": "opencode-go/qwen3.6-plus",
|
|
86
|
+
"visual-critic": "opencode-go/qwen3.6-plus",
|
|
87
|
+
};
|
|
88
|
+
export function listDevloomAgents(profile) {
|
|
89
|
+
const agents = [];
|
|
90
|
+
const models = profile?.models ?? {};
|
|
91
|
+
for (const [role, variants] of Object.entries(AGENT_VARIANTS)) {
|
|
92
|
+
const color = ROLE_COLORS[role] ?? "#7fdbca";
|
|
93
|
+
for (const variant of variants) {
|
|
94
|
+
const name = `devloom-${variant}`;
|
|
95
|
+
const isOrchestrator = name === "devloom-orchestrator";
|
|
96
|
+
agents.push({
|
|
97
|
+
name,
|
|
98
|
+
role,
|
|
99
|
+
description: `${DESCRIPTIONS[name] ?? `DevLoom ${variant}`}${isOrchestrator ? profileLabel(profile) : ""}`,
|
|
100
|
+
mode: isOrchestrator ? "all" : "subagent",
|
|
101
|
+
color,
|
|
102
|
+
model: models[role] ?? DEFAULT_MODELS[role] ?? "",
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return agents;
|
|
107
|
+
}
|
|
108
|
+
export function buildAgentConfigs(rootDir) {
|
|
109
|
+
const profile = readActiveProfile(rootDir);
|
|
110
|
+
if (!profile || !profile.models)
|
|
111
|
+
return {};
|
|
112
|
+
const configs = {};
|
|
113
|
+
for (const agent of listDevloomAgents(profile)) {
|
|
114
|
+
// listDevloomAgents names agents `devloom-${variant}`; recover the variant
|
|
115
|
+
// so the visibility rule applies to the same string unit tests use.
|
|
116
|
+
const variant = agent.name.startsWith("devloom-") ? agent.name.slice("devloom-".length) : agent.name;
|
|
117
|
+
configs[agent.name] = {
|
|
118
|
+
description: agent.description,
|
|
119
|
+
mode: agent.mode,
|
|
120
|
+
model: agent.model,
|
|
121
|
+
color: agent.color,
|
|
122
|
+
hidden: !agentVariantVisible(profile, variant),
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
return configs;
|
|
126
|
+
}
|
|
127
|
+
export function injectDevloomAgents(opencodeConfig, rootDir) {
|
|
128
|
+
const configs = buildAgentConfigs(rootDir);
|
|
129
|
+
if (Object.keys(configs).length === 0)
|
|
130
|
+
return;
|
|
131
|
+
opencodeConfig.agent = opencodeConfig.agent ?? {};
|
|
132
|
+
for (const [name, agent] of Object.entries(configs)) {
|
|
133
|
+
const existing = opencodeConfig.agent[name];
|
|
134
|
+
opencodeConfig.agent[name] = existing
|
|
135
|
+
? { ...existing, ...agent }
|
|
136
|
+
: agent;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=agents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agents.js","sourceRoot":"","sources":["../src/agents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAShC,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC/C,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,CAAC,CAAA;IAC9D,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAA;IAC/B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAkB,CAAA;IAC7D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,8EAA8E;AAC9E,sFAAsF;AACtF,MAAM,UAAU,YAAY,CAAC,OAA6B;IACxD,MAAM,IAAI,GAAG,OAAO,EAAE,eAAe,IAAI,OAAO,EAAE,OAAO,CAAA;IACzD,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAA;IACpB,MAAM,IAAI,GAAG,OAAO,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAA;IAC/D,OAAO,cAAc,IAAI,GAAG,IAAI,GAAG,CAAA;AACrC,CAAC;AAED,4EAA4E;AAC5E,2EAA2E;AAC3E,gFAAgF;AAChF,4EAA4E;AAC5E,8EAA8E;AAC9E,mDAAmD;AACnD,MAAM,UAAU,mBAAmB,CAAC,QAA8B,EAAE,OAAe;IACjF,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAA;AACpE,CAAC;AAED,MAAM,cAAc,GAA6B;IAC/C,SAAS,EAAE,CAAC,WAAW,EAAE,iBAAiB,EAAE,kBAAkB,CAAC;IAC/D,OAAO,EAAE,CAAC,SAAS,EAAE,eAAe,EAAE,gBAAgB,CAAC;IACvD,EAAE,EAAE,CAAC,IAAI,EAAE,UAAU,CAAC;IACtB,QAAQ,EAAE,CAAC,UAAU,CAAC;IACtB,QAAQ,EAAE,CAAC,UAAU,EAAE,iBAAiB,CAAC;IACzC,UAAU,EAAE,CAAC,YAAY,EAAE,kBAAkB,CAAC;IAC9C,YAAY,EAAE,CAAC,cAAc,CAAC;IAC9B,MAAM,EAAE,CAAC,QAAQ,CAAC;IAClB,iBAAiB,EAAE,CAAC,iBAAiB,CAAC;IACtC,eAAe,EAAE,CAAC,eAAe,CAAC;CACnC,CAAA;AAWD,MAAM,WAAW,GAA2B;IAC1C,YAAY,EAAE,SAAS;IACvB,OAAO,EAAE,SAAS;IAClB,SAAS,EAAE,SAAS;IACpB,EAAE,EAAE,SAAS;IACb,QAAQ,EAAE,SAAS;IACnB,QAAQ,EAAE,SAAS;IACnB,UAAU,EAAE,SAAS;IACrB,MAAM,EAAE,SAAS;IACjB,iBAAiB,EAAE,SAAS;IAC5B,eAAe,EAAE,SAAS;CAC3B,CAAA;AAED,MAAM,YAAY,GAA2B;IAC3C,sBAAsB,EAAE,uDAAuD;IAC/E,iBAAiB,EAAE,0FAA0F;IAC7G,wBAAwB,EAAE,yGAAyG;IACnI,uBAAuB,EAAE,+FAA+F;IACxH,mBAAmB,EAAE,4FAA4F;IACjH,0BAA0B,EAAE,2GAA2G;IACvI,yBAAyB,EAAE,yGAAyG;IACpI,YAAY,EAAE,wFAAwF;IACtG,kBAAkB,EAAE,0GAA0G;IAC9H,kBAAkB,EAAE,2FAA2F;IAC/G,kBAAkB,EAAE,8FAA8F;IAClH,yBAAyB,EAAE,0GAA0G;IACrI,oBAAoB,EAAE,sFAAsF;IAC5G,0BAA0B,EAAE,wGAAwG;IACpI,gBAAgB,EAAE,uHAAuH;IACzI,yBAAyB,EAAE,6FAA6F;IACxH,uBAAuB,EAAE,8HAA8H;CACxJ,CAAA;AAED,MAAM,cAAc,GAA2B;IAC7C,YAAY,EAAE,+BAA+B;IAC7C,OAAO,EAAE,yBAAyB;IAClC,SAAS,EAAE,4BAA4B;IACvC,EAAE,EAAE,+BAA+B;IACnC,QAAQ,EAAE,+BAA+B;IACzC,QAAQ,EAAE,+BAA+B;IACzC,UAAU,EAAE,+BAA+B;IAC3C,MAAM,EAAE,0BAA0B;IAClC,iBAAiB,EAAE,0BAA0B;IAC7C,eAAe,EAAE,0BAA0B;CAC5C,CAAA;AAED,MAAM,UAAU,iBAAiB,CAAC,OAA6B;IAC7D,MAAM,MAAM,GAAuB,EAAE,CAAA;IACrC,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,EAAE,CAAA;IACpC,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC;QAC9D,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,SAAS,CAAA;QAC5C,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,IAAI,GAAG,WAAW,OAAO,EAAE,CAAA;YACjC,MAAM,cAAc,GAAG,IAAI,KAAK,sBAAsB,CAAA;YACtD,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI;gBACJ,IAAI;gBACJ,WAAW,EAAE,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,WAAW,OAAO,EAAE,GAAG,cAAc,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;gBAC1G,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU;gBACzC,KAAK;gBACL,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE;aAClD,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAUD,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC/C,MAAM,OAAO,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAA;IAC1C,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM;QAAE,OAAO,EAAE,CAAA;IAC1C,MAAM,OAAO,GAAuC,EAAE,CAAA;IACtD,KAAK,MAAM,KAAK,IAAI,iBAAiB,CAAC,OAAO,CAAC,EAAE,CAAC;QAC/C,2EAA2E;QAC3E,oEAAoE;QACpE,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAA;QACpG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG;YACpB,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,MAAM,EAAE,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC;SAC/C,CAAA;IACH,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,cAA0E,EAC1E,OAAe;IAEf,MAAM,OAAO,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAA;IAC1C,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC;QAAE,OAAM;IAC7C,cAAc,CAAC,KAAK,GAAG,cAAc,CAAC,KAAK,IAAI,EAAE,CAAA;IACjD,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACpD,MAAM,QAAQ,GAAG,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC3C,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,QAAQ;YACnC,CAAC,CAAC,EAAE,GAAG,QAAQ,EAAE,GAAG,KAAK,EAAE;YAC3B,CAAC,CAAC,KAAK,CAAA;IACX,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
type ProjectState = {
|
|
2
|
+
v: number;
|
|
3
|
+
phase: string;
|
|
4
|
+
prompt: string;
|
|
5
|
+
ticket: string;
|
|
6
|
+
next: string;
|
|
7
|
+
updatedAt: string;
|
|
8
|
+
notes: string[];
|
|
9
|
+
sessions: Record<string, string>;
|
|
10
|
+
degraded: boolean;
|
|
11
|
+
};
|
|
12
|
+
type ProjectBoard = {
|
|
13
|
+
v: number;
|
|
14
|
+
tracker: "local" | "github";
|
|
15
|
+
active: string;
|
|
16
|
+
cols: {
|
|
17
|
+
backlog: string[];
|
|
18
|
+
ready: string[];
|
|
19
|
+
doing: string[];
|
|
20
|
+
review: string[];
|
|
21
|
+
blocked: string[];
|
|
22
|
+
done: string[];
|
|
23
|
+
};
|
|
24
|
+
updatedAt: string;
|
|
25
|
+
};
|
|
26
|
+
type ProjectConfig = {
|
|
27
|
+
v: number;
|
|
28
|
+
lang: "en";
|
|
29
|
+
tracker: "local" | "github";
|
|
30
|
+
gh: {
|
|
31
|
+
enabled: boolean;
|
|
32
|
+
owner: string;
|
|
33
|
+
repo: string;
|
|
34
|
+
project: string;
|
|
35
|
+
};
|
|
36
|
+
rules: {
|
|
37
|
+
flow: string[];
|
|
38
|
+
tests: "required";
|
|
39
|
+
regression: "required";
|
|
40
|
+
queue: "single";
|
|
41
|
+
docs: "official";
|
|
42
|
+
delegation: "required";
|
|
43
|
+
skills: "required";
|
|
44
|
+
memory: "load";
|
|
45
|
+
save: "always";
|
|
46
|
+
promptTask: "append-last";
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
export declare function ensureProjectWorkspace(rootDir: string): {
|
|
50
|
+
config: ProjectConfig;
|
|
51
|
+
board: ProjectBoard;
|
|
52
|
+
state: ProjectState;
|
|
53
|
+
projectRoot: string;
|
|
54
|
+
};
|
|
55
|
+
export {};
|
|
56
|
+
//# sourceMappingURL=bootstrap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../src/bootstrap.ts"],"names":[],"mappings":"AAIA,KAAK,YAAY,GAAG;IAClB,CAAC,EAAE,MAAM,CAAA;IACT,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,QAAQ,EAAE,OAAO,CAAA;CAClB,CAAA;AAED,KAAK,YAAY,GAAG;IAClB,CAAC,EAAE,MAAM,CAAA;IACT,OAAO,EAAE,OAAO,GAAG,QAAQ,CAAA;IAC3B,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE;QACJ,OAAO,EAAE,MAAM,EAAE,CAAA;QACjB,KAAK,EAAE,MAAM,EAAE,CAAA;QACf,KAAK,EAAE,MAAM,EAAE,CAAA;QACf,MAAM,EAAE,MAAM,EAAE,CAAA;QAChB,OAAO,EAAE,MAAM,EAAE,CAAA;QACjB,IAAI,EAAE,MAAM,EAAE,CAAA;KACf,CAAA;IACD,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,KAAK,aAAa,GAAG;IACnB,CAAC,EAAE,MAAM,CAAA;IACT,IAAI,EAAE,IAAI,CAAA;IACV,OAAO,EAAE,OAAO,GAAG,QAAQ,CAAA;IAC3B,EAAE,EAAE;QACF,OAAO,EAAE,OAAO,CAAA;QAChB,KAAK,EAAE,MAAM,CAAA;QACb,IAAI,EAAE,MAAM,CAAA;QACZ,OAAO,EAAE,MAAM,CAAA;KAChB,CAAA;IACD,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,EAAE,CAAA;QACd,KAAK,EAAE,UAAU,CAAA;QACjB,UAAU,EAAE,UAAU,CAAA;QACtB,KAAK,EAAE,QAAQ,CAAA;QACf,IAAI,EAAE,UAAU,CAAA;QAChB,UAAU,EAAE,UAAU,CAAA;QACtB,MAAM,EAAE,UAAU,CAAA;QAClB,MAAM,EAAE,MAAM,CAAA;QACd,IAAI,EAAE,QAAQ,CAAA;QACd,UAAU,EAAE,aAAa,CAAA;KAC1B,CAAA;CACF,CAAA;AA8FD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM;;;;;EA+BrD"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { ensureLoopWorkspace } from "./loop.js";
|
|
4
|
+
const PROJECT_DIRS = ["stories", "tasks", "bugs", "decisions", "reports"];
|
|
5
|
+
const WORKSPACE_README = [
|
|
6
|
+
"# DevLoom Project Workspace",
|
|
7
|
+
"All artifacts in this workspace must be written in English.",
|
|
8
|
+
"AI-only state files use minified JSON to reduce token usage.",
|
|
9
|
+
"Every new /devloom prompt must be appended as the last task in project/tasks/TODO.md before execution continues.",
|
|
10
|
+
"Default workflow: load state, inspect memory, use relevant skills, delegate to subagents, keep tickets/todos/plan updated, and save state at every phase boundary.",
|
|
11
|
+
"",
|
|
12
|
+
].join("\n");
|
|
13
|
+
function ensureDir(path) {
|
|
14
|
+
if (!existsSync(path))
|
|
15
|
+
mkdirSync(path, { recursive: true });
|
|
16
|
+
}
|
|
17
|
+
function readJson(path, fallback) {
|
|
18
|
+
try {
|
|
19
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return fallback;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function normalizeStringArray(value) {
|
|
26
|
+
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
27
|
+
}
|
|
28
|
+
function normalizeTracker(value) {
|
|
29
|
+
return value === "github" ? "github" : "local";
|
|
30
|
+
}
|
|
31
|
+
function normalizeConfig(value) {
|
|
32
|
+
const cfg = typeof value === "object" && value ? value : {};
|
|
33
|
+
return {
|
|
34
|
+
v: 1,
|
|
35
|
+
lang: "en",
|
|
36
|
+
tracker: normalizeTracker(cfg.tracker),
|
|
37
|
+
gh: {
|
|
38
|
+
enabled: Boolean(cfg.gh?.enabled),
|
|
39
|
+
owner: typeof cfg.gh?.owner === "string" ? cfg.gh.owner : "",
|
|
40
|
+
repo: typeof cfg.gh?.repo === "string" ? cfg.gh.repo : "",
|
|
41
|
+
project: typeof cfg.gh?.project === "string" ? cfg.gh.project : "",
|
|
42
|
+
},
|
|
43
|
+
rules: {
|
|
44
|
+
flow: ["analysis", "documentation", "implementation", "verification", "regression", "done"],
|
|
45
|
+
tests: "required",
|
|
46
|
+
regression: "required",
|
|
47
|
+
queue: "single",
|
|
48
|
+
docs: "official",
|
|
49
|
+
delegation: "required",
|
|
50
|
+
skills: "required",
|
|
51
|
+
memory: "load",
|
|
52
|
+
save: "always",
|
|
53
|
+
promptTask: "append-last",
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function normalizeBoard(value, tracker, now) {
|
|
58
|
+
const board = typeof value === "object" && value ? value : {};
|
|
59
|
+
const active = typeof board.active === "string" ? board.active : "";
|
|
60
|
+
return {
|
|
61
|
+
v: 1,
|
|
62
|
+
tracker,
|
|
63
|
+
active,
|
|
64
|
+
cols: {
|
|
65
|
+
backlog: normalizeStringArray(board.cols?.backlog),
|
|
66
|
+
ready: normalizeStringArray(board.cols?.ready),
|
|
67
|
+
doing: normalizeStringArray(board.cols?.doing).slice(0, 1),
|
|
68
|
+
review: normalizeStringArray(board.cols?.review),
|
|
69
|
+
blocked: normalizeStringArray(board.cols?.blocked),
|
|
70
|
+
done: normalizeStringArray(board.cols?.done),
|
|
71
|
+
},
|
|
72
|
+
updatedAt: now,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function normalizeState(value, board, now) {
|
|
76
|
+
const state = typeof value === "object" && value ? value : {};
|
|
77
|
+
return {
|
|
78
|
+
v: 1,
|
|
79
|
+
phase: typeof state.phase === "string" ? state.phase : "idle",
|
|
80
|
+
prompt: typeof state.prompt === "string" ? state.prompt : "",
|
|
81
|
+
ticket: typeof state.ticket === "string" ? state.ticket : board.active,
|
|
82
|
+
next: typeof state.next === "string" ? state.next : "analysis",
|
|
83
|
+
updatedAt: now,
|
|
84
|
+
notes: normalizeStringArray(state.notes),
|
|
85
|
+
sessions: typeof state.sessions === "object" && state.sessions ? state.sessions : {},
|
|
86
|
+
degraded: typeof state.degraded === "boolean" ? state.degraded : false,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
export function ensureProjectWorkspace(rootDir) {
|
|
90
|
+
const projectRoot = join(rootDir, ".opencode", "devloom", "project");
|
|
91
|
+
const devloomRoot = join(rootDir, ".opencode", "devloom");
|
|
92
|
+
const now = new Date().toISOString();
|
|
93
|
+
ensureDir(projectRoot);
|
|
94
|
+
ensureDir(join(devloomRoot, ".tmp"));
|
|
95
|
+
for (const dir of PROJECT_DIRS)
|
|
96
|
+
ensureDir(join(projectRoot, dir));
|
|
97
|
+
const configPath = join(projectRoot, "config.json");
|
|
98
|
+
const boardPath = join(projectRoot, "board.json");
|
|
99
|
+
const statePath = join(projectRoot, "state.json");
|
|
100
|
+
const readmePath = join(projectRoot, "README.md");
|
|
101
|
+
const config = normalizeConfig(readJson(configPath, {}));
|
|
102
|
+
const board = normalizeBoard(readJson(boardPath, {}), config.tracker, now);
|
|
103
|
+
const state = normalizeState(readJson(statePath, {}), board, now);
|
|
104
|
+
writeFileSync(readmePath, WORKSPACE_README);
|
|
105
|
+
writeFileSync(configPath, JSON.stringify(config));
|
|
106
|
+
writeFileSync(boardPath, JSON.stringify(board));
|
|
107
|
+
writeFileSync(statePath, JSON.stringify(state));
|
|
108
|
+
ensureLoopWorkspace(rootDir);
|
|
109
|
+
return {
|
|
110
|
+
config,
|
|
111
|
+
board,
|
|
112
|
+
state,
|
|
113
|
+
projectRoot,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=bootstrap.js.map
|