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
package/dist/loop.js
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { DEFAULT_CONSTRAINTS } from "./constraints.js";
|
|
4
|
+
const DEFAULT_CONFIG = { pattern: "", cadence: "0 0 * * *", level: "L1", paused: false, mode: "recurring" };
|
|
5
|
+
function nextMidnightISO() {
|
|
6
|
+
const now = new Date();
|
|
7
|
+
const mid = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 0, 0, 0, 0);
|
|
8
|
+
return mid.toISOString();
|
|
9
|
+
}
|
|
10
|
+
function defaultBudget() {
|
|
11
|
+
return { dailyLimit: 500000, spent: 0, resetAt: nextMidnightISO() };
|
|
12
|
+
}
|
|
13
|
+
function readJson(path, fallback) {
|
|
14
|
+
try {
|
|
15
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return fallback;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function writeJson(path, data) {
|
|
22
|
+
const dir = dirname(path);
|
|
23
|
+
if (!existsSync(dir))
|
|
24
|
+
mkdirSync(dir, { recursive: true });
|
|
25
|
+
writeFileSync(path, JSON.stringify(data, null, 2) + "\n");
|
|
26
|
+
}
|
|
27
|
+
export function loopWorkspaceDir(rootDir) {
|
|
28
|
+
return join(rootDir, ".opencode", "devloom", "loop");
|
|
29
|
+
}
|
|
30
|
+
export function readLoopConfig(rootDir) {
|
|
31
|
+
const path = join(loopWorkspaceDir(rootDir), "loop-config.json");
|
|
32
|
+
return readJson(path, { ...DEFAULT_CONFIG });
|
|
33
|
+
}
|
|
34
|
+
export function writeLoopConfig(rootDir, config) {
|
|
35
|
+
const path = join(loopWorkspaceDir(rootDir), "loop-config.json");
|
|
36
|
+
writeJson(path, config);
|
|
37
|
+
}
|
|
38
|
+
export function readRunLog(rootDir, limit) {
|
|
39
|
+
const path = join(loopWorkspaceDir(rootDir), "run-log.json");
|
|
40
|
+
const entries = readJson(path, []);
|
|
41
|
+
if (limit && limit > 0) {
|
|
42
|
+
return entries.slice(-limit);
|
|
43
|
+
}
|
|
44
|
+
return entries;
|
|
45
|
+
}
|
|
46
|
+
/** The loop runs on a cron cadence — cap the log so it cannot grow forever. */
|
|
47
|
+
export const RUN_LOG_MAX_ENTRIES = 200;
|
|
48
|
+
export function appendRunLog(rootDir, entry) {
|
|
49
|
+
const path = join(loopWorkspaceDir(rootDir), "run-log.json");
|
|
50
|
+
const entries = readJson(path, []);
|
|
51
|
+
entries.push(entry);
|
|
52
|
+
writeJson(path, entries.slice(-RUN_LOG_MAX_ENTRIES));
|
|
53
|
+
}
|
|
54
|
+
export function readBudget(rootDir) {
|
|
55
|
+
const path = join(loopWorkspaceDir(rootDir), "budget.json");
|
|
56
|
+
return readJson(path, defaultBudget());
|
|
57
|
+
}
|
|
58
|
+
export function writeBudget(rootDir, budget) {
|
|
59
|
+
const path = join(loopWorkspaceDir(rootDir), "budget.json");
|
|
60
|
+
writeJson(path, budget);
|
|
61
|
+
}
|
|
62
|
+
export function checkBudget(rootDir) {
|
|
63
|
+
const budget = readBudget(rootDir);
|
|
64
|
+
const now = new Date();
|
|
65
|
+
const resetTime = new Date(budget.resetAt);
|
|
66
|
+
let effective;
|
|
67
|
+
if (now >= resetTime) {
|
|
68
|
+
effective = defaultBudget();
|
|
69
|
+
writeBudget(rootDir, effective);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
effective = budget;
|
|
73
|
+
}
|
|
74
|
+
const remaining = Math.max(0, effective.dailyLimit - effective.spent);
|
|
75
|
+
return { allowed: remaining > 0, remaining, resetAt: effective.resetAt };
|
|
76
|
+
}
|
|
77
|
+
export function recordSpend(rootDir, tokens) {
|
|
78
|
+
const budget = readBudget(rootDir);
|
|
79
|
+
const now = new Date();
|
|
80
|
+
const resetTime = new Date(budget.resetAt);
|
|
81
|
+
let effective;
|
|
82
|
+
if (now >= resetTime) {
|
|
83
|
+
effective = { ...defaultBudget(), spent: tokens };
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
effective = { ...budget, spent: budget.spent + tokens };
|
|
87
|
+
}
|
|
88
|
+
writeBudget(rootDir, effective);
|
|
89
|
+
}
|
|
90
|
+
export function shouldPause(rootDir) {
|
|
91
|
+
const check = checkBudget(rootDir);
|
|
92
|
+
if (!check.allowed) {
|
|
93
|
+
const config = readLoopConfig(rootDir);
|
|
94
|
+
if (!config.paused) {
|
|
95
|
+
config.paused = true;
|
|
96
|
+
writeLoopConfig(rootDir, config);
|
|
97
|
+
}
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
export function ensureLoopWorkspace(rootDir) {
|
|
103
|
+
const dir = loopWorkspaceDir(rootDir);
|
|
104
|
+
if (!existsSync(dir))
|
|
105
|
+
mkdirSync(dir, { recursive: true });
|
|
106
|
+
const configPath = join(dir, "loop-config.json");
|
|
107
|
+
if (!existsSync(configPath))
|
|
108
|
+
writeJson(configPath, { ...DEFAULT_CONFIG });
|
|
109
|
+
const runLogPath = join(dir, "run-log.json");
|
|
110
|
+
if (!existsSync(runLogPath))
|
|
111
|
+
writeJson(runLogPath, []);
|
|
112
|
+
const budgetPath = join(dir, "budget.json");
|
|
113
|
+
if (!existsSync(budgetPath))
|
|
114
|
+
writeJson(budgetPath, defaultBudget());
|
|
115
|
+
const constraintsPath = join(dir, "loop-constraints.md");
|
|
116
|
+
if (!existsSync(constraintsPath))
|
|
117
|
+
writeFileSync(constraintsPath, DEFAULT_CONSTRAINTS);
|
|
118
|
+
}
|
|
119
|
+
export function progressFilePath(rootDir) {
|
|
120
|
+
return join(loopWorkspaceDir(rootDir), "progress.json");
|
|
121
|
+
}
|
|
122
|
+
export function readProgress(rootDir) {
|
|
123
|
+
return readJson(progressFilePath(rootDir), null);
|
|
124
|
+
}
|
|
125
|
+
export function writeProgress(rootDir, progress) {
|
|
126
|
+
writeJson(progressFilePath(rootDir), progress);
|
|
127
|
+
}
|
|
128
|
+
export function initUntilDoneProgress(items, condition) {
|
|
129
|
+
const done = items.filter((i) => i.status === "done" || i.status === "verified").length;
|
|
130
|
+
const verified = items.filter((i) => i.status === "verified").length;
|
|
131
|
+
return { items, completionCondition: condition, total: items.length, done, verified };
|
|
132
|
+
}
|
|
133
|
+
export function updateProgressItem(progress, id, status) {
|
|
134
|
+
const item = progress.items.find((i) => i.id === id);
|
|
135
|
+
if (item)
|
|
136
|
+
item.status = status;
|
|
137
|
+
progress.done = progress.items.filter((i) => i.status === "done" || i.status === "verified").length;
|
|
138
|
+
progress.verified = progress.items.filter((i) => i.status === "verified").length;
|
|
139
|
+
return progress;
|
|
140
|
+
}
|
|
141
|
+
export function checkCompletionCondition(progress) {
|
|
142
|
+
return progress.items.every((i) => i.status === "verified");
|
|
143
|
+
}
|
|
144
|
+
export function progressByCategory(progress) {
|
|
145
|
+
const counts = {};
|
|
146
|
+
for (const item of progress.items) {
|
|
147
|
+
const cat = item.category || "un categorized";
|
|
148
|
+
counts[cat] = (counts[cat] || 0) + 1;
|
|
149
|
+
}
|
|
150
|
+
return counts;
|
|
151
|
+
}
|
|
152
|
+
export function readLoopStateSummary(rootDir) {
|
|
153
|
+
const config = readLoopConfig(rootDir);
|
|
154
|
+
if (!config.pattern)
|
|
155
|
+
return "loop=inactive";
|
|
156
|
+
const entries = readRunLog(rootDir, 1);
|
|
157
|
+
const lastRun = entries.length > 0 ? entries[entries.length - 1].timestamp : "";
|
|
158
|
+
const mode = config.mode === "until-done" ? " until-done" : "";
|
|
159
|
+
const progress = config.mode === "until-done" && config.progress
|
|
160
|
+
? ` verified=${config.progress.verified}/${config.progress.total}`
|
|
161
|
+
: "";
|
|
162
|
+
return `loop=${config.pattern}${mode} lastRun=${lastRun || "never"} paused=${config.paused}${progress}`;
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=loop.js.map
|
package/dist/loop.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop.js","sourceRoot":"","sources":["../src/loop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC5E,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AA8CtD,MAAM,cAAc,GAAe,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,CAAA;AAEvH,SAAS,eAAe;IACtB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAA;IACtB,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,GAAG,CAAC,QAAQ,EAAE,EAAE,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;IACtF,OAAO,GAAG,CAAC,WAAW,EAAE,CAAA;AAC1B,CAAC;AAED,SAAS,aAAa;IACpB,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,eAAe,EAAE,EAAE,CAAA;AACrE,CAAC;AAED,SAAS,QAAQ,CAAI,IAAY,EAAE,QAAW;IAC5C,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAM,CAAA;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,QAAQ,CAAA;IACjB,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,IAAY,EAAE,IAAa;IAC5C,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACzB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACzD,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAA;AAC3D,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,OAAO,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,CAAC,CAAA;AACtD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,kBAAkB,CAAC,CAAA;IAChE,OAAO,QAAQ,CAAC,IAAI,EAAE,EAAE,GAAG,cAAc,EAAE,CAAC,CAAA;AAC9C,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAe,EAAE,MAAkB;IACjE,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,kBAAkB,CAAC,CAAA;IAChE,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;AACzB,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,OAAe,EAAE,KAAc;IACxD,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,cAAc,CAAC,CAAA;IAC5D,MAAM,OAAO,GAAG,QAAQ,CAAgB,IAAI,EAAE,EAAE,CAAC,CAAA;IACjD,IAAI,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAA;IAC9B,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,+EAA+E;AAC/E,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAG,CAAA;AAEtC,MAAM,UAAU,YAAY,CAAC,OAAe,EAAE,KAAkB;IAC9D,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,cAAc,CAAC,CAAA;IAC5D,MAAM,OAAO,GAAG,QAAQ,CAAgB,IAAI,EAAE,EAAE,CAAC,CAAA;IACjD,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACnB,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAA;AACtD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,OAAe;IACxC,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC,CAAA;IAC3D,OAAO,QAAQ,CAAC,IAAI,EAAE,aAAa,EAAE,CAAC,CAAA;AACxC,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,OAAe,EAAE,MAAc;IACzD,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC,CAAA;IAC3D,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;AACzB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,CAAA;IAClC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAA;IACtB,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IAC1C,IAAI,SAAiB,CAAA;IACrB,IAAI,GAAG,IAAI,SAAS,EAAE,CAAC;QACrB,SAAS,GAAG,aAAa,EAAE,CAAA;QAC3B,WAAW,CAAC,OAAO,EAAE,SAAS,CAAC,CAAA;IACjC,CAAC;SAAM,CAAC;QACN,SAAS,GAAG,MAAM,CAAA;IACpB,CAAC;IACD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,UAAU,GAAG,SAAS,CAAC,KAAK,CAAC,CAAA;IACrE,OAAO,EAAE,OAAO,EAAE,SAAS,GAAG,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,CAAC,OAAO,EAAE,CAAA;AAC1E,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,OAAe,EAAE,MAAc;IACzD,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,CAAA;IAClC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAA;IACtB,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IAC1C,IAAI,SAAiB,CAAA;IACrB,IAAI,GAAG,IAAI,SAAS,EAAE,CAAC;QACrB,SAAS,GAAG,EAAE,GAAG,aAAa,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAA;IACnD,CAAC;SAAM,CAAC;QACN,SAAS,GAAG,EAAE,GAAG,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,GAAG,MAAM,EAAE,CAAA;IACzD,CAAC;IACD,WAAW,CAAC,OAAO,EAAE,SAAS,CAAC,CAAA;AACjC,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,MAAM,KAAK,GAAG,WAAW,CAAC,OAAO,CAAC,CAAA;IAClC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;QACnB,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;QACtC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACnB,MAAM,CAAC,MAAM,GAAG,IAAI,CAAA;YACpB,eAAe,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;QAClC,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,OAAe;IACjD,MAAM,GAAG,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAA;IACrC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAEzD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAA;IAChD,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,SAAS,CAAC,UAAU,EAAE,EAAE,GAAG,cAAc,EAAE,CAAC,CAAA;IAEzE,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAA;IAC5C,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,SAAS,CAAC,UAAU,EAAE,EAAE,CAAC,CAAA;IAEtD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,CAAA;IAC3C,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,SAAS,CAAC,UAAU,EAAE,aAAa,EAAE,CAAC,CAAA;IAEnE,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAA;IACxD,IAAI,CAAC,UAAU,CAAC,eAAe,CAAC;QAAE,aAAa,CAAC,eAAe,EAAE,mBAAmB,CAAC,CAAA;AACvF,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,OAAO,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,eAAe,CAAC,CAAA;AACzD,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,OAAO,QAAQ,CAA2B,gBAAgB,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,CAAA;AAC5E,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAe,EAAE,QAA2B;IACxE,SAAS,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAA;AAChD,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,KAAsB,EAAE,SAAiB;IAC7E,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,MAAM,CAAA;IACvF,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,MAAM,CAAA;IACpE,OAAO,EAAE,KAAK,EAAE,mBAAmB,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAA;AACvF,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,QAA2B,EAAE,EAAU,EAAE,MAA+B;IACzG,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;IACpD,IAAI,IAAI;QAAE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;IAC9B,QAAQ,CAAC,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,MAAM,CAAA;IACnG,QAAQ,CAAC,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,MAAM,CAAA;IAChF,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,QAA2B;IAClE,OAAO,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,CAAA;AAC7D,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,QAA2B;IAC5D,MAAM,MAAM,GAA2B,EAAE,CAAA;IACzC,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;QAClC,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,IAAI,gBAAgB,CAAA;QAC7C,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAA;IACtC,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,OAAe;IAClD,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;IACtC,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,OAAO,eAAe,CAAA;IAC3C,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;IACtC,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAA;IAC/E,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAA;IAC9D,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,KAAK,YAAY,IAAI,MAAM,CAAC,QAAQ;QAC9D,CAAC,CAAC,aAAa,MAAM,CAAC,QAAQ,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE;QAClE,CAAC,CAAC,EAAE,CAAA;IACN,OAAO,QAAQ,MAAM,CAAC,OAAO,GAAG,IAAI,YAAY,OAAO,IAAI,OAAO,WAAW,MAAM,CAAC,MAAM,GAAG,QAAQ,EAAE,CAAA;AACzG,CAAC"}
|
package/dist/plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AA0B7D,iBAAS,oBAAoB,CAAC,IAAI,EAAE,WAAW,GAAG,KAAK,CA4HtD;AAED,OAAO,EAAE,oBAAoB,EAAE,CAAA"}
|
package/dist/plugin.js
CHANGED
|
@@ -1,7 +1,61 @@
|
|
|
1
1
|
import { env } from "node:process";
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { ensureProjectWorkspace } from "./bootstrap.js";
|
|
5
|
+
import { injectDevloomAgents } from "./agents.js";
|
|
6
|
+
import { autoGenerateContextIfMissing, ensureAtlas } from "./context.js";
|
|
7
|
+
import { ensureLoopWorkspace } from "./loop.js";
|
|
8
|
+
import { ORCHESTRATOR_AGENT, buildGuardText, clampToolOutput, isBlockedOrchestratorCall, readStateSummary, } from "./guard.js";
|
|
2
9
|
const PLUGIN_NAME = "devloom";
|
|
10
|
+
const MAX_TRACKED_SESSIONS = 100;
|
|
11
|
+
const COMPACTION_CONTEXT = [
|
|
12
|
+
"DevLoom is active in this project. The summary MUST preserve:",
|
|
13
|
+
'(1) routing rule — all code work is delegated via task(subagent:"devloom-orchestrator");',
|
|
14
|
+
"(2) current pipeline state from .opencode/devloom/project/state.json and board.json (phase, active ticket, next step);",
|
|
15
|
+
"(3) pending pipeline phases and open defects;",
|
|
16
|
+
"(4) active git worktrees under .devloom-worktrees/ (branches, agents, merge status) — never lose track of parallel agent work;",
|
|
17
|
+
"(5) project context at .opencode/devloom/context/ — tech stack, conventions, security, examples, and architecture atlas (auto-generated, pattern-aware code generation).",
|
|
18
|
+
"(6) loop engineering state at .opencode/devloom/loop/ — pattern, cadence, level, budget, run history.",
|
|
19
|
+
].join(" ");
|
|
3
20
|
function createLifecycleHooks(_ctx) {
|
|
4
21
|
const debug = env.DEVLOOM_DEBUG === "1";
|
|
22
|
+
const rootDir = typeof _ctx.directory === "string" ? _ctx.directory : "";
|
|
23
|
+
if (rootDir.length > 0 && existsSync(join(rootDir, ".opencode", "devloom"))) {
|
|
24
|
+
ensureProjectWorkspace(rootDir);
|
|
25
|
+
autoGenerateContextIfMissing(rootDir);
|
|
26
|
+
ensureAtlas(rootDir);
|
|
27
|
+
ensureLoopWorkspace(rootDir);
|
|
28
|
+
}
|
|
29
|
+
const agentBySession = new Map();
|
|
30
|
+
const sessionsFile = rootDir ? join(rootDir, ".opencode", "devloom", ".sessions.json") : "";
|
|
31
|
+
// Restore persisted session→agent map (survives plugin reloads)
|
|
32
|
+
if (sessionsFile && existsSync(sessionsFile)) {
|
|
33
|
+
try {
|
|
34
|
+
const data = JSON.parse(readFileSync(sessionsFile, "utf8"));
|
|
35
|
+
for (const [sid, agent] of Object.entries(data))
|
|
36
|
+
agentBySession.set(sid, agent);
|
|
37
|
+
}
|
|
38
|
+
catch { /* ignore corrupt file */ }
|
|
39
|
+
}
|
|
40
|
+
// Insertion-ordered Map: evicting from the front drops the oldest sessions.
|
|
41
|
+
const trimSessions = () => {
|
|
42
|
+
while (agentBySession.size > MAX_TRACKED_SESSIONS) {
|
|
43
|
+
const oldest = agentBySession.keys().next().value;
|
|
44
|
+
if (oldest === undefined)
|
|
45
|
+
break;
|
|
46
|
+
agentBySession.delete(oldest);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const persistSessions = () => {
|
|
50
|
+
if (!sessionsFile)
|
|
51
|
+
return;
|
|
52
|
+
trimSessions();
|
|
53
|
+
try {
|
|
54
|
+
writeFileSync(sessionsFile, JSON.stringify(Object.fromEntries(agentBySession)));
|
|
55
|
+
}
|
|
56
|
+
catch { /* best effort */ }
|
|
57
|
+
};
|
|
58
|
+
let partCounter = 0;
|
|
5
59
|
const log = (message, data) => {
|
|
6
60
|
if (debug) {
|
|
7
61
|
console.log(`[${new Date().toISOString()}] [${PLUGIN_NAME}]`, message, data ? JSON.stringify(data, null, 2) : "");
|
|
@@ -14,8 +68,48 @@ function createLifecycleHooks(_ctx) {
|
|
|
14
68
|
properties: Object.keys(event.properties ?? {}),
|
|
15
69
|
});
|
|
16
70
|
},
|
|
17
|
-
|
|
71
|
+
config: async (cfg) => {
|
|
72
|
+
if (!rootDir)
|
|
73
|
+
return;
|
|
74
|
+
injectDevloomAgents(cfg, rootDir);
|
|
75
|
+
},
|
|
76
|
+
"chat.message": async (input, output) => {
|
|
77
|
+
if (input.agent && agentBySession.get(input.sessionID) !== input.agent) {
|
|
78
|
+
agentBySession.set(input.sessionID, input.agent);
|
|
79
|
+
persistSessions();
|
|
80
|
+
}
|
|
81
|
+
const guard = buildGuardText(input.agent, readStateSummary(rootDir));
|
|
82
|
+
log("Message received", { agent: input.agent, sessionID: input.sessionID, guarded: !!guard });
|
|
83
|
+
if (!guard)
|
|
84
|
+
return;
|
|
85
|
+
output.parts.push({
|
|
86
|
+
id: `prt_devloom_${Date.now().toString(36)}_${(partCounter++).toString(36)}`,
|
|
87
|
+
sessionID: output.message?.sessionID ?? input.sessionID,
|
|
88
|
+
messageID: output.message?.id ?? input.messageID ?? "",
|
|
89
|
+
type: "text",
|
|
90
|
+
text: guard,
|
|
91
|
+
synthetic: true,
|
|
92
|
+
});
|
|
93
|
+
},
|
|
94
|
+
"experimental.chat.system.transform": async (input, output) => {
|
|
95
|
+
const agent = input.sessionID ? agentBySession.get(input.sessionID) : undefined;
|
|
96
|
+
const guard = buildGuardText(agent, readStateSummary(rootDir));
|
|
97
|
+
if (guard)
|
|
98
|
+
output.system.push(guard);
|
|
99
|
+
},
|
|
100
|
+
"experimental.session.compacting": async (_input, output) => {
|
|
101
|
+
log("Compaction starting — injecting DevLoom preservation context");
|
|
102
|
+
output.context.push(COMPACTION_CONTEXT);
|
|
103
|
+
},
|
|
104
|
+
"tool.execute.before": async ({ tool, sessionID }, output) => {
|
|
18
105
|
log("Tool executing", { tool, sessionID });
|
|
106
|
+
if (agentBySession.get(sessionID) === ORCHESTRATOR_AGENT &&
|
|
107
|
+
isBlockedOrchestratorCall(tool, output.args)) {
|
|
108
|
+
throw new Error("DevLoom guard: the orchestrator must not modify project files directly — " +
|
|
109
|
+
"this applies to write/edit/patch and to bash commands that write, move, or delete files. " +
|
|
110
|
+
'Delegate via task(subagent:"devloom-developer" | "devloom-qa" | ...). ' +
|
|
111
|
+
"Only writes under .opencode/devloom/ are allowed.");
|
|
112
|
+
}
|
|
19
113
|
},
|
|
20
114
|
"tool.execute.after": async ({ tool, sessionID }, output) => {
|
|
21
115
|
log("Tool completed", {
|
|
@@ -24,6 +118,12 @@ function createLifecycleHooks(_ctx) {
|
|
|
24
118
|
title: output?.title,
|
|
25
119
|
outputLength: output?.output?.length ?? 0,
|
|
26
120
|
});
|
|
121
|
+
// The orchestrator session lives for the whole pipeline; unclamped sub-agent
|
|
122
|
+
// outputs are the main driver of context overflow there.
|
|
123
|
+
if (agentBySession.get(sessionID) === ORCHESTRATOR_AGENT &&
|
|
124
|
+
typeof output?.output === "string") {
|
|
125
|
+
output.output = clampToolOutput(output.output);
|
|
126
|
+
}
|
|
27
127
|
},
|
|
28
128
|
};
|
|
29
129
|
}
|
package/dist/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export declare const DEVOOM_AGENT_PREFIX = "devloom-";
|
|
2
|
+
export declare const ORCHESTRATOR_AGENT_NAME = "devloom-orchestrator";
|
|
3
|
+
export declare const DEVOOM_SIDEBAR_ORDER = 100;
|
|
4
|
+
export declare const DEVOOM_SIDEBAR_MAX_ROWS = 12;
|
|
5
|
+
/** Minimal structural subset of the SDK `Agent` type served by /agent. */
|
|
6
|
+
export interface SidebarAgentModel {
|
|
7
|
+
modelID: string;
|
|
8
|
+
providerID: string;
|
|
9
|
+
}
|
|
10
|
+
export interface SidebarAgent {
|
|
11
|
+
name: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
mode?: string;
|
|
14
|
+
color?: string;
|
|
15
|
+
model?: string | SidebarAgentModel;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Derive a human-readable model name for display. The config hook injects the
|
|
19
|
+
* model as a string (`provider/model`), while the SDK `/agent` endpoint
|
|
20
|
+
* normalizes it to `{ modelID, providerID }`. Both are handled.
|
|
21
|
+
*/
|
|
22
|
+
export declare function formatAgentModel(model: string | SidebarAgentModel | undefined): string;
|
|
23
|
+
export interface SidebarAgentView {
|
|
24
|
+
name: string;
|
|
25
|
+
color: string;
|
|
26
|
+
mode: string;
|
|
27
|
+
model: string;
|
|
28
|
+
profileLabel: string | null;
|
|
29
|
+
}
|
|
30
|
+
export interface SidebarAgentsView {
|
|
31
|
+
/** The orchestrator (rendered first, highlighted), or null when absent. */
|
|
32
|
+
orchestrator: SidebarAgentView | null;
|
|
33
|
+
/** Every other DevLoom agent, sorted by name. */
|
|
34
|
+
others: SidebarAgentView[];
|
|
35
|
+
/** The currently active profile derived from the orchestrator label, or null. */
|
|
36
|
+
profile: string | null;
|
|
37
|
+
total: number;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Extract the `(profile: X)` marker the config hook stamps into the
|
|
41
|
+
* orchestrator description, so the sidebar can surface the active profile.
|
|
42
|
+
* Stops at the first comma so the extended `(profile: go, tier: senior)` form
|
|
43
|
+
* still yields just the profile part.
|
|
44
|
+
*/
|
|
45
|
+
export declare function extractProfileLabel(description: string | undefined): string | null;
|
|
46
|
+
/**
|
|
47
|
+
* Extract the optional `tier: X` marker from the extended orchestrator label
|
|
48
|
+
* (e.g. `(profile: go, tier: senior)`), or null when absent.
|
|
49
|
+
*/
|
|
50
|
+
export declare function extractTierLabel(description: string | undefined): string | null;
|
|
51
|
+
/**
|
|
52
|
+
* Turn the raw agent list from `api.client.app.agents()` into the view models
|
|
53
|
+
* rendered in the right sidebar: base and non-tiered DevLoom agents only
|
|
54
|
+
* (flash and senior variants are hidden but still registered), orchestrator
|
|
55
|
+
* first, the rest sorted by name, each with the model it uses. When `profile`
|
|
56
|
+
* is omitted it is derived from the orchestrator label stamped by the config
|
|
57
|
+
* hook — the backward-compatible path used by src/tui.ts, which passes no
|
|
58
|
+
* args. Never throws; empty input yields an empty view.
|
|
59
|
+
*/
|
|
60
|
+
export declare function buildSidebarAgentViews(agents: readonly SidebarAgent[], profile?: string | null): SidebarAgentsView;
|
|
61
|
+
//# sourceMappingURL=tui-agents.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tui-agents.d.ts","sourceRoot":"","sources":["../src/tui-agents.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,mBAAmB,aAAa,CAAA;AAC7C,eAAO,MAAM,uBAAuB,yBAAyB,CAAA;AAC7D,eAAO,MAAM,oBAAoB,MAAM,CAAA;AACvC,eAAO,MAAM,uBAAuB,KAAK,CAAA;AAEzC,0EAA0E;AAC1E,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAAA;CACnC;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,GAAG,MAAM,CAItF;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5B;AAED,MAAM,WAAW,iBAAiB;IAChC,2EAA2E;IAC3E,YAAY,EAAE,gBAAgB,GAAG,IAAI,CAAA;IACrC,iDAAiD;IACjD,MAAM,EAAE,gBAAgB,EAAE,CAAA;IAC1B,iFAAiF;IACjF,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,KAAK,EAAE,MAAM,CAAA;CACd;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAIlF;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAI/E;AAcD;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,SAAS,YAAY,EAAE,EAC/B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,GACtB,iBAAiB,CA0BnB"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// Pure view-model helpers for the DevLoom TUI sidebar plugin (src/tui.ts).
|
|
2
|
+
// Kept free of any @opentui/solid / solid-js runtime imports so the logic is
|
|
3
|
+
// unit-testable in isolation.
|
|
4
|
+
export const DEVOOM_AGENT_PREFIX = "devloom-";
|
|
5
|
+
export const ORCHESTRATOR_AGENT_NAME = "devloom-orchestrator";
|
|
6
|
+
export const DEVOOM_SIDEBAR_ORDER = 100;
|
|
7
|
+
export const DEVOOM_SIDEBAR_MAX_ROWS = 12;
|
|
8
|
+
/**
|
|
9
|
+
* Derive a human-readable model name for display. The config hook injects the
|
|
10
|
+
* model as a string (`provider/model`), while the SDK `/agent` endpoint
|
|
11
|
+
* normalizes it to `{ modelID, providerID }`. Both are handled.
|
|
12
|
+
*/
|
|
13
|
+
export function formatAgentModel(model) {
|
|
14
|
+
if (!model)
|
|
15
|
+
return "";
|
|
16
|
+
if (typeof model === "string")
|
|
17
|
+
return model;
|
|
18
|
+
return model.providerID ? `${model.providerID}/${model.modelID}` : model.modelID;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Extract the `(profile: X)` marker the config hook stamps into the
|
|
22
|
+
* orchestrator description, so the sidebar can surface the active profile.
|
|
23
|
+
* Stops at the first comma so the extended `(profile: go, tier: senior)` form
|
|
24
|
+
* still yields just the profile part.
|
|
25
|
+
*/
|
|
26
|
+
export function extractProfileLabel(description) {
|
|
27
|
+
if (!description)
|
|
28
|
+
return null;
|
|
29
|
+
const match = /\(profile: ([^),]+)[^)]*\)/.exec(description);
|
|
30
|
+
return match ? match[1] : null;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Extract the optional `tier: X` marker from the extended orchestrator label
|
|
34
|
+
* (e.g. `(profile: go, tier: senior)`), or null when absent.
|
|
35
|
+
*/
|
|
36
|
+
export function extractTierLabel(description) {
|
|
37
|
+
if (!description)
|
|
38
|
+
return null;
|
|
39
|
+
const match = /tier: ([^)]+)/.exec(description);
|
|
40
|
+
return match ? match[1] : null;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Whether an agent name (`devloom-<variant>`) should be shown in the sidebar.
|
|
44
|
+
* Mirrors `agentVariantVisible` in agents.ts without pulling the fs-bound
|
|
45
|
+
* agents module into this pure view-model module. Only base and non-tiered
|
|
46
|
+
* variants are shown; flash and senior variants are always hidden regardless
|
|
47
|
+
* of the active profile.
|
|
48
|
+
*/
|
|
49
|
+
function variantVisible(name) {
|
|
50
|
+
const variant = name.startsWith(DEVOOM_AGENT_PREFIX) ? name.slice(DEVOOM_AGENT_PREFIX.length) : name;
|
|
51
|
+
return !variant.endsWith("-flash") && !variant.endsWith("-senior");
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Turn the raw agent list from `api.client.app.agents()` into the view models
|
|
55
|
+
* rendered in the right sidebar: base and non-tiered DevLoom agents only
|
|
56
|
+
* (flash and senior variants are hidden but still registered), orchestrator
|
|
57
|
+
* first, the rest sorted by name, each with the model it uses. When `profile`
|
|
58
|
+
* is omitted it is derived from the orchestrator label stamped by the config
|
|
59
|
+
* hook — the backward-compatible path used by src/tui.ts, which passes no
|
|
60
|
+
* args. Never throws; empty input yields an empty view.
|
|
61
|
+
*/
|
|
62
|
+
export function buildSidebarAgentViews(agents, profile) {
|
|
63
|
+
let resolvedProfile = profile ?? null;
|
|
64
|
+
if (resolvedProfile === null) {
|
|
65
|
+
const orchestrator = agents.find((agent) => agent && typeof agent.name === "string" && agent.name === ORCHESTRATOR_AGENT_NAME);
|
|
66
|
+
if (orchestrator) {
|
|
67
|
+
resolvedProfile = extractProfileLabel(orchestrator.description) ?? null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const views = [];
|
|
71
|
+
for (const agent of agents) {
|
|
72
|
+
if (!agent || typeof agent.name !== "string" || !agent.name.startsWith(DEVOOM_AGENT_PREFIX))
|
|
73
|
+
continue;
|
|
74
|
+
if (!variantVisible(agent.name))
|
|
75
|
+
continue;
|
|
76
|
+
views.push({
|
|
77
|
+
name: agent.name,
|
|
78
|
+
color: typeof agent.color === "string" ? agent.color : "#7fdbca",
|
|
79
|
+
mode: agent.mode ?? "subagent",
|
|
80
|
+
model: formatAgentModel(agent.model),
|
|
81
|
+
profileLabel: extractProfileLabel(agent.description),
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
views.sort((a, b) => a.name.localeCompare(b.name));
|
|
85
|
+
const orchestrator = views.find((view) => view.name === ORCHESTRATOR_AGENT_NAME) ?? null;
|
|
86
|
+
const others = views.filter((view) => view !== orchestrator);
|
|
87
|
+
return { orchestrator, others, total: views.length, profile: resolvedProfile };
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=tui-agents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tui-agents.js","sourceRoot":"","sources":["../src/tui-agents.ts"],"names":[],"mappings":"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"}
|
package/dist/tui.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAA2B,eAAe,EAAY,MAAM,yBAAyB,CAAA;AAmFjG,QAAA,MAAM,MAAM,EAAE,eAAe,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAG3C,CAAA;AAED,eAAe,MAAM,CAAA"}
|
package/dist/tui.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// TUI entrypoint for the DevLoom plugin.
|
|
2
|
+
//
|
|
3
|
+
// Why this exists: OpenCode's right sidebar is not fed from any agent
|
|
4
|
+
// directory — in the 1.18 TUI the rightbar renders ONLY plugin slots
|
|
5
|
+
// (`sidebar_title` / `sidebar_content` / `sidebar_footer`, see
|
|
6
|
+
// packages/tui/src/routes/session/sidebar.tsx). The agents configured via the
|
|
7
|
+
// server config hook are resolvable (Tab dialog, `@` menu, `/agent` endpoint)
|
|
8
|
+
// but never appear in the rightbar unless a TUI plugin renders them there.
|
|
9
|
+
// This module registers a `sidebar_content` slot that lists the DevLoom agents
|
|
10
|
+
// so a restarted session shows them in the right sidebar.
|
|
11
|
+
//
|
|
12
|
+
// Loaded by OpenCode only when the package exposes `exports["./tui"]` AND the
|
|
13
|
+
// plugin is listed in tui.json's `plugin` array (no directory auto-discovery).
|
|
14
|
+
// The loader rejects a module that exports both `server` and `tui`, so this
|
|
15
|
+
// target-exclusive module lives in its own file next to dist/index.js
|
|
16
|
+
// (`./server`).
|
|
17
|
+
import { createSignal } from "solid-js";
|
|
18
|
+
import { createElement, insert, setProp } from "@opentui/solid";
|
|
19
|
+
import { DEVOOM_SIDEBAR_MAX_ROWS, DEVOOM_SIDEBAR_ORDER, buildSidebarAgentViews, } from "./tui-agents.js";
|
|
20
|
+
/** Build an @opentui element tree without JSX (same primitives the host uses). */
|
|
21
|
+
function element(tag, props = {}, children = []) {
|
|
22
|
+
const node = createElement(tag);
|
|
23
|
+
for (const [key, value] of Object.entries(props)) {
|
|
24
|
+
if (value !== undefined)
|
|
25
|
+
setProp(node, key, value);
|
|
26
|
+
}
|
|
27
|
+
for (const child of children) {
|
|
28
|
+
if (child === null || child === undefined || child === false)
|
|
29
|
+
continue;
|
|
30
|
+
insert(node, child);
|
|
31
|
+
}
|
|
32
|
+
return node;
|
|
33
|
+
}
|
|
34
|
+
function agentRow(agent) {
|
|
35
|
+
const marker = agent.name === "devloom-orchestrator" ? "◈ " : "● ";
|
|
36
|
+
const shortName = agent.name.startsWith("devloom-") ? agent.name.slice("devloom-".length) : agent.name;
|
|
37
|
+
const model = agent.model ? `: ${agent.model}` : "";
|
|
38
|
+
return element("text", { fg: agent.color }, [`${marker}${shortName}${model}`]);
|
|
39
|
+
}
|
|
40
|
+
function renderRows(api, agents) {
|
|
41
|
+
return element("box", { flexDirection: "column" }, [
|
|
42
|
+
() => {
|
|
43
|
+
const theme = api.theme.current;
|
|
44
|
+
const view = buildSidebarAgentViews(agents());
|
|
45
|
+
if (view.total === 0) {
|
|
46
|
+
return element("text", { fg: theme.textMuted }, [
|
|
47
|
+
"DevLoom agents will appear after /devloom-refresh + restart",
|
|
48
|
+
]);
|
|
49
|
+
}
|
|
50
|
+
const rows = [];
|
|
51
|
+
if (view.orchestrator)
|
|
52
|
+
rows.push(agentRow(view.orchestrator));
|
|
53
|
+
for (const other of view.others.slice(0, DEVOOM_SIDEBAR_MAX_ROWS))
|
|
54
|
+
rows.push(agentRow(other));
|
|
55
|
+
if (view.others.length > DEVOOM_SIDEBAR_MAX_ROWS) {
|
|
56
|
+
rows.push(element("text", { fg: theme.textMuted }, [
|
|
57
|
+
`+${view.others.length - DEVOOM_SIDEBAR_MAX_ROWS} more`,
|
|
58
|
+
]));
|
|
59
|
+
}
|
|
60
|
+
return rows;
|
|
61
|
+
},
|
|
62
|
+
]);
|
|
63
|
+
}
|
|
64
|
+
const tui = async (api) => {
|
|
65
|
+
const [agents, setAgents] = createSignal([]);
|
|
66
|
+
api.client.app
|
|
67
|
+
.agents(undefined, { throwOnError: true })
|
|
68
|
+
.then((result) => setAgents(result.data))
|
|
69
|
+
.catch(() => setAgents([]));
|
|
70
|
+
api.slots.register({
|
|
71
|
+
order: DEVOOM_SIDEBAR_ORDER,
|
|
72
|
+
slots: {
|
|
73
|
+
sidebar_content() {
|
|
74
|
+
const theme = api.theme.current;
|
|
75
|
+
return element("box", { flexDirection: "column", gap: 1, paddingRight: 1 }, [
|
|
76
|
+
() => {
|
|
77
|
+
const view = buildSidebarAgentViews(agents());
|
|
78
|
+
const profile = view.profile ? ` - ${view.profile}` : "";
|
|
79
|
+
return element("text", { fg: theme.text }, [element("b", {}, [`DevLoom${profile}`])]);
|
|
80
|
+
},
|
|
81
|
+
renderRows(api, agents),
|
|
82
|
+
]);
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
};
|
|
87
|
+
const plugin = {
|
|
88
|
+
id: "devloom",
|
|
89
|
+
tui,
|
|
90
|
+
};
|
|
91
|
+
export default plugin;
|
|
92
|
+
//# sourceMappingURL=tui.js.map
|
package/dist/tui.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tui.js","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export type WorktreeEntry = {
|
|
2
|
+
branch: string;
|
|
3
|
+
path: string;
|
|
4
|
+
baseRef: string;
|
|
5
|
+
createdAt: string;
|
|
6
|
+
ticket: string;
|
|
7
|
+
agent: string;
|
|
8
|
+
};
|
|
9
|
+
export type WorktreeStatus = {
|
|
10
|
+
branch: string;
|
|
11
|
+
exists: boolean;
|
|
12
|
+
path?: string;
|
|
13
|
+
clean: boolean;
|
|
14
|
+
ahead: number;
|
|
15
|
+
behind: number;
|
|
16
|
+
createdAt?: string;
|
|
17
|
+
ticket?: string;
|
|
18
|
+
agent?: string;
|
|
19
|
+
};
|
|
20
|
+
export type MergeResult = {
|
|
21
|
+
success: boolean;
|
|
22
|
+
conflicts: string[];
|
|
23
|
+
message: string;
|
|
24
|
+
branch: string;
|
|
25
|
+
worktreePath?: string;
|
|
26
|
+
mergedInto?: string;
|
|
27
|
+
};
|
|
28
|
+
export type RemoveResult = {
|
|
29
|
+
removed: boolean;
|
|
30
|
+
message: string;
|
|
31
|
+
};
|
|
32
|
+
export type CleanResult = {
|
|
33
|
+
branch: string;
|
|
34
|
+
removed: boolean;
|
|
35
|
+
reason?: string;
|
|
36
|
+
};
|
|
37
|
+
export declare function getCurrentBranch(rootDir: string): string;
|
|
38
|
+
export declare function isClean(rootDir: string): boolean;
|
|
39
|
+
export declare function createWorktree(rootDir: string, branchName: string, baseRef?: string): WorktreeEntry;
|
|
40
|
+
export declare function mergeWorktree(rootDir: string, branchName: string): MergeResult;
|
|
41
|
+
export declare function removeWorktree(rootDir: string, branchName: string, force?: boolean): RemoveResult;
|
|
42
|
+
export declare function listWorktrees(rootDir: string): WorktreeEntry[];
|
|
43
|
+
export declare function worktreeStatus(rootDir: string, branchName: string): WorktreeStatus;
|
|
44
|
+
export declare function cleanWorktrees(rootDir: string, force?: boolean): CleanResult[];
|
|
45
|
+
export declare function readWorktreeSummary(rootDir: string): string;
|
|
46
|
+
//# sourceMappingURL=worktree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree.d.ts","sourceRoot":"","sources":["../src/worktree.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,OAAO,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,OAAO,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA;AAmDD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAGhD;AAuCD,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,aAAa,CAuCnG;AAeD,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,WAAW,CAuD9E;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,UAAQ,GAAG,YAAY,CAoB/F;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,EAAE,CAI9D;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,cAAc,CAwBlF;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,UAAQ,GAAG,WAAW,EAAE,CAwB5E;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAO3D"}
|