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
@@ -0,0 +1,19 @@
1
+ export declare const ORCHESTRATOR_AGENT = "devloom-orchestrator";
2
+ export declare const DEVLOOM_AGENTS: {
3
+ name: string;
4
+ role: string;
5
+ }[];
6
+ /** Test hook — drops the memoized state summary. */
7
+ export declare function resetStateSummaryCache(): void;
8
+ /**
9
+ * Memoized for {@link STATE_SUMMARY_TTL_MS}: this runs on every `chat.message`
10
+ * AND every `experimental.chat.system.transform`, and each uncached call spawns
11
+ * a synchronous `git` per worktree plus a dozen file reads.
12
+ */
13
+ export declare function readStateSummary(rootDir: string): string;
14
+ export declare function buildGuardText(agent: string | undefined, stateSummary: string): string | null;
15
+ export declare const ORCH_TOOL_OUTPUT_LIMIT = 12000;
16
+ export declare function clampToolOutput(text: string, limit?: number): string;
17
+ export declare function bashWriteTargets(command: string): string[];
18
+ export declare function isBlockedOrchestratorCall(tool: string, args: unknown): boolean;
19
+ //# sourceMappingURL=guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,kBAAkB,yBAAyB,CAAA;AAKxD,eAAO,MAAM,cAAc;;;GAW1B,CAAA;AAaD,oDAAoD;AACpD,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAQxD;AAiDD,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA8B7F;AAED,eAAO,MAAM,sBAAsB,QAAS,CAAA;AAE5C,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,SAAyB,GAAG,MAAM,CASpF;AAuLD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAsE1D;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAc9E"}
package/dist/guard.js ADDED
@@ -0,0 +1,418 @@
1
+ import { readFileSync, existsSync } from "node:fs";
2
+ import { join, normalize } from "node:path";
3
+ import { readWorktreeSummary } from "./worktree.js";
4
+ import { contextSummaryString } from "./context.js";
5
+ import { readLoopStateSummary } from "./loop.js";
6
+ import { readConstraints, buildConstraintsGuard } from "./constraints.js";
7
+ function constraintsSummary(rootDir) {
8
+ const loop = readLoopStateSummary(rootDir);
9
+ if (loop.includes("loop=inactive"))
10
+ return "";
11
+ const constraints = readConstraints(rootDir);
12
+ return buildConstraintsGuard(constraints);
13
+ }
14
+ export const ORCHESTRATOR_AGENT = "devloom-orchestrator";
15
+ const WRITE_TOOLS = new Set(["write", "edit", "patch"]);
16
+ const DEVLOOM_STATE_DIR = ".opencode/devloom/";
17
+ export const DEVLOOM_AGENTS = [
18
+ { name: "devloom-orchestrator", role: "Strategic coordinator" },
19
+ { name: "devloom-planner", role: "Requirements, specs, architecture" },
20
+ { name: "devloom-developer", role: "Implementation, code, fixes" },
21
+ { name: "devloom-qa", role: "Verification, review, regression" },
22
+ { name: "devloom-verifier", role: "Runtime checks, routes, a11y, API" },
23
+ { name: "devloom-security", role: "Security audit, CRUD review" },
24
+ { name: "devloom-documenter", role: "Documentation, README" },
25
+ { name: "devloom-vision", role: "Image/screenshot analysis" },
26
+ { name: "devloom-visual-director", role: "Design brief, DESIGN_FILE" },
27
+ { name: "devloom-visual-critic", role: "Visual critique, score, verdict" },
28
+ ];
29
+ function readJson(path, fallback) {
30
+ try {
31
+ return JSON.parse(readFileSync(path, "utf8"));
32
+ }
33
+ catch {
34
+ return fallback;
35
+ }
36
+ }
37
+ const STATE_SUMMARY_TTL_MS = 2_000;
38
+ let stateCache = null;
39
+ /** Test hook — drops the memoized state summary. */
40
+ export function resetStateSummaryCache() {
41
+ stateCache = null;
42
+ }
43
+ /**
44
+ * Memoized for {@link STATE_SUMMARY_TTL_MS}: this runs on every `chat.message`
45
+ * AND every `experimental.chat.system.transform`, and each uncached call spawns
46
+ * a synchronous `git` per worktree plus a dozen file reads.
47
+ */
48
+ export function readStateSummary(rootDir) {
49
+ const now = Date.now();
50
+ if (stateCache && stateCache.rootDir === rootDir && now - stateCache.at < STATE_SUMMARY_TTL_MS) {
51
+ return stateCache.value;
52
+ }
53
+ const value = computeStateSummary(rootDir);
54
+ stateCache = { rootDir, at: now, value };
55
+ return value;
56
+ }
57
+ function computeStateSummary(rootDir) {
58
+ const projectRoot = join(rootDir, ".opencode", "devloom", "project");
59
+ const state = readJson(join(projectRoot, "state.json"), {});
60
+ const board = readJson(join(projectRoot, "board.json"), {});
61
+ if (!state.phase)
62
+ return "unbootstrapped";
63
+ const doing = Array.isArray(board.cols?.doing) ? board.cols.doing.length : 0;
64
+ const backlog = Array.isArray(board.cols?.backlog) ? board.cols.backlog.length : 0;
65
+ const wt = readWorktreeSummary(rootDir);
66
+ const loopSummary = readLoopStateSummary(rootDir);
67
+ const ctx = contextSummaryString(rootDir);
68
+ const sessCount = state.sessions ? Object.keys(state.sessions).length : 0;
69
+ const degraded = state.degraded ? " degraded" : "";
70
+ const atlas = existsSync(join(rootDir, ".opencode", "devloom", "context", "atlas.md")) ? " atlas" : "";
71
+ const loopDetect = detectLoopState(state);
72
+ const parts = [`phase=${state.phase} ticket=${state.ticket || "-"} next=${state.next || "-"} doing=${doing} backlog=${backlog} sessions=${sessCount}${degraded}${atlas} ${wt} ${loopSummary} ${ctx}${loopDetect}`];
73
+ const constrGuard = constraintsSummary(rootDir);
74
+ if (constrGuard)
75
+ parts.push(constrGuard);
76
+ return parts.join(" ");
77
+ }
78
+ function detectLoopState(state) {
79
+ if (!state.loopCounts || Object.keys(state.loopCounts).length === 0)
80
+ return "";
81
+ const warnings = [];
82
+ for (const [agent, count] of Object.entries(state.loopCounts)) {
83
+ if (count >= 3) {
84
+ warnings.push(`ALERT:${agent}=${count}x(retry limit reached)`);
85
+ }
86
+ else if (count >= 2) {
87
+ warnings.push(`WARN:${agent}=${count}x`);
88
+ }
89
+ }
90
+ if (warnings.length === 0)
91
+ return "";
92
+ return ` loop_risk=[${warnings.join(";")}]`;
93
+ }
94
+ const COMPLIANCE_REQUIREMENTS = [
95
+ "COMPLIANCE: you MUST follow the protocol and skill files declared in your LOAD directive — they define your operating rules, output format, and gates.",
96
+ "COMPLIANCE: you MUST NOT skip, abbreviate, or ignore any RULE in your LOADed files. Every rule is mandatory.",
97
+ "COMPLIANCE: you MUST complete all required gates (build, lint, test, review) before emitting your OUT signal.",
98
+ "COMPLIANCE: you MUST use your skill file — it defines the engineering standards and workflow for your role.",
99
+ ];
100
+ export function buildGuardText(agent, stateSummary) {
101
+ if (agent && agent.startsWith("devloom-") && agent !== ORCHESTRATOR_AGENT) {
102
+ return [
103
+ `[devloom-guard] ${agent}`,
104
+ ...COMPLIANCE_REQUIREMENTS,
105
+ `DevLoom state: ${stateSummary}`,
106
+ ].join(" ");
107
+ }
108
+ if (agent === ORCHESTRATOR_AGENT) {
109
+ const loopWarning = stateSummary.includes("loop_risk=")
110
+ ? " LOOP DETECTED — reduce delegation depth, break task into smaller pieces, or report BLOCKED."
111
+ : "";
112
+ return [
113
+ "[devloom-guard] Orchestrator protocol, every turn:",
114
+ ...COMPLIANCE_REQUIREMENTS,
115
+ "COMPLIANCE: verify every sub-agent output against the protocol gates — reject incomplete or non-compliant results.",
116
+ "1) read board+state 2) resume pending phase first 3) new prompt → triage intent, pick minimal chain (never full pipeline by default)",
117
+ "4) delegate ALL phase work via task() — never write code/diffs yourself, never self-delegate",
118
+ "5) persist board+state after each phase 6) end only with task() issued, BLOCKED+reason, or DEVLOOM_DONE.",
119
+ "ANTI-LOOP: max 2 retries per agent per ticket. After 2 failures → BLOCKED + report. Never delegate to same agent 3x on same ticket.",
120
+ "REDIRECT: if sub-agent calls task() instead of completing work → STOP, report BLOCKED, delegation chain detected." + loopWarning,
121
+ `State: ${stateSummary}`,
122
+ ].join(" ");
123
+ }
124
+ return [
125
+ "[devloom-guard] Routing rule: code work (build/fix/refactor/add/test/migrate/deploy/document)",
126
+ '→ task(subagent:"devloom-orchestrator", description:"...", prompt:"<request>").',
127
+ "Pure questions or single-line tweaks → answer directly.",
128
+ `DevLoom state: ${stateSummary}`,
129
+ ].join(" ");
130
+ }
131
+ export const ORCH_TOOL_OUTPUT_LIMIT = 12_000;
132
+ export function clampToolOutput(text, limit = ORCH_TOOL_OUTPUT_LIMIT) {
133
+ if (text.length <= limit)
134
+ return text;
135
+ const head = text.slice(0, Math.floor(limit * 0.7));
136
+ const tail = text.slice(-Math.floor(limit * 0.2));
137
+ return [
138
+ head,
139
+ `\n[devloom-guard] output truncated (${text.length} chars). Full detail belongs in .opencode/devloom/ artifacts, not chat context.\n`,
140
+ tail,
141
+ ].join("");
142
+ }
143
+ /**
144
+ * True when `path` lands inside `.opencode/devloom/`. Normalizes first so
145
+ * `.opencode/devloom/../../src/app.ts` is correctly seen as an escape, and so
146
+ * the exact `.opencode/devloom` root is still allowed (the trailing-slash
147
+ * `.includes` alone would reject it). Backslash separators are folded to `/`
148
+ * both before (input) and after (Windows `normalize`) normalization.
149
+ */
150
+ function isDevloomStatePath(path) {
151
+ if (!path)
152
+ return false;
153
+ const normalized = normalize(path.replace(/\\/g, "/")).replace(/\\/g, "/");
154
+ // `includes` (with trailing slash) covers anything beneath the root;
155
+ // `endsWith` covers the root itself — e.g. `/repo/.opencode/devloom`.
156
+ return normalized.includes(DEVLOOM_STATE_DIR) || normalized.endsWith(DEVLOOM_STATE_DIR.slice(0, -1));
157
+ }
158
+ /** Mutators the orchestrator has no legitimate use for — always blocked. */
159
+ const BASH_FORBIDDEN = /\b(?:sed\s+(?:-\S+\s+)*-\S*i|perl\s+(?:-\S+\s+)*-\S*i|truncate|dd)\b/;
160
+ /** Targets that are fd/device sinks, never project files. */
161
+ const IGNORED_TARGETS = new Set([
162
+ "/dev/null",
163
+ "/dev/zero",
164
+ "/dev/stdin",
165
+ "/dev/stdout",
166
+ "/dev/stderr",
167
+ "/dev/tty",
168
+ ]);
169
+ const WORD_STOP = " \t\r\n><|&;()'\"`\\#";
170
+ /**
171
+ * Lightweight, quote-aware shell tokenizer. Splits a command into words,
172
+ * operators (`>`, `>>`, `<<`, `>&`, `|`, `&&`, ...), and command-substitution
173
+ * bodies (`$(...)`, backticks) that are re-scanned recursively. Unlike the old
174
+ * regexes it respects single/double quotes and backslash escapes, and it skips
175
+ * heredoc bodies between the `<<DELIM` and the closing delimiter line.
176
+ *
177
+ * Known limit (unchanged): it does not execute the command, so writes hidden in
178
+ * `node -e "writeFileSync(...)"` or an aliased shell function stay invisible.
179
+ */
180
+ function tokenizeShell(command) {
181
+ const toks = [];
182
+ const n = command.length;
183
+ let i = 0;
184
+ let heredocPending = false;
185
+ let heredocDelim = "";
186
+ let heredocAwaitNewline = false;
187
+ let inHeredoc = false;
188
+ const pushWord = (value) => {
189
+ if (heredocPending) {
190
+ heredocDelim = value;
191
+ heredocPending = false;
192
+ // The heredoc body starts at the first newline after the delimiter; other
193
+ // tokens on the same line (e.g. `cat <<EOF >> out`) are still real
194
+ // command tokens that must be scanned before the body is skipped.
195
+ heredocAwaitNewline = true;
196
+ return;
197
+ }
198
+ toks.push({ kind: "word", value });
199
+ };
200
+ while (i < n) {
201
+ if (inHeredoc) {
202
+ const nl = command.indexOf("\n", i);
203
+ const lineEnd = nl === -1 ? n : nl;
204
+ if (command.slice(i, lineEnd).trim() === heredocDelim)
205
+ inHeredoc = false;
206
+ i = nl === -1 ? n : nl + 1;
207
+ continue;
208
+ }
209
+ const c = command[i];
210
+ if (c === "\n" || c === "\r") {
211
+ if (heredocAwaitNewline) {
212
+ heredocAwaitNewline = false;
213
+ inHeredoc = true;
214
+ }
215
+ i++;
216
+ continue;
217
+ }
218
+ if (c === " " || c === "\t") {
219
+ i++;
220
+ continue;
221
+ }
222
+ if (c === "#") {
223
+ while (i < n && command[i] !== "\n")
224
+ i++;
225
+ continue;
226
+ }
227
+ if (c === ">" || c === "<") {
228
+ const next = command[i + 1];
229
+ if (next === c) {
230
+ toks.push({ kind: "op", op: c + c });
231
+ if (c === "<")
232
+ heredocPending = true;
233
+ i += 2;
234
+ }
235
+ else if (next === "&") {
236
+ toks.push({ kind: "op", op: c + "&" });
237
+ i += 2;
238
+ }
239
+ else {
240
+ toks.push({ kind: "op", op: c });
241
+ i++;
242
+ }
243
+ continue;
244
+ }
245
+ if (c === "|" || c === "&") {
246
+ toks.push({ kind: "op", op: command[i + 1] === c ? c + c : c });
247
+ i += command[i + 1] === c ? 2 : 1;
248
+ continue;
249
+ }
250
+ if (c === ";" || c === "(" || c === ")") {
251
+ toks.push({ kind: "op", op: c });
252
+ i++;
253
+ continue;
254
+ }
255
+ if (c === "'") {
256
+ const end = command.indexOf("'", i + 1);
257
+ pushWord(end === -1 ? command.slice(i + 1) : command.slice(i + 1, end));
258
+ i = end === -1 ? n : end + 1;
259
+ continue;
260
+ }
261
+ if (c === '"') {
262
+ let j = i + 1;
263
+ let value = "";
264
+ while (j < n && command[j] !== '"') {
265
+ if (command[j] === "\\" && j + 1 < n) {
266
+ value += command[j + 1];
267
+ j += 2;
268
+ }
269
+ else {
270
+ value += command[j];
271
+ j++;
272
+ }
273
+ }
274
+ pushWord(value);
275
+ i = j < n ? j + 1 : n;
276
+ continue;
277
+ }
278
+ if (c === "\\") {
279
+ pushWord(i + 1 < n ? command[i + 1] : "");
280
+ i += 2;
281
+ continue;
282
+ }
283
+ if (c === "$" && command[i + 1] === "(") {
284
+ let depth = 1;
285
+ let j = i + 2;
286
+ while (j < n && depth > 0) {
287
+ if (command[j] === "(")
288
+ depth++;
289
+ else if (command[j] === ")")
290
+ depth--;
291
+ j++;
292
+ }
293
+ toks.push({ kind: "sub", code: command.slice(i + 2, j - 1) });
294
+ i = j;
295
+ continue;
296
+ }
297
+ if (c === "`") {
298
+ const end = command.indexOf("`", i + 1);
299
+ toks.push({ kind: "sub", code: command.slice(i + 1, end === -1 ? n : end) });
300
+ i = end === -1 ? n : end + 1;
301
+ continue;
302
+ }
303
+ let j = i;
304
+ while (j < n && !WORD_STOP.includes(command[j]))
305
+ j++;
306
+ pushWord(command.slice(i, j));
307
+ i = j;
308
+ }
309
+ return toks;
310
+ }
311
+ /**
312
+ * Write targets a bash command would touch.
313
+ *
314
+ * Quote-aware tokenizer (not a full shell parser): it catches redirection
315
+ * (`>`, `>>`), `tee` outputs, `mv`/`cp`/`install` destinations, and `rm`
316
+ * arguments, recurses into `$(...)`/backtick substitutions and `sh -c`/`bash -c`
317
+ * code strings. It cannot see through `node -e "writeFileSync(...)"` or an
318
+ * aliased command.
319
+ */
320
+ const SHELL_COMMANDS = new Set(["bash", "sh", "zsh", "ksh", "dash", "fish", "/bin/bash", "/bin/sh", "env bash"]);
321
+ export function bashWriteTargets(command) {
322
+ const targets = new Set();
323
+ let pendingRedirect = false;
324
+ let fdDupTarget = false;
325
+ let segment = [];
326
+ const segments = [segment];
327
+ const visit = (code, depth = 0) => {
328
+ if (depth > 5)
329
+ return;
330
+ for (const t of tokenizeShell(code)) {
331
+ if (t.kind === "sub") {
332
+ pendingRedirect = false;
333
+ visit(t.code, depth + 1);
334
+ continue;
335
+ }
336
+ if (t.kind === "op") {
337
+ if (t.op === ">" || t.op === ">>") {
338
+ pendingRedirect = true;
339
+ }
340
+ else {
341
+ pendingRedirect = false;
342
+ }
343
+ // `2>&1` / `2>err.log`: a bare integer immediately before a redirect is
344
+ // an fd number, not a file argument.
345
+ if (/^\d+$/.test(segment[segment.length - 1] ?? ""))
346
+ segment.pop();
347
+ if (t.op === ">&" || t.op === "<&")
348
+ fdDupTarget = true;
349
+ if (t.op === "|" || t.op === ";" || t.op === "&&" || t.op === "||" || t.op === "(") {
350
+ segment = [];
351
+ segments.push(segment);
352
+ fdDupTarget = false;
353
+ }
354
+ continue;
355
+ }
356
+ if (pendingRedirect) {
357
+ if (!IGNORED_TARGETS.has(t.value))
358
+ targets.add(t.value);
359
+ pendingRedirect = false;
360
+ fdDupTarget = false;
361
+ continue;
362
+ }
363
+ if (fdDupTarget) {
364
+ fdDupTarget = false;
365
+ continue;
366
+ }
367
+ segment.push(t.value);
368
+ }
369
+ };
370
+ visit(command);
371
+ // `sh -c 'echo x > f'` hides the write inside a quoted code string.
372
+ for (const seg of segments) {
373
+ if (seg.length >= 3 && SHELL_COMMANDS.has(seg[0]) && seg[1] === "-c") {
374
+ visit(seg.slice(2).join(" "), 1);
375
+ }
376
+ }
377
+ for (const seg of segments) {
378
+ if (seg.length === 0)
379
+ continue;
380
+ const cmd = seg[0];
381
+ const args = seg.slice(1);
382
+ if (cmd === "tee") {
383
+ for (const arg of args)
384
+ if (!arg.startsWith("-") && !IGNORED_TARGETS.has(arg))
385
+ targets.add(arg);
386
+ }
387
+ else if (cmd === "rm" || cmd === "rmdir") {
388
+ for (const arg of args)
389
+ if (!arg.startsWith("-") && !IGNORED_TARGETS.has(arg))
390
+ targets.add(arg);
391
+ }
392
+ else if (cmd === "mv" || cmd === "cp" || cmd === "install") {
393
+ const dest = args[args.length - 1];
394
+ if (dest && !dest.startsWith("-") && !IGNORED_TARGETS.has(dest))
395
+ targets.add(dest);
396
+ }
397
+ }
398
+ return [...targets];
399
+ }
400
+ export function isBlockedOrchestratorCall(tool, args) {
401
+ if (tool === "bash") {
402
+ const command = typeof args?.command === "string"
403
+ ? args.command
404
+ : "";
405
+ if (!command)
406
+ return false;
407
+ if (BASH_FORBIDDEN.test(command))
408
+ return true;
409
+ return bashWriteTargets(command).some((target) => !isDevloomStatePath(target));
410
+ }
411
+ if (!WRITE_TOOLS.has(tool))
412
+ return false;
413
+ const filePath = typeof args?.filePath === "string"
414
+ ? args.filePath
415
+ : "";
416
+ return !isDevloomStatePath(filePath);
417
+ }
418
+ //# sourceMappingURL=guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guard.js","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"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"}
package/dist/loop.d.ts ADDED
@@ -0,0 +1,64 @@
1
+ export type LoopConfig = {
2
+ pattern: string;
3
+ cadence: string;
4
+ level: "L1" | "L2" | "L3";
5
+ paused: boolean;
6
+ mode?: "recurring" | "until-done";
7
+ progress?: UntilDoneProgress;
8
+ };
9
+ export type RunLogEntry = {
10
+ timestamp: string;
11
+ pattern: string;
12
+ agentsUsed: string[];
13
+ outcome: "success" | "failure" | "partial";
14
+ tokenCost: number;
15
+ durationMs: number;
16
+ error?: string;
17
+ };
18
+ export type Budget = {
19
+ dailyLimit: number;
20
+ spent: number;
21
+ resetAt: string;
22
+ };
23
+ export type IssueCategory = "ui" | "functional" | "missing-action" | "broken-action" | "api" | "state";
24
+ export type IssueSeverity = "critical" | "high" | "medium" | "low";
25
+ export type UntilDoneItem = {
26
+ id: string;
27
+ status: "pending" | "in-progress" | "done" | "verified";
28
+ category?: IssueCategory;
29
+ severity?: IssueSeverity;
30
+ data?: Record<string, unknown>;
31
+ };
32
+ export type UntilDoneProgress = {
33
+ items: UntilDoneItem[];
34
+ completionCondition: string;
35
+ total: number;
36
+ done: number;
37
+ verified: number;
38
+ };
39
+ export declare function loopWorkspaceDir(rootDir: string): string;
40
+ export declare function readLoopConfig(rootDir: string): LoopConfig;
41
+ export declare function writeLoopConfig(rootDir: string, config: LoopConfig): void;
42
+ export declare function readRunLog(rootDir: string, limit?: number): RunLogEntry[];
43
+ /** The loop runs on a cron cadence — cap the log so it cannot grow forever. */
44
+ export declare const RUN_LOG_MAX_ENTRIES = 200;
45
+ export declare function appendRunLog(rootDir: string, entry: RunLogEntry): void;
46
+ export declare function readBudget(rootDir: string): Budget;
47
+ export declare function writeBudget(rootDir: string, budget: Budget): void;
48
+ export declare function checkBudget(rootDir: string): {
49
+ allowed: boolean;
50
+ remaining: number;
51
+ resetAt: string;
52
+ };
53
+ export declare function recordSpend(rootDir: string, tokens: number): void;
54
+ export declare function shouldPause(rootDir: string): boolean;
55
+ export declare function ensureLoopWorkspace(rootDir: string): void;
56
+ export declare function progressFilePath(rootDir: string): string;
57
+ export declare function readProgress(rootDir: string): UntilDoneProgress | null;
58
+ export declare function writeProgress(rootDir: string, progress: UntilDoneProgress): void;
59
+ export declare function initUntilDoneProgress(items: UntilDoneItem[], condition: string): UntilDoneProgress;
60
+ export declare function updateProgressItem(progress: UntilDoneProgress, id: string, status: UntilDoneItem["status"]): UntilDoneProgress;
61
+ export declare function checkCompletionCondition(progress: UntilDoneProgress): boolean;
62
+ export declare function progressByCategory(progress: UntilDoneProgress): Record<string, number>;
63
+ export declare function readLoopStateSummary(rootDir: string): string;
64
+ //# sourceMappingURL=loop.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../src/loop.ts"],"names":[],"mappings":"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"}