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,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: pr-babysitter
|
|
3
|
+
cadence: "*/15 * * * *"
|
|
4
|
+
level: L2
|
|
5
|
+
agents: [planner, developer, qa]
|
|
6
|
+
cost: 200000
|
|
7
|
+
description: "Watch long-running PRs and push them forward"
|
|
8
|
+
---
|
|
9
|
+
# PR Babysitter Pattern
|
|
10
|
+
|
|
11
|
+
## Purpose
|
|
12
|
+
Watch open PRs that have been idle for >2 hours and push them forward with fixes, rebases, or reviews.
|
|
13
|
+
|
|
14
|
+
## State Schema
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"prs": [
|
|
18
|
+
{
|
|
19
|
+
"number": number,
|
|
20
|
+
"status": "idle" | "in_progress" | "blocked" | "merged",
|
|
21
|
+
"lastActivity": "ISO string",
|
|
22
|
+
"agentAssigned": string,
|
|
23
|
+
"attempts": number
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Agent Chain
|
|
30
|
+
1. planner — analyze PR diff and comments, plan next action
|
|
31
|
+
2. developer — implement the planned change in a worktree
|
|
32
|
+
3. qa — verify the change, run tests
|
|
33
|
+
|
|
34
|
+
## Safety
|
|
35
|
+
- L2: all changes go through verifier review before commit
|
|
36
|
+
- Max 3 attempts per PR per tick
|
|
37
|
+
- Never force-push
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Loop Pattern Registry
|
|
2
|
+
# Each pattern defines: cadence, safety level, agent chain, token cost estimate
|
|
3
|
+
v: 1
|
|
4
|
+
patterns:
|
|
5
|
+
- id: daily-triage
|
|
6
|
+
cadence: "0 6 * * *"
|
|
7
|
+
level: L1
|
|
8
|
+
agents: [verifier, documenter]
|
|
9
|
+
cost_estimate: 50000
|
|
10
|
+
description: "Report repo health every morning"
|
|
11
|
+
- id: pr-babysitter
|
|
12
|
+
cadence: "*/15 * * * *"
|
|
13
|
+
level: L2
|
|
14
|
+
agents: [planner, developer, qa]
|
|
15
|
+
cost_estimate: 200000
|
|
16
|
+
description: "Watch long-running PRs and push them forward"
|
|
17
|
+
- id: ci-sweeper
|
|
18
|
+
cadence: "*/10 * * * *"
|
|
19
|
+
level: L2
|
|
20
|
+
agents: [developer, qa]
|
|
21
|
+
cost_estimate: 300000
|
|
22
|
+
description: "Detect and fix CI failures"
|
|
23
|
+
- id: dependency-sweeper
|
|
24
|
+
cadence: "0 */6 * * *"
|
|
25
|
+
level: L2
|
|
26
|
+
agents: [verifier, developer]
|
|
27
|
+
cost_estimate: 100000
|
|
28
|
+
description: "Patch-only dependency updates"
|
|
29
|
+
- id: changelog-drafter
|
|
30
|
+
cadence: "0 8 * * *"
|
|
31
|
+
level: L1
|
|
32
|
+
agents: [documenter]
|
|
33
|
+
cost_estimate: 30000
|
|
34
|
+
description: "Draft release notes from recent commits"
|
|
35
|
+
- id: post-merge-cleanup
|
|
36
|
+
cadence: "0 3 * * *"
|
|
37
|
+
level: L1
|
|
38
|
+
agents: [developer, qa]
|
|
39
|
+
cost_estimate: 40000
|
|
40
|
+
description: "Clean up stale branches and worktrees"
|
|
41
|
+
- id: issue-triage
|
|
42
|
+
cadence: "0 */2 * * *"
|
|
43
|
+
level: L1
|
|
44
|
+
agents: [planner]
|
|
45
|
+
cost_estimate: 60000
|
|
46
|
+
description: "Propose labels and priorities for new issues"
|
|
47
|
+
- id: design-audit
|
|
48
|
+
cadence: "on-demand"
|
|
49
|
+
level: L1
|
|
50
|
+
agents: [verifier]
|
|
51
|
+
cost_estimate: 150000
|
|
52
|
+
description: "Comprehensive UI/UX design audit with automated fix loop"
|
package/postinstall.mjs
CHANGED
|
@@ -1,62 +1,96 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import { copyFileSync, mkdirSync, existsSync, readdirSync, statSync } from "fs"
|
|
2
|
+
import { copyFileSync, mkdirSync, existsSync, readdirSync, statSync, accessSync, constants, readFileSync, writeFileSync } from "fs"
|
|
5
3
|
import { resolve, dirname, join, relative } from "path"
|
|
6
4
|
import { fileURLToPath } from "url"
|
|
7
5
|
import { homedir, platform } from "os"
|
|
6
|
+
import { getOpenCodeCacheDir, refreshOpenCodePluginCache, syncOpenCodePluginDependencies } from "./scripts/plugin-cache.mjs"
|
|
8
7
|
|
|
9
8
|
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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")
|
|
10
|
+
export function getConfigDir(_platform = platform(), _homedir = homedir()) {
|
|
11
|
+
if (_platform === "win32") {
|
|
12
|
+
return resolve(process.env.APPDATA ?? _homedir, "opencode")
|
|
19
13
|
}
|
|
14
|
+
// OpenCode resolves its global config from the XDG path on macOS too
|
|
15
|
+
// (~/.config/opencode), not ~/Library/Application Support.
|
|
20
16
|
return resolve(
|
|
21
|
-
process.env.XDG_CONFIG_HOME ?? join(
|
|
17
|
+
process.env.XDG_CONFIG_HOME ?? join(_homedir, ".config"),
|
|
22
18
|
"opencode"
|
|
23
19
|
)
|
|
24
20
|
}
|
|
25
21
|
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const AGENTS = [
|
|
32
|
-
"devloom-orchestrator",
|
|
33
|
-
"devloom-analyst",
|
|
34
|
-
"devloom-architect",
|
|
35
|
-
"devloom-developer",
|
|
36
|
-
"devloom-qa",
|
|
37
|
-
"devloom-documenter",
|
|
38
|
-
]
|
|
22
|
+
export function isPathSafe(basePath, resolvedPath) {
|
|
23
|
+
const rel = relative(basePath, resolvedPath)
|
|
24
|
+
return !rel.startsWith("..") && !rel.startsWith("/")
|
|
25
|
+
}
|
|
39
26
|
|
|
40
|
-
|
|
27
|
+
export function isDebug() {
|
|
28
|
+
return process.env.DEVLOOM_DEBUG === "1" || process.env.DEVLOOM_DEBUG === "true"
|
|
29
|
+
}
|
|
41
30
|
|
|
42
|
-
|
|
43
|
-
function ensureDir(dir) {
|
|
31
|
+
export function ensureDir(dir) {
|
|
44
32
|
if (!existsSync(dir)) {
|
|
45
33
|
mkdirSync(dir, { recursive: true })
|
|
34
|
+
if (isDebug()) console.log(`[debug] Created directory: ${dir}`)
|
|
46
35
|
console.log(` Created: ${dir}`)
|
|
47
36
|
}
|
|
48
37
|
}
|
|
49
38
|
|
|
39
|
+
// Register the DevLoom TUI plugin in tui.json's `plugin` array so OpenCode's
|
|
40
|
+
// TUI loads the rightbar sidebar slot (no directory auto-discovery for TUI
|
|
41
|
+
// plugins). Preserves every existing key (theme, keybinds, ...); dedupes the
|
|
42
|
+
// plugin entry; returns the merged object, or null when the file is corrupt
|
|
43
|
+
// (caller decides whether to warn).
|
|
44
|
+
export function ensureTuiPlugin(tuiPath, pluginName = "devloom") {
|
|
45
|
+
let tui = {}
|
|
46
|
+
if (existsSync(tuiPath)) {
|
|
47
|
+
try {
|
|
48
|
+
tui = JSON.parse(readFileSync(tuiPath, "utf8"))
|
|
49
|
+
} catch {
|
|
50
|
+
return null
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (typeof tui !== "object" || tui === null || Array.isArray(tui)) return null
|
|
54
|
+
if (!tui.$schema) tui.$schema = "https://opencode.ai/tui.json"
|
|
55
|
+
const plugins = Array.isArray(tui.plugin) ? tui.plugin.filter((spec) => spec !== pluginName) : []
|
|
56
|
+
plugins.push(pluginName)
|
|
57
|
+
tui.plugin = plugins
|
|
58
|
+
writeFileSync(tuiPath, JSON.stringify(tui, null, 2) + "\n")
|
|
59
|
+
return tui
|
|
60
|
+
}
|
|
61
|
+
|
|
50
62
|
let installFailed = false
|
|
51
63
|
|
|
52
|
-
function installFile(src, dest, label) {
|
|
64
|
+
export function installFile(src, dest, label, configDir, optional = false) {
|
|
65
|
+
const baseDir = configDir || getConfigDir()
|
|
53
66
|
if (!existsSync(src)) {
|
|
67
|
+
if (optional) {
|
|
68
|
+
console.log(` Skipped (not shipped) -- ${label}`)
|
|
69
|
+
return
|
|
70
|
+
}
|
|
54
71
|
console.error(` Source file not found: ${src}`)
|
|
55
72
|
installFailed = true
|
|
56
73
|
return
|
|
57
74
|
}
|
|
75
|
+
const destDir = dirname(dest)
|
|
76
|
+
if (!isPathSafe(baseDir, resolve(destDir))) {
|
|
77
|
+
console.error(` Path traversal blocked -- ${label}: ${dest}`)
|
|
78
|
+
installFailed = true
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
accessSync(destDir, constants.W_OK)
|
|
83
|
+
} catch {
|
|
84
|
+
console.error(` No write permission -- ${label}: ${destDir}`)
|
|
85
|
+
installFailed = true
|
|
86
|
+
return
|
|
87
|
+
}
|
|
58
88
|
try {
|
|
59
89
|
copyFileSync(src, dest)
|
|
90
|
+
if (isDebug()) {
|
|
91
|
+
const srcStat = statSync(src)
|
|
92
|
+
console.log(`[debug] Copied ${src} -> ${dest} (${srcStat.size} bytes)`)
|
|
93
|
+
}
|
|
60
94
|
console.log(` ${label}`)
|
|
61
95
|
} catch (err) {
|
|
62
96
|
console.error(` Failed -- ${label}: ${err.message}`)
|
|
@@ -64,7 +98,8 @@ function installFile(src, dest, label) {
|
|
|
64
98
|
}
|
|
65
99
|
}
|
|
66
100
|
|
|
67
|
-
function installDirRecursive(srcDir, destDir, labelPrefix) {
|
|
101
|
+
export function installDirRecursive(srcDir, destDir, labelPrefix, configDir) {
|
|
102
|
+
const baseDir = configDir || getConfigDir()
|
|
68
103
|
if (!existsSync(srcDir)) {
|
|
69
104
|
console.error(` Source dir not found: ${srcDir}`)
|
|
70
105
|
installFailed = true
|
|
@@ -77,61 +112,226 @@ function installDirRecursive(srcDir, destDir, labelPrefix) {
|
|
|
77
112
|
const destPath = join(destDir, entry)
|
|
78
113
|
const stat = statSync(srcPath)
|
|
79
114
|
if (stat.isDirectory()) {
|
|
80
|
-
installDirRecursive(srcPath, destPath, `${labelPrefix}/${entry}
|
|
115
|
+
installDirRecursive(srcPath, destPath, `${labelPrefix}/${entry}`, baseDir)
|
|
81
116
|
} else {
|
|
82
|
-
installFile(srcPath, destPath, `${labelPrefix}/${entry}
|
|
117
|
+
installFile(srcPath, destPath, `${labelPrefix}/${entry}`, baseDir)
|
|
83
118
|
}
|
|
84
119
|
}
|
|
85
120
|
}
|
|
86
121
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
122
|
+
const CONFIG_DIR = getConfigDir()
|
|
123
|
+
const AGENTS_DIR = resolve(CONFIG_DIR, "agents")
|
|
124
|
+
const COMMANDS_DIR = resolve(CONFIG_DIR, "commands")
|
|
125
|
+
const SKILLS_DIR = resolve(CONFIG_DIR, "skills")
|
|
126
|
+
const PROTOCOL_DIR = resolve(CONFIG_DIR, "protocol")
|
|
127
|
+
const AI_DIR = resolve(CONFIG_DIR, "devloom-ai")
|
|
128
|
+
const THEMES_DIR = resolve(CONFIG_DIR, "themes")
|
|
129
|
+
|
|
130
|
+
const AGENTS = [
|
|
131
|
+
"devloom-orchestrator",
|
|
132
|
+
"devloom-planner",
|
|
133
|
+
"devloom-developer",
|
|
134
|
+
"devloom-qa",
|
|
135
|
+
"devloom-verifier",
|
|
136
|
+
"devloom-security",
|
|
137
|
+
"devloom-documenter",
|
|
138
|
+
"devloom-vision",
|
|
139
|
+
"devloom-visual-director",
|
|
140
|
+
"devloom-visual-critic",
|
|
141
|
+
"devloom-planner-senior",
|
|
142
|
+
"devloom-developer-senior",
|
|
143
|
+
"devloom-security-senior",
|
|
144
|
+
"devloom-planner-flash",
|
|
145
|
+
"devloom-developer-flash",
|
|
146
|
+
"devloom-qa-flash",
|
|
147
|
+
"devloom-documenter-flash",
|
|
148
|
+
]
|
|
149
|
+
|
|
150
|
+
const COMMANDS = ["devloom", "devloom-status", "devloom-resume", "devloom-init", "devloom-save", "devloom-auto", "devloom-go", "devloom-go-economy", "devloom-go-flash", "devloom-deepseek", "devloom-free", "devloom-mimo", "devloom-deepseek-mimo", "devloom-plan", "devloom-context", "devloom-agents", "devloom-refresh"]
|
|
151
|
+
|
|
152
|
+
const SCRIPTS_DIR = resolve(CONFIG_DIR, "devloom-scripts")
|
|
93
153
|
|
|
94
|
-
|
|
95
|
-
|
|
154
|
+
const PROTOCOLS = [
|
|
155
|
+
"orchestrator-core",
|
|
156
|
+
"agent-contracts",
|
|
157
|
+
"artifact-system",
|
|
158
|
+
"verification-policy",
|
|
159
|
+
"project-system",
|
|
160
|
+
]
|
|
161
|
+
|
|
162
|
+
function main() {
|
|
163
|
+
console.log("\nDevLoom -- post-install\n")
|
|
164
|
+
console.log(` Config dir : ${CONFIG_DIR}`)
|
|
165
|
+
console.log(` Agents dir : ${AGENTS_DIR}`)
|
|
166
|
+
console.log(` Commands dir: ${COMMANDS_DIR}`)
|
|
167
|
+
console.log(` Skills dir : ${SKILLS_DIR}\n`)
|
|
168
|
+
console.log(` AI dir : ${AI_DIR}\n`)
|
|
169
|
+
|
|
170
|
+
if (isDebug()) console.log("[debug] Starting DevLoom post-install")
|
|
96
171
|
|
|
172
|
+
ensureDir(AGENTS_DIR)
|
|
173
|
+
ensureDir(COMMANDS_DIR)
|
|
97
174
|
|
|
98
|
-
console.log("Installing agents:")
|
|
99
|
-
for (const name of AGENTS) {
|
|
175
|
+
console.log("Installing agents:")
|
|
176
|
+
for (const name of AGENTS) {
|
|
177
|
+
installFile(
|
|
178
|
+
resolve(__dirname, "agents", `${name}.md`),
|
|
179
|
+
resolve(AGENTS_DIR, `${name}.md`),
|
|
180
|
+
`Agent: ${name}`
|
|
181
|
+
)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
console.log("\nInstalling commands:")
|
|
185
|
+
for (const name of COMMANDS) {
|
|
186
|
+
installFile(
|
|
187
|
+
resolve(__dirname, "commands", `${name}.md`),
|
|
188
|
+
resolve(COMMANDS_DIR, `${name}.md`),
|
|
189
|
+
`Command: /${name}`
|
|
190
|
+
)
|
|
191
|
+
}
|
|
100
192
|
installFile(
|
|
101
|
-
resolve(__dirname, "
|
|
102
|
-
resolve(
|
|
103
|
-
|
|
193
|
+
resolve(__dirname, "scripts", "profile.mjs"),
|
|
194
|
+
resolve(COMMANDS_DIR, "profile.mjs"),
|
|
195
|
+
"Profile manager"
|
|
104
196
|
)
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
console.log("\nInstalling commands:")
|
|
108
|
-
for (const name of COMMANDS) {
|
|
109
197
|
installFile(
|
|
110
|
-
resolve(__dirname, "
|
|
111
|
-
resolve(COMMANDS_DIR,
|
|
112
|
-
|
|
198
|
+
resolve(__dirname, "scripts", "model-capabilities.mjs"),
|
|
199
|
+
resolve(COMMANDS_DIR, "model-capabilities.mjs"),
|
|
200
|
+
"Model capabilities helper"
|
|
113
201
|
)
|
|
114
|
-
|
|
202
|
+
installFile(
|
|
203
|
+
resolve(__dirname, "scripts", "briefing.mjs"),
|
|
204
|
+
resolve(COMMANDS_DIR, "briefing.mjs"),
|
|
205
|
+
"Briefing change tracker"
|
|
206
|
+
)
|
|
207
|
+
installFile(
|
|
208
|
+
resolve(__dirname, "scripts", "plugin-cache.mjs"),
|
|
209
|
+
resolve(COMMANDS_DIR, "plugin-cache.mjs"),
|
|
210
|
+
"Plugin cache helper"
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
console.log("\nInstalling skills:")
|
|
214
|
+
installDirRecursive(
|
|
215
|
+
resolve(__dirname, "skills"),
|
|
216
|
+
SKILLS_DIR,
|
|
217
|
+
"Skill"
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
console.log("\nInstalling AI DSL:")
|
|
221
|
+
installDirRecursive(
|
|
222
|
+
resolve(__dirname, ".ai"),
|
|
223
|
+
AI_DIR,
|
|
224
|
+
"AI"
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
console.log("\nInstalling profile manager scripts:")
|
|
228
|
+
installDirRecursive(
|
|
229
|
+
resolve(__dirname, "scripts"),
|
|
230
|
+
SCRIPTS_DIR,
|
|
231
|
+
"Script"
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
console.log("\nInstalling protocol modules:")
|
|
235
|
+
ensureDir(PROTOCOL_DIR)
|
|
236
|
+
for (const name of PROTOCOLS) {
|
|
237
|
+
installFile(
|
|
238
|
+
resolve(__dirname, "protocol", `${name}.md`),
|
|
239
|
+
resolve(PROTOCOL_DIR, `${name}.md`),
|
|
240
|
+
`Protocol: ${name}`
|
|
241
|
+
)
|
|
242
|
+
}
|
|
115
243
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
"
|
|
121
|
-
|
|
244
|
+
// Install theme
|
|
245
|
+
console.log("\nInstalling DevLoom Night Owl theme:")
|
|
246
|
+
ensureDir(THEMES_DIR)
|
|
247
|
+
const themeSrc = resolve(__dirname, ".opencode", "themes", "devloom-night-owl.json")
|
|
248
|
+
const themeDest = resolve(THEMES_DIR, "devloom-night-owl.json")
|
|
249
|
+
// ponytail: cosmetic asset — a missing theme must never fail the install
|
|
250
|
+
installFile(themeSrc, themeDest, "Theme: DevLoom Night Owl", CONFIG_DIR, true)
|
|
122
251
|
|
|
123
|
-
|
|
124
|
-
|
|
252
|
+
// Register the TUI plugin in tui.json (the right sidebar renders only plugin
|
|
253
|
+
// slots, so this is what makes the DevLoom agents visible in the rightbar)
|
|
254
|
+
// and activate the theme when no theme is set.
|
|
255
|
+
const tuiPath = resolve(CONFIG_DIR, "tui.json")
|
|
256
|
+
const tui = ensureTuiPlugin(tuiPath)
|
|
257
|
+
if (tui === null) {
|
|
258
|
+
console.log(" Skipping tui.json update (parse error)")
|
|
259
|
+
} else {
|
|
260
|
+
if (!tui.theme) {
|
|
261
|
+
tui.theme = "devloom-night-owl"
|
|
262
|
+
writeFileSync(tuiPath, JSON.stringify(tui, null, 2) + "\n")
|
|
263
|
+
console.log(" Theme activated in tui.json (change via /theme)")
|
|
264
|
+
} else {
|
|
265
|
+
console.log(` Theme already set: ${tui.theme} (change via /theme)`)
|
|
266
|
+
}
|
|
267
|
+
console.log(" DevLoom TUI plugin registered in tui.json (agents render in the right sidebar)")
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Refresh the OpenCode plugin cache so the plugin code loaded by the TUI
|
|
271
|
+
// actually contains the config hook that injects DevLoom agents + profile
|
|
272
|
+
// into the sidebar. Best-effort only: OpenCode installs plugins with
|
|
273
|
+
// ignoreScripts, so this copy is the only way the cache picks up new code.
|
|
274
|
+
// Cosmetic failures here must never fail the npm install.
|
|
275
|
+
console.log("\nRefreshing OpenCode plugin cache:")
|
|
276
|
+
const cacheDir = getOpenCodeCacheDir()
|
|
277
|
+
const refresh = refreshOpenCodePluginCache(__dirname, cacheDir)
|
|
278
|
+
if (refresh.build && refresh.build.built) {
|
|
279
|
+
console.log(" Rebuilt dist/ before refreshing the plugin cache.")
|
|
280
|
+
}
|
|
281
|
+
if (refresh.build && refresh.build.errors.length > 0) {
|
|
282
|
+
console.log(` Warning (not fatal): dist rebuild failed — ${refresh.build.errors[0]}`)
|
|
283
|
+
}
|
|
284
|
+
for (const entry of refresh.refreshed) {
|
|
285
|
+
console.log(` Refreshed plugin cache: ${entry} -> fresh DevLoom code with the sidebar config hook`)
|
|
286
|
+
}
|
|
287
|
+
for (const entry of refresh.skipped) {
|
|
288
|
+
console.log(` Skipped: no OpenCode plugin cache entry found at ${entry}`)
|
|
289
|
+
}
|
|
290
|
+
for (const error of refresh.errors) {
|
|
291
|
+
console.log(` Warning (not fatal): plugin cache refresh failed for ${error}`)
|
|
292
|
+
}
|
|
293
|
+
if (refresh.skipped.length > 0 && refresh.refreshed.length === 0) {
|
|
294
|
+
console.log("")
|
|
295
|
+
console.log(" DevLoom is not yet registered as an OpenCode plugin.")
|
|
296
|
+
console.log(" Install it once with: opencode plugin devloom --global")
|
|
297
|
+
console.log(" then re-run this installer (or /devloom-refresh) to sync the plugin code.")
|
|
298
|
+
} else if (refresh.errors.length > 0) {
|
|
299
|
+
console.log(" The plugin cache could not be fully refreshed — run /devloom-refresh to retry.")
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
console.log("\nSyncing plugin cache dependencies (TUI sidebar plugin):")
|
|
303
|
+
const deps = syncOpenCodePluginDependencies(__dirname, cacheDir)
|
|
304
|
+
for (const entry of deps.synced) {
|
|
305
|
+
console.log(` Synced runtime deps: ${entry} (right-sidebar TUI plugin ready)`)
|
|
306
|
+
}
|
|
307
|
+
for (const entry of deps.skipped) {
|
|
308
|
+
console.log(` Skipped: no OpenCode plugin cache entry found at ${entry}`)
|
|
309
|
+
}
|
|
310
|
+
for (const error of deps.errors) {
|
|
311
|
+
console.log(` Warning (not fatal): dependency sync failed for ${error}`)
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (!installFailed) {
|
|
315
|
+
console.log(`
|
|
125
316
|
DevLoom installed successfully!
|
|
126
317
|
|
|
127
318
|
Start weaving:
|
|
128
319
|
/devloom Build a REST API for user management with JWT auth
|
|
129
320
|
/devloom-status
|
|
130
321
|
|
|
322
|
+
Protocol modules available at ~/.config/opencode/protocol/
|
|
323
|
+
|
|
324
|
+
Theme: DevLoom Night Owl active (change via /theme or edit tui.json)
|
|
325
|
+
|
|
131
326
|
Debug mode:
|
|
132
327
|
DEVLOOM_DEBUG=1 opencode @devloom-orchestrator
|
|
133
328
|
`)
|
|
134
|
-
} else {
|
|
135
|
-
|
|
136
|
-
|
|
329
|
+
} else {
|
|
330
|
+
console.error("\nSome files could not be installed. See errors above.")
|
|
331
|
+
process.exit(1)
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (process.argv[1] && fileURLToPath(import.meta.url) === resolve(process.argv[1])) {
|
|
336
|
+
main()
|
|
137
337
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# DevLoom Project Standard
|
|
2
|
+
|
|
3
|
+
ROOT: `.opencode/devloom/project/`
|
|
4
|
+
|
|
5
|
+
GOALS:
|
|
6
|
+
- EN artifacts
|
|
7
|
+
- JSONM for AI-only state
|
|
8
|
+
- SingleActive queue
|
|
9
|
+
- Persist pending work
|
|
10
|
+
- Load memory every prompt
|
|
11
|
+
- Use relevant skills every prompt
|
|
12
|
+
- Append each prompt as the last task/todo
|
|
13
|
+
- Keep tickets/todos/plan in sync
|
|
14
|
+
- Tests+Regr required
|
|
15
|
+
- Local tracker default
|
|
16
|
+
- GitHub Project mirror only with explicit authorization
|
|
17
|
+
|
|
18
|
+
TREE:
|
|
19
|
+
- README.md
|
|
20
|
+
- config.json
|
|
21
|
+
- board.json
|
|
22
|
+
- state.json
|
|
23
|
+
- stories/
|
|
24
|
+
- tasks/
|
|
25
|
+
- bugs/
|
|
26
|
+
- decisions/
|
|
27
|
+
- reports/
|
|
28
|
+
|
|
29
|
+
JSON_KEYS: v|id|type|title|status|ac|deps|files|tests|cols|ts
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Agent Contracts
|
|
2
|
+
|
|
3
|
+
LOAD: ~/.config/opencode/devloom-ai/core.dsl|~/.config/opencode/devloom-ai/workflow.dsl|~/.config/opencode/devloom-ai/verify.dsl
|
|
4
|
+
|
|
5
|
+
FMT:
|
|
6
|
+
`Agent|Purpose|In|Out|Rules|Signal`
|
|
7
|
+
|
|
8
|
+
AGENTS (7):
|
|
9
|
+
- Orchestrator|triage+route+queue+inline recovery|prompt|state+handoffs|EN|SingleActive|PersistAll|LoadMemory|UseSkills|AppendPromptTask|MaintainPlan|NoSelfDelegate|DEVLOOM_DONE
|
|
10
|
+
- Planner|prompt->REQ and/or PLAN+tickets|prompt/REQ|REQ|PLAN+tasks/*|NoImpl|CleanArch|LatestStableCheck|OfficialDocsFirst|TestsInPlan|ANALYST_COMPLETE/ARCHITECT_COMPLETE/PLANNER_COMPLETE
|
|
11
|
+
- Developer|implement one ticket OR fix one defect|ticket/defect+PLAN|code+tests|TDDReq|RootCauseFix|NoWorkaround|SOLID|NoScopeCreep|MinChange|DEVELOPER_COMPLETE/REPAIR_COMPLETE
|
|
12
|
+
- QA|verify+review+regression|ticket+diff|results|Lint|Tests|CodeReview|Regr|QA_PASS/QA_FAIL/REGRESSION_PASS/REGRESSION_FAIL
|
|
13
|
+
- Verifier|runtime app verification by scope|scope+app url/cmd|defects/report|UX_BAR|NoGuess|Forensic|VERIFIER_COMPLETE
|
|
14
|
+
- Security|review CRUD/exposure surfaces|endpoint+dto+component api|security report|SEC checks|Forensic|SECURITY_REVIEW_COMPLETE
|
|
15
|
+
- Documenter|update docs+state|done tasks|docs+state|OnlyImplemented|EN|DOCUMENTER_COMPLETE
|
|
16
|
+
|
|
17
|
+
SHARED:
|
|
18
|
+
- EN
|
|
19
|
+
- DeltaCommOnly
|
|
20
|
+
- FinalResponse<=40lines: status signal + deltas + artifact paths; full detail goes to .opencode/devloom/ artifacts, never chat
|
|
21
|
+
- JSONM for AI-only state
|
|
22
|
+
- Update BOARD+PSTATE on ticket state change
|
|
23
|
+
- Append each prompt to project/tasks/TODO.md before execution routing
|
|
24
|
+
- Keep tasks/todos/plan aligned with the active ticket
|
|
25
|
+
- DevLoom subagents are callable by the orchestrator and may also be invoked manually by the user
|
|
26
|
+
- OfficialDocsFirst for stack-specific decisions
|
|
27
|
+
- LatestStableCheck before stack-specific planning/coding
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Artifact System
|
|
2
|
+
|
|
3
|
+
LOAD: ~/.config/opencode/devloom-ai/core.dsl
|
|
4
|
+
|
|
5
|
+
REG:
|
|
6
|
+
- REG=.opencode/devloom/registry.json
|
|
7
|
+
- BOARD=.opencode/devloom/project/board.json
|
|
8
|
+
- PSTATE=.opencode/devloom/project/state.json
|
|
9
|
+
|
|
10
|
+
TYPES: feature|defect|requirement|plan|exploration|verification|journey|decision
|
|
11
|
+
|
|
12
|
+
RULES:
|
|
13
|
+
- use ids, not raw dumps
|
|
14
|
+
- send title|files|ac|signal only
|
|
15
|
+
- summaries <=100 tokens when possible
|
|
16
|
+
- use relative paths
|
|
17
|
+
- persist active work in BOARD
|
|
18
|
+
- append each prompt to project/tasks/TODO.md as the last todo item
|
|
19
|
+
- keep task, todo, and plan artifacts aligned on every state change
|
|
20
|
+
- JSONM for AI-only files
|
|
21
|
+
|
|
22
|
+
JSONM_EX:
|
|
23
|
+
```json
|
|
24
|
+
{"v":1,"id":"TASK-003","type":"task","status":"doing","ac":["auth ok"],"files":["src/auth.ts"],"tests":["npm test -- auth"],"ts":"2026-05-24T19:00:00Z"}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
LAYERS:
|
|
28
|
+
- L1 project summary
|
|
29
|
+
- L2 arch summary
|
|
30
|
+
- L3 module summaries
|
|
31
|
+
- L4 source files on demand only
|
|
32
|
+
|
|
33
|
+
SIG:
|
|
34
|
+
- ANALYST_COMPLETE
|
|
35
|
+
- ARCHITECT_COMPLETE
|
|
36
|
+
- DEVELOPER_COMPLETE
|
|
37
|
+
- QA_PASS
|
|
38
|
+
- QA_FAIL
|
|
39
|
+
- EXPLORER_COMPLETE
|
|
40
|
+
- ROUTE_VERIFIER_COMPLETE
|
|
41
|
+
- FORM_VERIFIER_COMPLETE
|
|
42
|
+
- A11Y_VERIFIER_COMPLETE
|
|
43
|
+
- API_VERIFIER_COMPLETE
|
|
44
|
+
- JOURNEY_AGENT_COMPLETE
|
|
45
|
+
- RCA_COMPLETE
|
|
46
|
+
- REPAIR_COMPLETE
|
|
47
|
+
- REGRESSION_PASS
|
|
48
|
+
- REGRESSION_FAIL
|
|
49
|
+
- RECOVERY_DONE
|
|
50
|
+
- DOCUMENTER_COMPLETE
|
|
51
|
+
- DEVLOOM_RESUME
|
|
52
|
+
- DEVLOOM_HANG_DETECTED
|
|
53
|
+
- DEVLOOM_DONE
|