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.
Files changed (142) hide show
  1. package/.ai/core.dsl +44 -0
  2. package/.ai/skills.dsl +39 -0
  3. package/.ai/verify.dsl +97 -0
  4. package/.ai/workflow.dsl +81 -0
  5. package/.opencode/themes/devloom-night-owl.json +103 -0
  6. package/GUIDE.md +572 -115
  7. package/README.md +583 -109
  8. package/SECURITY.md +93 -0
  9. package/agents/devloom-developer-flash.md +31 -0
  10. package/agents/devloom-developer-senior.md +32 -0
  11. package/agents/devloom-developer.md +21 -55
  12. package/agents/devloom-documenter-flash.md +28 -0
  13. package/agents/devloom-documenter.md +17 -56
  14. package/agents/devloom-orchestrator.md +236 -356
  15. package/agents/devloom-planner-flash.md +34 -0
  16. package/agents/devloom-planner-senior.md +35 -0
  17. package/agents/devloom-planner.md +36 -0
  18. package/agents/devloom-qa-flash.md +32 -0
  19. package/agents/devloom-qa.md +21 -83
  20. package/agents/devloom-security-senior.md +35 -0
  21. package/agents/devloom-security.md +34 -0
  22. package/agents/devloom-verifier.md +33 -0
  23. package/agents/devloom-vision.md +113 -0
  24. package/agents/devloom-visual-critic.md +102 -0
  25. package/agents/devloom-visual-director.md +84 -0
  26. package/commands/devloom-agents.md +49 -0
  27. package/commands/devloom-auto.md +11 -0
  28. package/commands/devloom-context.md +82 -0
  29. package/commands/devloom-deepseek-mimo.md +11 -0
  30. package/commands/devloom-deepseek.md +11 -0
  31. package/commands/devloom-free.md +11 -0
  32. package/commands/devloom-go-economy.md +11 -0
  33. package/commands/devloom-go-flash.md +11 -0
  34. package/commands/devloom-go.md +11 -0
  35. package/commands/devloom-init.md +28 -50
  36. package/commands/devloom-loop-status.md +25 -0
  37. package/commands/devloom-loop.md +36 -0
  38. package/commands/devloom-mimo.md +11 -0
  39. package/commands/devloom-plan.md +13 -0
  40. package/commands/devloom-refresh.md +22 -0
  41. package/commands/devloom-resume.md +30 -49
  42. package/commands/devloom-save.md +69 -0
  43. package/commands/devloom-status.md +9 -18
  44. package/commands/devloom.md +99 -67
  45. package/dist/agents.d.ts +30 -0
  46. package/dist/agents.d.ts.map +1 -0
  47. package/dist/agents.js +139 -0
  48. package/dist/agents.js.map +1 -0
  49. package/dist/bootstrap.d.ts +56 -0
  50. package/dist/bootstrap.d.ts.map +1 -0
  51. package/dist/bootstrap.js +116 -0
  52. package/dist/bootstrap.js.map +1 -0
  53. package/dist/constraints.d.ts +5 -0
  54. package/dist/constraints.d.ts.map +1 -0
  55. package/dist/constraints.js +45 -0
  56. package/dist/constraints.js.map +1 -0
  57. package/dist/context.d.ts +42 -0
  58. package/dist/context.d.ts.map +1 -0
  59. package/dist/context.js +636 -0
  60. package/dist/context.js.map +1 -0
  61. package/dist/guard.d.ts +19 -0
  62. package/dist/guard.d.ts.map +1 -0
  63. package/dist/guard.js +418 -0
  64. package/dist/guard.js.map +1 -0
  65. package/dist/loop.d.ts +64 -0
  66. package/dist/loop.d.ts.map +1 -0
  67. package/dist/loop.js +164 -0
  68. package/dist/loop.js.map +1 -0
  69. package/dist/plugin.d.ts.map +1 -1
  70. package/dist/plugin.js +101 -1
  71. package/dist/plugin.js.map +1 -1
  72. package/dist/tui-agents.d.ts +61 -0
  73. package/dist/tui-agents.d.ts.map +1 -0
  74. package/dist/tui-agents.js +89 -0
  75. package/dist/tui-agents.js.map +1 -0
  76. package/dist/tui.d.ts +6 -0
  77. package/dist/tui.d.ts.map +1 -0
  78. package/dist/tui.js +92 -0
  79. package/dist/tui.js.map +1 -0
  80. package/dist/worktree.d.ts +46 -0
  81. package/dist/worktree.d.ts.map +1 -0
  82. package/dist/worktree.js +272 -0
  83. package/dist/worktree.js.map +1 -0
  84. package/package.json +46 -6
  85. package/patterns/changelog-drafter.md +38 -0
  86. package/patterns/ci-sweeper.md +40 -0
  87. package/patterns/daily-triage.md +37 -0
  88. package/patterns/dependency-sweeper.md +40 -0
  89. package/patterns/design-audit.md +63 -0
  90. package/patterns/issue-triage.md +37 -0
  91. package/patterns/post-merge-cleanup.md +34 -0
  92. package/patterns/pr-babysitter.md +37 -0
  93. package/patterns/registry.yaml +52 -0
  94. package/postinstall.mjs +264 -64
  95. package/project/README.md +29 -0
  96. package/protocol/agent-contracts.md +27 -0
  97. package/protocol/artifact-system.md +53 -0
  98. package/protocol/model-routing.md +194 -0
  99. package/protocol/orchestrator-core.md +43 -0
  100. package/protocol/project-system.md +45 -0
  101. package/protocol/rules.md +18 -0
  102. package/protocol/verification-policy.md +48 -0
  103. package/scripts/briefing.mjs +192 -0
  104. package/scripts/loop-run.mjs +205 -0
  105. package/scripts/model-capabilities.mjs +194 -0
  106. package/scripts/plugin-cache.mjs +269 -0
  107. package/scripts/profile.mjs +755 -0
  108. package/scripts/visual-benchmark.mjs +149 -0
  109. package/scripts/worktree.mjs +445 -0
  110. package/skills/build/development.md +33 -0
  111. package/skills/build/live-docs.md +38 -0
  112. package/skills/build/simplify.md +50 -0
  113. package/skills/build/vision-analysis.md +98 -0
  114. package/skills/design/app-design.md +31 -0
  115. package/skills/design/design-grounding.md +30 -0
  116. package/skills/design/design-system.md +27 -0
  117. package/skills/design/game-design.md +35 -0
  118. package/skills/design/motion-design.md +34 -0
  119. package/skills/design/visual-direction.md +32 -0
  120. package/skills/design/web-design.md +33 -0
  121. package/skills/loop/changelog-drafter.md +32 -0
  122. package/skills/loop/ci-sweeper.md +24 -0
  123. package/skills/loop/constraints.md +21 -0
  124. package/skills/loop/dependency-sweeper.md +24 -0
  125. package/skills/loop/design-audit.md +67 -0
  126. package/skills/loop/issue-triage.md +27 -0
  127. package/skills/loop/post-merge-cleanup.md +24 -0
  128. package/skills/loop/pr-babysitter.md +26 -0
  129. package/skills/loop/triage.md +25 -0
  130. package/skills/loop/verifier.md +20 -0
  131. package/skills/meta/skill-discovery.md +23 -0
  132. package/skills/plan/planning.md +27 -0
  133. package/skills/plan/verification-planning.md +40 -0
  134. package/skills/review/security-review.md +63 -0
  135. package/skills/ship/documentation.md +11 -0
  136. package/skills/verify/app-verification.md +19 -0
  137. package/skills/verify/quality-assurance.md +17 -0
  138. package/skills/verify/visual-critique.md +30 -0
  139. package/skills/verify/visual-quality-gate.md +29 -0
  140. package/skills/verify/visual-regression.md +25 -0
  141. package/agents/devloom-analyst.md +0 -83
  142. 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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop.js","sourceRoot":"","sources":["../src/loop.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAI7D,iBAAS,oBAAoB,CAAC,IAAI,EAAE,WAAW,GAAG,KAAK,CAkCtD;AAED,OAAO,EAAE,oBAAoB,EAAE,CAAA"}
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
- "tool.execute.before": async ({ tool, sessionID }) => {
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
  }
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AAGlC,MAAM,WAAW,GAAG,SAAS,CAAA;AAE7B,SAAS,oBAAoB,CAAC,IAAiB;IAC7C,MAAM,KAAK,GAAG,GAAG,CAAC,aAAa,KAAK,GAAG,CAAA;IAEvC,MAAM,GAAG,GAAG,CAAC,OAAe,EAAE,IAA8B,EAAE,EAAE;QAC9D,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,GAAG,CACT,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,MAAM,WAAW,GAAG,EAChD,OAAO,EACP,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAC1C,CAAA;QACH,CAAC;IACH,CAAC,CAAA;IAED,OAAO;QACL,KAAK,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;YACzB,GAAG,CAAC,gBAAgB,EAAE;gBACpB,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,IAAI,EAAE,CAAC;aAChD,CAAC,CAAA;QACJ,CAAC;QAED,qBAAqB,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE;YACnD,GAAG,CAAC,gBAAgB,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAA;QAC5C,CAAC;QAED,oBAAoB,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,EAAE;YAC1D,GAAG,CAAC,gBAAgB,EAAE;gBACpB,IAAI;gBACJ,SAAS;gBACT,KAAK,EAAE,MAAM,EAAE,KAAK;gBACpB,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,IAAI,CAAC;aAC1C,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC;AAED,OAAO,EAAE,oBAAoB,EAAE,CAAA"}
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,6 @@
1
+ import type { TuiPluginModule } from "@opencode-ai/plugin/tui";
2
+ declare const plugin: TuiPluginModule & {
3
+ id: string;
4
+ };
5
+ export default plugin;
6
+ //# sourceMappingURL=tui.d.ts.map
@@ -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
@@ -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"}