@bpinternal/overwatch 0.1.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/LICENSE +21 -0
- package/README.md +451 -0
- package/dist/actuators/actuator.d.ts +13 -0
- package/dist/actuators/actuator.js +30 -0
- package/dist/actuators/actuator.js.map +7 -0
- package/dist/actuators/agent-pr.d.ts +25 -0
- package/dist/actuators/agent-pr.js +119 -0
- package/dist/actuators/agent-pr.js.map +7 -0
- package/dist/actuators/comments.d.ts +3 -0
- package/dist/actuators/comments.js +42 -0
- package/dist/actuators/comments.js.map +7 -0
- package/dist/actuators/index.d.ts +54 -0
- package/dist/actuators/index.js +40 -0
- package/dist/actuators/index.js.map +7 -0
- package/dist/actuators/instructions.d.ts +9 -0
- package/dist/actuators/instructions.js +62 -0
- package/dist/actuators/instructions.js.map +7 -0
- package/dist/actuators.d.ts +72 -0
- package/dist/actuators.js +173 -0
- package/dist/actuators.js.map +7 -0
- package/dist/agents.d.ts +53 -0
- package/dist/agents.js +107 -0
- package/dist/agents.js.map +7 -0
- package/dist/claims.d.ts +16 -0
- package/dist/claims.js +51 -0
- package/dist/claims.js.map +7 -0
- package/dist/cli.d.ts +13 -0
- package/dist/cli.js +94 -0
- package/dist/cli.js.map +7 -0
- package/dist/control-loop.d.ts +50 -0
- package/dist/control-loop.js +285 -0
- package/dist/control-loop.js.map +7 -0
- package/dist/github.d.ts +98 -0
- package/dist/github.js +258 -0
- package/dist/github.js.map +7 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +69 -0
- package/dist/index.js.map +7 -0
- package/dist/log.d.ts +22 -0
- package/dist/log.js +87 -0
- package/dist/log.js.map +7 -0
- package/dist/pickers/busiest-file.d.ts +9 -0
- package/dist/pickers/busiest-file.js +48 -0
- package/dist/pickers/busiest-file.js.map +7 -0
- package/dist/pickers/count.d.ts +6 -0
- package/dist/pickers/count.js +29 -0
- package/dist/pickers/count.js.map +7 -0
- package/dist/pickers/index.d.ts +12 -0
- package/dist/pickers/index.js +41 -0
- package/dist/pickers/index.js.map +7 -0
- package/dist/pickers.d.ts +21 -0
- package/dist/pickers.js +61 -0
- package/dist/pickers.js.map +7 -0
- package/dist/repo-handle.d.ts +35 -0
- package/dist/repo-handle.js +75 -0
- package/dist/repo-handle.js.map +7 -0
- package/dist/sandbox.d.ts +33 -0
- package/dist/sandbox.js +91 -0
- package/dist/sandbox.js.map +7 -0
- package/dist/sensors/ast-grep.d.ts +41 -0
- package/dist/sensors/ast-grep.js +65 -0
- package/dist/sensors/ast-grep.js.map +7 -0
- package/dist/sensors/grep.d.ts +31 -0
- package/dist/sensors/grep.js +39 -0
- package/dist/sensors/grep.js.map +7 -0
- package/dist/sensors/index.d.ts +27 -0
- package/dist/sensors/index.js +38 -0
- package/dist/sensors/index.js.map +7 -0
- package/dist/sensors/react-doctor.d.ts +43 -0
- package/dist/sensors/react-doctor.js +71 -0
- package/dist/sensors/react-doctor.js.map +7 -0
- package/dist/sensors/script.d.ts +7 -0
- package/dist/sensors/script.js +32 -0
- package/dist/sensors/script.js.map +7 -0
- package/dist/sensors.d.ts +117 -0
- package/dist/sensors.js +126 -0
- package/dist/sensors.js.map +7 -0
- package/dist/types.d.ts +119 -0
- package/dist/types.js +17 -0
- package/dist/types.js.map +7 -0
- package/package.json +64 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/actuators/agent-pr.ts"],
|
|
4
|
+
"sourcesContent": ["import type { AgentContext } from \"../agents\";\nimport type { RunLog } from \"../log\";\nimport type { ControlLoopConfig, ControlLoopRunResult, Signal } from \"../types\";\nimport { claimMarker, signalKey } from \"../claims\";\nimport {\n REPO_PATH,\n SCRATCH_DIR,\n commitAll,\n memoryNote,\n readMemory,\n runConfiguredCommand,\n} from \"../sandbox\";\nimport { Actuator } from \"./actuator\";\nimport type { ActuatorInput, InstructionBuilder } from \"./index\";\nimport { fromSignal } from \"./instructions\";\n\nexport interface AgentPrActuatorProps {\n /** Builds the agent's instructions per signal. Defaults to {@link fromSignal}. */\n instructions?: InstructionBuilder;\n}\n\n/**\n * The default actuator: for each picked signal it runs the configured coding agent, then\n * re-senses to verify the signal is gone (retrying up to `config.maxFixAttempts`), and\n * finally commits every fix to a fresh branch and opens one PR \u2014 claiming the signals it\n * fixed in the PR body so concurrent runs don't duplicate the work.\n *\n * This is the behavior the loop used to hard-code; it's now a swappable actuator.\n */\nexport class AgentPrActuator<TData = unknown> extends Actuator<TData> {\n private readonly instructions: InstructionBuilder;\n\n constructor(props: AgentPrActuatorProps = {}) {\n super();\n this.instructions = props.instructions ?? fromSignal();\n }\n\n async act(input: ActuatorInput<TData>): Promise<ControlLoopRunResult<TData>> {\n const { signals: picked, sandbox, ctx, sense, config, log, label, displayLabel } = input;\n\n const prefix = (config.branchPrefix ?? \"control-loop\").replace(/\\/+$/, \"\");\n const branch = `${prefix}/${label}-${Date.now().toString(36)}`;\n await log.step(`checking out branch ${branch}`, async () => {\n await sandbox.git.createBranch(REPO_PATH, branch);\n await sandbox.git.checkoutBranch(REPO_PATH, branch);\n });\n\n await log.step(\"preparing agent\", () => config.agent.prepare(ctx));\n\n const memory = await readMemory(ctx, label);\n const unresolved = await this.runFixLoop(picked, ctx, sense, memory, log, config);\n if (unresolved.length > 0) {\n log.finish(`fix failed \u2014 ${unresolved.length} signal(s) still present`);\n return { status: \"fix-failed\", unresolved };\n }\n\n // The scratch dir holds prompts and sensor scripts; it must not end up in the PR.\n await ctx.exec(`rm -rf ${SCRATCH_DIR}`);\n await runConfiguredCommand(\"preCommit\", config, ctx, log);\n await log.step(\"committing & pushing\", async () => {\n await commitAll(ctx, prTitle(displayLabel, picked));\n await config.git.push(sandbox, REPO_PATH, branch);\n });\n\n const prUrl = await log.step(\"opening pull request\", () =>\n config.git.openPr({\n branch,\n label,\n title: prTitle(displayLabel, picked),\n body: prBody(displayLabel, picked),\n }),\n );\n log.finish(`PR opened \u2192 ${prUrl}`);\n return { status: \"pr-opened\", prUrl, fixed: picked };\n }\n\n /**\n * Runs the agent on each signal, then re-senses to verify. Signals still reported\n * by the sensor get retried (with a nudge appended) up to maxFixAttempts times.\n */\n private async runFixLoop(\n picked: Signal<TData>[],\n ctx: AgentContext,\n sense: () => Promise<Signal<TData>[]>,\n memory: string | undefined,\n log: RunLog,\n config: ControlLoopConfig,\n ): Promise<Signal<TData>[]> {\n const maxAttempts = config.maxFixAttempts ?? 3;\n let remaining = picked;\n let iteration = 0;\n\n for (let attempt = 1; attempt <= maxAttempts && remaining.length > 0; attempt++) {\n for (const signal of remaining) {\n const { instructions } = await this.instructions(signal);\n const retryNote =\n attempt === 1\n ? \"\"\n : \"\\n\\nA previous attempt did not resolve this issue \u2014 the sensor still reports it. Look again and try a different approach.\";\n const where = signalWhere(signal) || signal.message;\n iteration++;\n await log.step(`agent fixing ${where} (iteration ${iteration})`, () =>\n config.agent.executeAgent(instructions + retryNote + memoryNote(memory), ctx),\n );\n }\n\n const stillPresent = new Set((await log.step(\"re-sensing to verify\", sense)).map(signalKey));\n remaining = remaining.filter((signal) => stillPresent.has(signalKey(signal)));\n }\n\n return remaining;\n }\n}\n\n/** \"file:line\", \"file\", or \"\" \u2014 the human-readable location of a signal, if it has one. */\nfunction signalWhere(signal: Signal): string {\n const { location } = signal;\n if (!location) return \"\";\n return `${location.file}${location.line ? `:${location.line}` : \"\"}`;\n}\n\nfunction prTitle(label: string, fixed: Signal[]): string {\n return fixed.length === 1 ? `fix: ${fixed[0]!.message}` : `fix: ${label}: ${fixed.length} issues`;\n}\n\nfunction prBody(label: string, fixed: Signal[]): string {\n const lines = fixed.map((signal) => {\n const where = signalWhere(signal);\n const priority = signal.priority ? ` (${signal.priority})` : \"\";\n return `- ${where ? `\\`${where}\\` \u2014 ` : \"\"}${signal.message}${priority}`;\n });\n return [\n `Automated fix opened by the **${label}** control loop.`,\n \"\",\n \"Signals resolved (verified by re-running the sensor):\",\n ...lines,\n \"\",\n claimMarker(fixed),\n ].join(\"\\n\");\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var comments_exports = {};
|
|
20
|
+
__export(comments_exports, {
|
|
21
|
+
prComments: () => prComments
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(comments_exports);
|
|
24
|
+
const prComments = (comments) => {
|
|
25
|
+
const lines = comments.map(
|
|
26
|
+
(comment) => comment.file ? `- ${comment.author} on \`${comment.file}${comment.line ? `:${comment.line}` : ""}\`: ${comment.body}` : `- ${comment.author} (PR-level): ${comment.body}`
|
|
27
|
+
);
|
|
28
|
+
return {
|
|
29
|
+
instructions: [
|
|
30
|
+
"You are addressing review comments left on a pull request. Apply each comment's feedback to the code.",
|
|
31
|
+
"Keep changes minimal and scoped to what the comments ask \u2014 do not refactor or fix anything else.",
|
|
32
|
+
"",
|
|
33
|
+
"Comments to address:",
|
|
34
|
+
...lines
|
|
35
|
+
].join("\n")
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
39
|
+
0 && (module.exports = {
|
|
40
|
+
prComments
|
|
41
|
+
});
|
|
42
|
+
//# sourceMappingURL=comments.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/actuators/comments.ts"],
|
|
4
|
+
"sourcesContent": ["import type { PrComment } from \"../github\";\nimport type { CommentActuator } from \"./index\";\n\n/** Default comment actuator used by `applyPrComments` when none is configured. */\nexport const prComments: CommentActuator = (comments: PrComment[]) => {\n const lines = comments.map((comment) =>\n comment.file\n ? `- ${comment.author} on \\`${comment.file}${comment.line ? `:${comment.line}` : \"\"}\\`: ${comment.body}`\n : `- ${comment.author} (PR-level): ${comment.body}`,\n );\n return {\n instructions: [\n \"You are addressing review comments left on a pull request. Apply each comment's feedback to the code.\",\n \"Keep changes minimal and scoped to what the comments ask \u2014 do not refactor or fix anything else.\",\n \"\",\n \"Comments to address:\",\n ...lines,\n ].join(\"\\n\"),\n };\n};\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAIO,MAAM,aAA8B,CAAC,aAA0B;AACpE,QAAM,QAAQ,SAAS;AAAA,IAAI,CAAC,YAC1B,QAAQ,OACJ,KAAK,QAAQ,MAAM,SAAS,QAAQ,IAAI,GAAG,QAAQ,OAAO,IAAI,QAAQ,IAAI,KAAK,EAAE,OAAO,QAAQ,IAAI,KACpG,KAAK,QAAQ,MAAM,gBAAgB,QAAQ,IAAI;AAAA,EACrD;AACA,SAAO;AAAA,IACL,cAAc;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG;AAAA,IACL,EAAE,KAAK,IAAI;AAAA,EACb;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { Sandbox } from "@daytona/sdk";
|
|
2
|
+
import type { AgentContext } from "../agents";
|
|
3
|
+
import type { PrComment } from "../github";
|
|
4
|
+
import type { RunLog } from "../log";
|
|
5
|
+
import type { ControlLoopConfig, Signal } from "../types";
|
|
6
|
+
/**
|
|
7
|
+
* Builds the instructions handed to the agent for one signal. Feeds the default
|
|
8
|
+
* {@link Actuator} (`actuators.AgentPrActuator`) — the actuator calls it once per signal
|
|
9
|
+
* to produce the prompt the coding agent runs with. Create one with `actuators.fromFile`
|
|
10
|
+
* or `actuators.fromSignal`.
|
|
11
|
+
*/
|
|
12
|
+
export type InstructionBuilder<TData = unknown> = (signal: Signal<TData>) => Promise<{
|
|
13
|
+
instructions: string;
|
|
14
|
+
}> | {
|
|
15
|
+
instructions: string;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Builds the instructions handed to the agent when applying PR review comments.
|
|
19
|
+
* Optional — the loop has a sensible default.
|
|
20
|
+
*/
|
|
21
|
+
export type CommentActuator = (comments: PrComment[]) => Promise<{
|
|
22
|
+
instructions: string;
|
|
23
|
+
}> | {
|
|
24
|
+
instructions: string;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Everything an actuator needs to act on the run's picked signals. The sandbox is fully
|
|
28
|
+
* provisioned (repo cloned, git configured, `config.hooks.setup` already run).
|
|
29
|
+
*
|
|
30
|
+
* Note `sandbox` is exposed directly — unlike agents, which only ever see {@link AgentContext} —
|
|
31
|
+
* because an actuator is the layer allowed to drive git (branch, push) and open PRs.
|
|
32
|
+
*/
|
|
33
|
+
export interface ActuatorInput<TData = unknown> {
|
|
34
|
+
/** The signals the picker selected to act on this run. */
|
|
35
|
+
signals: Signal<TData>[];
|
|
36
|
+
/** The provisioned sandbox. */
|
|
37
|
+
sandbox: Sandbox;
|
|
38
|
+
/** Narrow exec/writeFile surface into the sandbox, with the repo root as cwd. */
|
|
39
|
+
ctx: AgentContext;
|
|
40
|
+
/** Re-runs the sensor — actuators that fix-then-verify use this to confirm resolution. */
|
|
41
|
+
sense: () => Promise<Signal<TData>[]>;
|
|
42
|
+
/** The loop's static configuration. */
|
|
43
|
+
config: ControlLoopConfig;
|
|
44
|
+
/** Slugified loop label — used for the branch, PR label, and memory file. */
|
|
45
|
+
label: string;
|
|
46
|
+
/** Human-readable loop label — used in PR titles and bodies. */
|
|
47
|
+
displayLabel: string;
|
|
48
|
+
/** The run's logger. */
|
|
49
|
+
log: RunLog;
|
|
50
|
+
}
|
|
51
|
+
export { Actuator } from "./actuator";
|
|
52
|
+
export { AgentPrActuator, type AgentPrActuatorProps } from "./agent-pr";
|
|
53
|
+
export { fromFile, fromSignal } from "./instructions";
|
|
54
|
+
export { prComments } from "./comments";
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var actuators_exports = {};
|
|
20
|
+
__export(actuators_exports, {
|
|
21
|
+
Actuator: () => import_actuator.Actuator,
|
|
22
|
+
AgentPrActuator: () => import_agent_pr.AgentPrActuator,
|
|
23
|
+
fromFile: () => import_instructions.fromFile,
|
|
24
|
+
fromSignal: () => import_instructions.fromSignal,
|
|
25
|
+
prComments: () => import_comments.prComments
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(actuators_exports);
|
|
28
|
+
var import_actuator = require("./actuator");
|
|
29
|
+
var import_agent_pr = require("./agent-pr");
|
|
30
|
+
var import_instructions = require("./instructions");
|
|
31
|
+
var import_comments = require("./comments");
|
|
32
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
33
|
+
0 && (module.exports = {
|
|
34
|
+
Actuator,
|
|
35
|
+
AgentPrActuator,
|
|
36
|
+
fromFile,
|
|
37
|
+
fromSignal,
|
|
38
|
+
prComments
|
|
39
|
+
});
|
|
40
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/actuators/index.ts"],
|
|
4
|
+
"sourcesContent": ["import type { Sandbox } from \"@daytona/sdk\";\nimport type { AgentContext } from \"../agents\";\nimport type { PrComment } from \"../github\";\nimport type { RunLog } from \"../log\";\nimport type { ControlLoopConfig, Signal } from \"../types\";\n\n/**\n * Builds the instructions handed to the agent for one signal. Feeds the default\n * {@link Actuator} (`actuators.AgentPrActuator`) \u2014 the actuator calls it once per signal\n * to produce the prompt the coding agent runs with. Create one with `actuators.fromFile`\n * or `actuators.fromSignal`.\n */\nexport type InstructionBuilder<TData = unknown> = (\n signal: Signal<TData>,\n) => Promise<{ instructions: string }> | { instructions: string };\n\n/**\n * Builds the instructions handed to the agent when applying PR review comments.\n * Optional \u2014 the loop has a sensible default.\n */\nexport type CommentActuator = (\n comments: PrComment[],\n) => Promise<{ instructions: string }> | { instructions: string };\n\n/**\n * Everything an actuator needs to act on the run's picked signals. The sandbox is fully\n * provisioned (repo cloned, git configured, `config.hooks.setup` already run).\n *\n * Note `sandbox` is exposed directly \u2014 unlike agents, which only ever see {@link AgentContext} \u2014\n * because an actuator is the layer allowed to drive git (branch, push) and open PRs.\n */\nexport interface ActuatorInput<TData = unknown> {\n /** The signals the picker selected to act on this run. */\n signals: Signal<TData>[];\n /** The provisioned sandbox. */\n sandbox: Sandbox;\n /** Narrow exec/writeFile surface into the sandbox, with the repo root as cwd. */\n ctx: AgentContext;\n /** Re-runs the sensor \u2014 actuators that fix-then-verify use this to confirm resolution. */\n sense: () => Promise<Signal<TData>[]>;\n /** The loop's static configuration. */\n config: ControlLoopConfig;\n /** Slugified loop label \u2014 used for the branch, PR label, and memory file. */\n label: string;\n /** Human-readable loop label \u2014 used in PR titles and bodies. */\n displayLabel: string;\n /** The run's logger. */\n log: RunLog;\n}\n\n// The abstract base lives in its own module (not inline here) so the sibling default\n// implementations can `extends Actuator` without forming a require-cycle with this\n// barrel \u2014 under the CommonJS build a subclass that imported its base from the barrel,\n// which in turn re-exports the subclass, would hit the base in its temporal dead zone.\nexport { Actuator } from \"./actuator\";\nexport { AgentPrActuator, type AgentPrActuatorProps } from \"./agent-pr\";\nexport { fromFile, fromSignal } from \"./instructions\";\nexport { prComments } from \"./comments\";\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsDA,sBAAyB;AACzB,sBAA2D;AAC3D,0BAAqC;AACrC,sBAA2B;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { InstructionBuilder } from "./index";
|
|
2
|
+
/**
|
|
3
|
+
* Instruction builder that reads a local file (markdown, plain text, ...) and uses its
|
|
4
|
+
* contents as the instructions for every signal, with the signal's details appended. The
|
|
5
|
+
* file is read once per process and cached.
|
|
6
|
+
*/
|
|
7
|
+
export declare const fromFile: (localPath: string) => InstructionBuilder;
|
|
8
|
+
/** Minimal instruction builder: instructions built from the signal itself, nothing else. */
|
|
9
|
+
export declare const fromSignal: () => InstructionBuilder;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var instructions_exports = {};
|
|
20
|
+
__export(instructions_exports, {
|
|
21
|
+
fromFile: () => fromFile,
|
|
22
|
+
fromSignal: () => fromSignal
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(instructions_exports);
|
|
25
|
+
var import_promises = require("node:fs/promises");
|
|
26
|
+
const fromFile = (localPath) => {
|
|
27
|
+
let cached;
|
|
28
|
+
return async (signal) => {
|
|
29
|
+
cached ??= await (0, import_promises.readFile)(localPath, "utf-8");
|
|
30
|
+
const where = signal.location ? `In ${signal.location.file}${signal.location.line ? ` around line ${signal.location.line}` : ""}:
|
|
31
|
+
` : "";
|
|
32
|
+
return {
|
|
33
|
+
instructions: `${where}${cached.trimEnd()}
|
|
34
|
+
|
|
35
|
+
${signalContext(signal)}`
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
const fromSignal = () => (signal) => ({
|
|
40
|
+
instructions: [
|
|
41
|
+
"Fix the following issue detected in this codebase. Make the smallest change that resolves it;",
|
|
42
|
+
"do not fix unrelated issues or refactor unrelated code.",
|
|
43
|
+
"",
|
|
44
|
+
signalContext(signal)
|
|
45
|
+
].join("\n")
|
|
46
|
+
});
|
|
47
|
+
function signalContext(signal) {
|
|
48
|
+
const lines = ["Issue to fix:"];
|
|
49
|
+
if (signal.location) {
|
|
50
|
+
const { file, line } = signal.location;
|
|
51
|
+
lines.push(`- Location: ${line ? `${file}:${line}` : file}`);
|
|
52
|
+
}
|
|
53
|
+
lines.push(`- Description: ${signal.message}`);
|
|
54
|
+
if (signal.priority) lines.push(`- Priority: ${signal.priority}`);
|
|
55
|
+
return lines.join("\n");
|
|
56
|
+
}
|
|
57
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
58
|
+
0 && (module.exports = {
|
|
59
|
+
fromFile,
|
|
60
|
+
fromSignal
|
|
61
|
+
});
|
|
62
|
+
//# sourceMappingURL=instructions.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/actuators/instructions.ts"],
|
|
4
|
+
"sourcesContent": ["import { readFile } from \"node:fs/promises\";\nimport type { Signal } from \"../types\";\nimport type { InstructionBuilder } from \"./index\";\n\n/**\n * Instruction builder that reads a local file (markdown, plain text, ...) and uses its\n * contents as the instructions for every signal, with the signal's details appended. The\n * file is read once per process and cached.\n */\nexport const fromFile = (localPath: string): InstructionBuilder => {\n let cached: string | undefined;\n return async (signal) => {\n cached ??= await readFile(localPath, \"utf-8\");\n const where = signal.location\n ? `In ${signal.location.file}${signal.location.line ? ` around line ${signal.location.line}` : \"\"}: \\n`\n : \"\";\n return {\n instructions: `${where}${cached.trimEnd()}\\n\\n${signalContext(signal)}`,\n };\n };\n};\n\n/** Minimal instruction builder: instructions built from the signal itself, nothing else. */\nexport const fromSignal = (): InstructionBuilder => (signal) => ({\n instructions: [\n \"Fix the following issue detected in this codebase. Make the smallest change that resolves it;\",\n \"do not fix unrelated issues or refactor unrelated code.\",\n \"\",\n signalContext(signal),\n ].join(\"\\n\"),\n});\n\nfunction signalContext(signal: Signal): string {\n const lines = [\"Issue to fix:\"];\n if (signal.location) {\n const { file, line } = signal.location;\n lines.push(`- Location: ${line ? `${file}:${line}` : file}`);\n }\n lines.push(`- Description: ${signal.message}`);\n if (signal.priority) lines.push(`- Priority: ${signal.priority}`);\n return lines.join(\"\\n\");\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAAyB;AASlB,MAAM,WAAW,CAAC,cAA0C;AACjE,MAAI;AACJ,SAAO,OAAO,WAAW;AACvB,eAAW,UAAM,0BAAS,WAAW,OAAO;AAC5C,UAAM,QAAQ,OAAO,WACjB,MAAM,OAAO,SAAS,IAAI,GAAG,OAAO,SAAS,OAAO,gBAAgB,OAAO,SAAS,IAAI,KAAK,EAAE;AAAA,IAC/F;AACJ,WAAO;AAAA,MACL,cAAc,GAAG,KAAK,GAAG,OAAO,QAAQ,CAAC;AAAA;AAAA,EAAO,cAAc,MAAM,CAAC;AAAA,IACvE;AAAA,EACF;AACF;AAGO,MAAM,aAAa,MAA0B,CAAC,YAAY;AAAA,EAC/D,cAAc;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAc,MAAM;AAAA,EACtB,EAAE,KAAK,IAAI;AACb;AAEA,SAAS,cAAc,QAAwB;AAC7C,QAAM,QAAQ,CAAC,eAAe;AAC9B,MAAI,OAAO,UAAU;AACnB,UAAM,EAAE,MAAM,KAAK,IAAI,OAAO;AAC9B,UAAM,KAAK,eAAe,OAAO,GAAG,IAAI,IAAI,IAAI,KAAK,IAAI,EAAE;AAAA,EAC7D;AACA,QAAM,KAAK,kBAAkB,OAAO,OAAO,EAAE;AAC7C,MAAI,OAAO,SAAU,OAAM,KAAK,eAAe,OAAO,QAAQ,EAAE;AAChE,SAAO,MAAM,KAAK,IAAI;AACxB;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { Sandbox } from "@daytona/sdk";
|
|
2
|
+
import type { AgentContext } from "./agents";
|
|
3
|
+
import type { RunLog } from "./log";
|
|
4
|
+
import type { CommentActuator, ControlLoopConfig, ControlLoopRunResult, InstructionBuilder, Signal } from "./types";
|
|
5
|
+
/**
|
|
6
|
+
* Actuator that reads a local file (markdown, plain text, ...) and uses its contents
|
|
7
|
+
* as the instructions for every signal, with the signal's details appended. The file
|
|
8
|
+
* is read once per process and cached.
|
|
9
|
+
*/
|
|
10
|
+
export declare const fromFile: (localPath: string) => InstructionBuilder;
|
|
11
|
+
/** Minimal instruction builder: instructions built from the signal itself, nothing else. */
|
|
12
|
+
export declare const fromSignal: () => InstructionBuilder;
|
|
13
|
+
/** Default comment actuator used by `applyPrComments` when none is configured. */
|
|
14
|
+
export declare const prComments: CommentActuator;
|
|
15
|
+
/**
|
|
16
|
+
* Everything an actuator needs to act on the run's picked signals. The sandbox is fully
|
|
17
|
+
* provisioned (repo cloned, git configured, `config.hooks.setup` already run).
|
|
18
|
+
*
|
|
19
|
+
* Note `sandbox` is exposed directly — unlike agents, which only ever see {@link AgentContext} —
|
|
20
|
+
* because an actuator is the layer allowed to drive git (branch, push) and open PRs.
|
|
21
|
+
*/
|
|
22
|
+
export interface ActuatorInput<TData = unknown> {
|
|
23
|
+
/** The signals the picker selected to act on this run. */
|
|
24
|
+
signals: Signal<TData>[];
|
|
25
|
+
/** The provisioned sandbox. */
|
|
26
|
+
sandbox: Sandbox;
|
|
27
|
+
/** Narrow exec/writeFile surface into the sandbox, with the repo root as cwd. */
|
|
28
|
+
ctx: AgentContext;
|
|
29
|
+
/** Re-runs the sensor — actuators that fix-then-verify use this to confirm resolution. */
|
|
30
|
+
sense: () => Promise<Signal<TData>[]>;
|
|
31
|
+
/** The loop's static configuration. */
|
|
32
|
+
config: ControlLoopConfig;
|
|
33
|
+
/** Slugified loop label — used for the branch, PR label, and memory file. */
|
|
34
|
+
label: string;
|
|
35
|
+
/** Human-readable loop label — used in PR titles and bodies. */
|
|
36
|
+
displayLabel: string;
|
|
37
|
+
/** The run's logger. */
|
|
38
|
+
log: RunLog;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Owns the "act on the picked signals" step of a run and reports the outcome. The loop
|
|
42
|
+
* senses, filters, and picks; the actuator decides what actually happens next.
|
|
43
|
+
*
|
|
44
|
+
* The default {@link AgentPrActuator} runs a coding agent per signal, verifies via
|
|
45
|
+
* re-sensing, and opens a PR — but an actuator is free to do anything (post a message,
|
|
46
|
+
* write a report, call an API) and need not touch an agent or open a PR at all.
|
|
47
|
+
*/
|
|
48
|
+
export declare abstract class Actuator<TData = unknown> {
|
|
49
|
+
abstract act(input: ActuatorInput<TData>): Promise<ControlLoopRunResult<TData>>;
|
|
50
|
+
}
|
|
51
|
+
export interface AgentPrActuatorProps {
|
|
52
|
+
/** Builds the agent's instructions per signal. Defaults to {@link fromSignal}. */
|
|
53
|
+
instructions?: InstructionBuilder;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The default actuator: for each picked signal it runs the configured coding agent, then
|
|
57
|
+
* re-senses to verify the signal is gone (retrying up to `config.maxFixAttempts`), and
|
|
58
|
+
* finally commits every fix to a fresh branch and opens one PR — claiming the signals it
|
|
59
|
+
* fixed in the PR body so concurrent runs don't duplicate the work.
|
|
60
|
+
*
|
|
61
|
+
* This is the behavior the loop used to hard-code; it's now a swappable actuator.
|
|
62
|
+
*/
|
|
63
|
+
export declare class AgentPrActuator<TData = unknown> extends Actuator<TData> {
|
|
64
|
+
private readonly instructions;
|
|
65
|
+
constructor(props?: AgentPrActuatorProps);
|
|
66
|
+
act(input: ActuatorInput<TData>): Promise<ControlLoopRunResult<TData>>;
|
|
67
|
+
/**
|
|
68
|
+
* Runs the agent on each signal, then re-senses to verify. Signals still reported
|
|
69
|
+
* by the sensor get retried (with a nudge appended) up to maxFixAttempts times.
|
|
70
|
+
*/
|
|
71
|
+
private runFixLoop;
|
|
72
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var actuators_exports = {};
|
|
20
|
+
__export(actuators_exports, {
|
|
21
|
+
Actuator: () => Actuator,
|
|
22
|
+
AgentPrActuator: () => AgentPrActuator,
|
|
23
|
+
fromFile: () => fromFile,
|
|
24
|
+
fromSignal: () => fromSignal,
|
|
25
|
+
prComments: () => prComments
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(actuators_exports);
|
|
28
|
+
var import_promises = require("node:fs/promises");
|
|
29
|
+
var import_claims = require("./claims");
|
|
30
|
+
var import_sandbox = require("./sandbox");
|
|
31
|
+
const fromFile = (localPath) => {
|
|
32
|
+
let cached;
|
|
33
|
+
return async (signal) => {
|
|
34
|
+
cached ??= await (0, import_promises.readFile)(localPath, "utf-8");
|
|
35
|
+
const where = signal.location ? `In ${signal.location.file}${signal.location.line ? ` around line ${signal.location.line}` : ""}:
|
|
36
|
+
` : "";
|
|
37
|
+
return {
|
|
38
|
+
instructions: `${where}${cached.trimEnd()}
|
|
39
|
+
|
|
40
|
+
${signalContext(signal)}`
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
const fromSignal = () => (signal) => ({
|
|
45
|
+
instructions: [
|
|
46
|
+
"Fix the following issue detected in this codebase. Make the smallest change that resolves it;",
|
|
47
|
+
"do not fix unrelated issues or refactor unrelated code.",
|
|
48
|
+
"",
|
|
49
|
+
signalContext(signal)
|
|
50
|
+
].join("\n")
|
|
51
|
+
});
|
|
52
|
+
function signalContext(signal) {
|
|
53
|
+
const lines = ["Issue to fix:"];
|
|
54
|
+
if (signal.location) {
|
|
55
|
+
const { file, line } = signal.location;
|
|
56
|
+
lines.push(`- Location: ${line ? `${file}:${line}` : file}`);
|
|
57
|
+
}
|
|
58
|
+
lines.push(`- Description: ${signal.message}`);
|
|
59
|
+
if (signal.priority) lines.push(`- Priority: ${signal.priority}`);
|
|
60
|
+
return lines.join("\n");
|
|
61
|
+
}
|
|
62
|
+
const prComments = (comments) => {
|
|
63
|
+
const lines = comments.map(
|
|
64
|
+
(comment) => comment.file ? `- ${comment.author} on \`${comment.file}${comment.line ? `:${comment.line}` : ""}\`: ${comment.body}` : `- ${comment.author} (PR-level): ${comment.body}`
|
|
65
|
+
);
|
|
66
|
+
return {
|
|
67
|
+
instructions: [
|
|
68
|
+
"You are addressing review comments left on a pull request. Apply each comment's feedback to the code.",
|
|
69
|
+
"Keep changes minimal and scoped to what the comments ask \u2014 do not refactor or fix anything else.",
|
|
70
|
+
"",
|
|
71
|
+
"Comments to address:",
|
|
72
|
+
...lines
|
|
73
|
+
].join("\n")
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
class Actuator {
|
|
77
|
+
}
|
|
78
|
+
class AgentPrActuator extends Actuator {
|
|
79
|
+
instructions;
|
|
80
|
+
constructor(props = {}) {
|
|
81
|
+
super();
|
|
82
|
+
this.instructions = props.instructions ?? fromSignal();
|
|
83
|
+
}
|
|
84
|
+
async act(input) {
|
|
85
|
+
const { signals: picked, sandbox, ctx, sense, config, log, label, displayLabel } = input;
|
|
86
|
+
const prefix = (config.branchPrefix ?? "control-loop").replace(/\/+$/, "");
|
|
87
|
+
const branch = `${prefix}/${label}-${Date.now().toString(36)}`;
|
|
88
|
+
await log.step(`checking out branch ${branch}`, async () => {
|
|
89
|
+
await sandbox.git.createBranch(import_sandbox.REPO_PATH, branch);
|
|
90
|
+
await sandbox.git.checkoutBranch(import_sandbox.REPO_PATH, branch);
|
|
91
|
+
});
|
|
92
|
+
await log.step("preparing agent", () => config.agent.prepare(ctx));
|
|
93
|
+
const memory = await (0, import_sandbox.readMemory)(ctx, label);
|
|
94
|
+
const unresolved = await this.runFixLoop(picked, ctx, sense, memory, log, config);
|
|
95
|
+
if (unresolved.length > 0) {
|
|
96
|
+
log.finish(`fix failed \u2014 ${unresolved.length} signal(s) still present`);
|
|
97
|
+
return { status: "fix-failed", unresolved };
|
|
98
|
+
}
|
|
99
|
+
await ctx.exec(`rm -rf ${import_sandbox.SCRATCH_DIR}`);
|
|
100
|
+
await (0, import_sandbox.runConfiguredCommand)("preCommit", config, ctx, log);
|
|
101
|
+
await log.step("committing & pushing", async () => {
|
|
102
|
+
await (0, import_sandbox.commitAll)(ctx, prTitle(displayLabel, picked));
|
|
103
|
+
await config.git.push(sandbox, import_sandbox.REPO_PATH, branch);
|
|
104
|
+
});
|
|
105
|
+
const prUrl = await log.step(
|
|
106
|
+
"opening pull request",
|
|
107
|
+
() => config.git.openPr({
|
|
108
|
+
branch,
|
|
109
|
+
label,
|
|
110
|
+
title: prTitle(displayLabel, picked),
|
|
111
|
+
body: prBody(displayLabel, picked)
|
|
112
|
+
})
|
|
113
|
+
);
|
|
114
|
+
log.finish(`PR opened \u2192 ${prUrl}`);
|
|
115
|
+
return { status: "pr-opened", prUrl, fixed: picked };
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Runs the agent on each signal, then re-senses to verify. Signals still reported
|
|
119
|
+
* by the sensor get retried (with a nudge appended) up to maxFixAttempts times.
|
|
120
|
+
*/
|
|
121
|
+
async runFixLoop(picked, ctx, sense, memory, log, config) {
|
|
122
|
+
const maxAttempts = config.maxFixAttempts ?? 3;
|
|
123
|
+
let remaining = picked;
|
|
124
|
+
let iteration = 0;
|
|
125
|
+
for (let attempt = 1; attempt <= maxAttempts && remaining.length > 0; attempt++) {
|
|
126
|
+
for (const signal of remaining) {
|
|
127
|
+
const { instructions } = await this.instructions(signal);
|
|
128
|
+
const retryNote = attempt === 1 ? "" : "\n\nA previous attempt did not resolve this issue \u2014 the sensor still reports it. Look again and try a different approach.";
|
|
129
|
+
const where = signalWhere(signal) || signal.message;
|
|
130
|
+
iteration++;
|
|
131
|
+
await log.step(
|
|
132
|
+
`agent fixing ${where} (iteration ${iteration})`,
|
|
133
|
+
() => config.agent.executeAgent(instructions + retryNote + (0, import_sandbox.memoryNote)(memory), ctx)
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
const stillPresent = new Set((await log.step("re-sensing to verify", sense)).map(import_claims.signalKey));
|
|
137
|
+
remaining = remaining.filter((signal) => stillPresent.has((0, import_claims.signalKey)(signal)));
|
|
138
|
+
}
|
|
139
|
+
return remaining;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
function signalWhere(signal) {
|
|
143
|
+
const { location } = signal;
|
|
144
|
+
if (!location) return "";
|
|
145
|
+
return `${location.file}${location.line ? `:${location.line}` : ""}`;
|
|
146
|
+
}
|
|
147
|
+
function prTitle(label, fixed) {
|
|
148
|
+
return fixed.length === 1 ? `fix: ${fixed[0].message}` : `fix: ${label}: ${fixed.length} issues`;
|
|
149
|
+
}
|
|
150
|
+
function prBody(label, fixed) {
|
|
151
|
+
const lines = fixed.map((signal) => {
|
|
152
|
+
const where = signalWhere(signal);
|
|
153
|
+
const priority = signal.priority ? ` (${signal.priority})` : "";
|
|
154
|
+
return `- ${where ? `\`${where}\` \u2014 ` : ""}${signal.message}${priority}`;
|
|
155
|
+
});
|
|
156
|
+
return [
|
|
157
|
+
`Automated fix opened by the **${label}** control loop.`,
|
|
158
|
+
"",
|
|
159
|
+
"Signals resolved (verified by re-running the sensor):",
|
|
160
|
+
...lines,
|
|
161
|
+
"",
|
|
162
|
+
(0, import_claims.claimMarker)(fixed)
|
|
163
|
+
].join("\n");
|
|
164
|
+
}
|
|
165
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
166
|
+
0 && (module.exports = {
|
|
167
|
+
Actuator,
|
|
168
|
+
AgentPrActuator,
|
|
169
|
+
fromFile,
|
|
170
|
+
fromSignal,
|
|
171
|
+
prComments
|
|
172
|
+
});
|
|
173
|
+
//# sourceMappingURL=actuators.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/actuators.ts"],
|
|
4
|
+
"sourcesContent": ["import { readFile } from \"node:fs/promises\";\nimport type { Sandbox } from \"@daytona/sdk\";\nimport type { AgentContext } from \"./agents\";\nimport type { PrComment } from \"./github\";\nimport type { RunLog } from \"./log\";\nimport type {\n CommentActuator,\n ControlLoopConfig,\n ControlLoopRunResult,\n InstructionBuilder,\n Signal,\n} from \"./types\";\nimport { claimMarker, signalKey } from \"./claims\";\nimport {\n REPO_PATH,\n SCRATCH_DIR,\n commitAll,\n memoryNote,\n readMemory,\n runConfiguredCommand,\n} from \"./sandbox\";\n\n/**\n * Actuator that reads a local file (markdown, plain text, ...) and uses its contents\n * as the instructions for every signal, with the signal's details appended. The file\n * is read once per process and cached.\n */\nexport const fromFile = (localPath: string): InstructionBuilder => {\n let cached: string | undefined;\n return async (signal) => {\n cached ??= await readFile(localPath, \"utf-8\");\n const where = signal.location\n ? `In ${signal.location.file}${signal.location.line ? ` around line ${signal.location.line}` : \"\"}: \\n`\n : \"\";\n return {\n instructions: `${where}${cached.trimEnd()}\\n\\n${signalContext(signal)}`,\n };\n };\n};\n\n/** Minimal instruction builder: instructions built from the signal itself, nothing else. */\nexport const fromSignal = (): InstructionBuilder => (signal) => ({\n instructions: [\n \"Fix the following issue detected in this codebase. Make the smallest change that resolves it;\",\n \"do not fix unrelated issues or refactor unrelated code.\",\n \"\",\n signalContext(signal),\n ].join(\"\\n\"),\n});\n\nfunction signalContext(signal: Signal): string {\n const lines = [\"Issue to fix:\"];\n if (signal.location) {\n const { file, line } = signal.location;\n lines.push(`- Location: ${line ? `${file}:${line}` : file}`);\n }\n lines.push(`- Description: ${signal.message}`);\n if (signal.priority) lines.push(`- Priority: ${signal.priority}`);\n return lines.join(\"\\n\");\n}\n\n/** Default comment actuator used by `applyPrComments` when none is configured. */\nexport const prComments: CommentActuator = (comments: PrComment[]) => {\n const lines = comments.map((comment) =>\n comment.file\n ? `- ${comment.author} on \\`${comment.file}${comment.line ? `:${comment.line}` : \"\"}\\`: ${comment.body}`\n : `- ${comment.author} (PR-level): ${comment.body}`,\n );\n return {\n instructions: [\n \"You are addressing review comments left on a pull request. Apply each comment's feedback to the code.\",\n \"Keep changes minimal and scoped to what the comments ask \u2014 do not refactor or fix anything else.\",\n \"\",\n \"Comments to address:\",\n ...lines,\n ].join(\"\\n\"),\n };\n};\n\n/**\n * Everything an actuator needs to act on the run's picked signals. The sandbox is fully\n * provisioned (repo cloned, git configured, `config.hooks.setup` already run).\n *\n * Note `sandbox` is exposed directly \u2014 unlike agents, which only ever see {@link AgentContext} \u2014\n * because an actuator is the layer allowed to drive git (branch, push) and open PRs.\n */\nexport interface ActuatorInput<TData = unknown> {\n /** The signals the picker selected to act on this run. */\n signals: Signal<TData>[];\n /** The provisioned sandbox. */\n sandbox: Sandbox;\n /** Narrow exec/writeFile surface into the sandbox, with the repo root as cwd. */\n ctx: AgentContext;\n /** Re-runs the sensor \u2014 actuators that fix-then-verify use this to confirm resolution. */\n sense: () => Promise<Signal<TData>[]>;\n /** The loop's static configuration. */\n config: ControlLoopConfig;\n /** Slugified loop label \u2014 used for the branch, PR label, and memory file. */\n label: string;\n /** Human-readable loop label \u2014 used in PR titles and bodies. */\n displayLabel: string;\n /** The run's logger. */\n log: RunLog;\n}\n\n/**\n * Owns the \"act on the picked signals\" step of a run and reports the outcome. The loop\n * senses, filters, and picks; the actuator decides what actually happens next.\n *\n * The default {@link AgentPrActuator} runs a coding agent per signal, verifies via\n * re-sensing, and opens a PR \u2014 but an actuator is free to do anything (post a message,\n * write a report, call an API) and need not touch an agent or open a PR at all.\n */\nexport abstract class Actuator<TData = unknown> {\n abstract act(input: ActuatorInput<TData>): Promise<ControlLoopRunResult<TData>>;\n}\n\nexport interface AgentPrActuatorProps {\n /** Builds the agent's instructions per signal. Defaults to {@link fromSignal}. */\n instructions?: InstructionBuilder;\n}\n\n/**\n * The default actuator: for each picked signal it runs the configured coding agent, then\n * re-senses to verify the signal is gone (retrying up to `config.maxFixAttempts`), and\n * finally commits every fix to a fresh branch and opens one PR \u2014 claiming the signals it\n * fixed in the PR body so concurrent runs don't duplicate the work.\n *\n * This is the behavior the loop used to hard-code; it's now a swappable actuator.\n */\nexport class AgentPrActuator<TData = unknown> extends Actuator<TData> {\n private readonly instructions: InstructionBuilder;\n\n constructor(props: AgentPrActuatorProps = {}) {\n super();\n this.instructions = props.instructions ?? fromSignal();\n }\n\n async act(input: ActuatorInput<TData>): Promise<ControlLoopRunResult<TData>> {\n const { signals: picked, sandbox, ctx, sense, config, log, label, displayLabel } = input;\n\n const prefix = (config.branchPrefix ?? \"control-loop\").replace(/\\/+$/, \"\");\n const branch = `${prefix}/${label}-${Date.now().toString(36)}`;\n await log.step(`checking out branch ${branch}`, async () => {\n await sandbox.git.createBranch(REPO_PATH, branch);\n await sandbox.git.checkoutBranch(REPO_PATH, branch);\n });\n\n await log.step(\"preparing agent\", () => config.agent.prepare(ctx));\n\n const memory = await readMemory(ctx, label);\n const unresolved = await this.runFixLoop(picked, ctx, sense, memory, log, config);\n if (unresolved.length > 0) {\n log.finish(`fix failed \u2014 ${unresolved.length} signal(s) still present`);\n return { status: \"fix-failed\", unresolved };\n }\n\n // The scratch dir holds prompts and sensor scripts; it must not end up in the PR.\n await ctx.exec(`rm -rf ${SCRATCH_DIR}`);\n await runConfiguredCommand(\"preCommit\", config, ctx, log);\n await log.step(\"committing & pushing\", async () => {\n await commitAll(ctx, prTitle(displayLabel, picked));\n await config.git.push(sandbox, REPO_PATH, branch);\n });\n\n const prUrl = await log.step(\"opening pull request\", () =>\n config.git.openPr({\n branch,\n label,\n title: prTitle(displayLabel, picked),\n body: prBody(displayLabel, picked),\n }),\n );\n log.finish(`PR opened \u2192 ${prUrl}`);\n return { status: \"pr-opened\", prUrl, fixed: picked };\n }\n\n /**\n * Runs the agent on each signal, then re-senses to verify. Signals still reported\n * by the sensor get retried (with a nudge appended) up to maxFixAttempts times.\n */\n private async runFixLoop(\n picked: Signal<TData>[],\n ctx: AgentContext,\n sense: () => Promise<Signal<TData>[]>,\n memory: string | undefined,\n log: RunLog,\n config: ControlLoopConfig,\n ): Promise<Signal<TData>[]> {\n const maxAttempts = config.maxFixAttempts ?? 3;\n let remaining = picked;\n let iteration = 0;\n\n for (let attempt = 1; attempt <= maxAttempts && remaining.length > 0; attempt++) {\n for (const signal of remaining) {\n const { instructions } = await this.instructions(signal);\n const retryNote =\n attempt === 1\n ? \"\"\n : \"\\n\\nA previous attempt did not resolve this issue \u2014 the sensor still reports it. Look again and try a different approach.\";\n const where = signalWhere(signal) || signal.message;\n iteration++;\n await log.step(`agent fixing ${where} (iteration ${iteration})`, () =>\n config.agent.executeAgent(instructions + retryNote + memoryNote(memory), ctx),\n );\n }\n\n const stillPresent = new Set((await log.step(\"re-sensing to verify\", sense)).map(signalKey));\n remaining = remaining.filter((signal) => stillPresent.has(signalKey(signal)));\n }\n\n return remaining;\n }\n}\n\n/** \"file:line\", \"file\", or \"\" \u2014 the human-readable location of a signal, if it has one. */\nfunction signalWhere(signal: Signal): string {\n const { location } = signal;\n if (!location) return \"\";\n return `${location.file}${location.line ? `:${location.line}` : \"\"}`;\n}\n\nfunction prTitle(label: string, fixed: Signal[]): string {\n return fixed.length === 1 ? `fix: ${fixed[0]!.message}` : `fix: ${label}: ${fixed.length} issues`;\n}\n\nfunction prBody(label: string, fixed: Signal[]): string {\n const lines = fixed.map((signal) => {\n const where = signalWhere(signal);\n const priority = signal.priority ? ` (${signal.priority})` : \"\";\n return `- ${where ? `\\`${where}\\` \u2014 ` : \"\"}${signal.message}${priority}`;\n });\n return [\n `Automated fix opened by the **${label}** control loop.`,\n \"\",\n \"Signals resolved (verified by re-running the sensor):\",\n ...lines,\n \"\",\n claimMarker(fixed),\n ].join(\"\\n\");\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/agents.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The slice of the sandbox an agent is allowed to touch. Commands run with the repo
|
|
3
|
+
* root as cwd; file paths are relative to the repo root.
|
|
4
|
+
*/
|
|
5
|
+
export interface AgentContext {
|
|
6
|
+
exec: (command: string, options?: {
|
|
7
|
+
env?: Record<string, string>;
|
|
8
|
+
timeoutSec?: number;
|
|
9
|
+
}) => Promise<{
|
|
10
|
+
exitCode: number;
|
|
11
|
+
output: string;
|
|
12
|
+
}>;
|
|
13
|
+
writeFile: (path: string, content: string) => Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* A coding agent that can be driven headlessly inside the sandbox. Implementations
|
|
17
|
+
* know how to install their own CLI and how to invoke it with a prompt.
|
|
18
|
+
*/
|
|
19
|
+
export declare abstract class Agent {
|
|
20
|
+
/**
|
|
21
|
+
* Called once per run, before any {@link executeAgent} call. Install the agent's CLI
|
|
22
|
+
* here if the sandbox image doesn't already have it.
|
|
23
|
+
*/
|
|
24
|
+
prepare(_ctx: AgentContext): Promise<void>;
|
|
25
|
+
/** Runs the agent against the repo with the given instructions, applying edits in place. */
|
|
26
|
+
abstract executeAgent(instructions: string, ctx: AgentContext): Promise<void>;
|
|
27
|
+
}
|
|
28
|
+
export type ClaudeProps = {
|
|
29
|
+
apiKey: string;
|
|
30
|
+
/** e.g. "claude-sonnet-5". Defaults to the CLI's default model. */
|
|
31
|
+
model?: string;
|
|
32
|
+
/** Max seconds for one agent invocation. Default 900. */
|
|
33
|
+
timeoutSec?: number;
|
|
34
|
+
};
|
|
35
|
+
export declare class Claude extends Agent {
|
|
36
|
+
private readonly props;
|
|
37
|
+
constructor(props: ClaudeProps);
|
|
38
|
+
prepare(ctx: AgentContext): Promise<void>;
|
|
39
|
+
executeAgent(instructions: string, ctx: AgentContext): Promise<void>;
|
|
40
|
+
}
|
|
41
|
+
export type CodexProps = {
|
|
42
|
+
apiKey: string;
|
|
43
|
+
/** e.g. "gpt-5.1-codex". Defaults to the CLI's default model. */
|
|
44
|
+
model?: string;
|
|
45
|
+
/** Max seconds for one agent invocation. Default 900. */
|
|
46
|
+
timeoutSec?: number;
|
|
47
|
+
};
|
|
48
|
+
export declare class Codex extends Agent {
|
|
49
|
+
private readonly props;
|
|
50
|
+
constructor(props: CodexProps);
|
|
51
|
+
prepare(ctx: AgentContext): Promise<void>;
|
|
52
|
+
executeAgent(instructions: string, ctx: AgentContext): Promise<void>;
|
|
53
|
+
}
|