ghostrail 0.0.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 +201 -0
- package/NOTICE +16 -0
- package/README.md +56 -0
- package/dist/agent/claude-code.d.ts +37 -0
- package/dist/agent/claude-code.d.ts.map +1 -0
- package/dist/agent/claude-code.js +74 -0
- package/dist/agent/claude-code.js.map +1 -0
- package/dist/agent/index.d.ts +4 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +4 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/prompt.d.ts +9 -0
- package/dist/agent/prompt.d.ts.map +1 -0
- package/dist/agent/prompt.js +15 -0
- package/dist/agent/prompt.js.map +1 -0
- package/dist/agent/result.d.ts +16 -0
- package/dist/agent/result.d.ts.map +1 -0
- package/dist/agent/result.js +56 -0
- package/dist/agent/result.js.map +1 -0
- package/dist/args.d.ts +27 -0
- package/dist/args.d.ts.map +1 -0
- package/dist/args.js +25 -0
- package/dist/args.js.map +1 -0
- package/dist/backend/container.d.ts +18 -0
- package/dist/backend/container.d.ts.map +1 -0
- package/dist/backend/container.js +70 -0
- package/dist/backend/container.js.map +1 -0
- package/dist/backend/docker.d.ts +22 -0
- package/dist/backend/docker.d.ts.map +1 -0
- package/dist/backend/docker.js +38 -0
- package/dist/backend/docker.js.map +1 -0
- package/dist/backend/fs.d.ts +9 -0
- package/dist/backend/fs.d.ts.map +1 -0
- package/dist/backend/fs.js +21 -0
- package/dist/backend/fs.js.map +1 -0
- package/dist/backend/index.d.ts +7 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +6 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/local-worktree.d.ts +17 -0
- package/dist/backend/local-worktree.d.ts.map +1 -0
- package/dist/backend/local-worktree.js +51 -0
- package/dist/backend/local-worktree.js.map +1 -0
- package/dist/backend/proc.d.ts +24 -0
- package/dist/backend/proc.d.ts.map +1 -0
- package/dist/backend/proc.js +103 -0
- package/dist/backend/proc.js.map +1 -0
- package/dist/backend/types.d.ts +75 -0
- package/dist/backend/types.d.ts.map +1 -0
- package/dist/backend/types.js +12 -0
- package/dist/backend/types.js.map +1 -0
- package/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +10 -0
- package/dist/bin.js.map +1 -0
- package/dist/board/index.d.ts +4 -0
- package/dist/board/index.d.ts.map +1 -0
- package/dist/board/index.js +4 -0
- package/dist/board/index.js.map +1 -0
- package/dist/board/page.d.ts +3 -0
- package/dist/board/page.d.ts.map +1 -0
- package/dist/board/page.js +55 -0
- package/dist/board/page.js.map +1 -0
- package/dist/board/server.d.ts +36 -0
- package/dist/board/server.d.ts.map +1 -0
- package/dist/board/server.js +110 -0
- package/dist/board/server.js.map +1 -0
- package/dist/board/stats.d.ts +26 -0
- package/dist/board/stats.d.ts.map +1 -0
- package/dist/board/stats.js +57 -0
- package/dist/board/stats.js.map +1 -0
- package/dist/cli/commands.d.ts +39 -0
- package/dist/cli/commands.d.ts.map +1 -0
- package/dist/cli/commands.js +224 -0
- package/dist/cli/commands.js.map +1 -0
- package/dist/cli.d.ts +16 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +45 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/help.d.ts +6 -0
- package/dist/commands/help.d.ts.map +1 -0
- package/dist/commands/help.js +29 -0
- package/dist/commands/help.js.map +1 -0
- package/dist/config/duration.d.ts +14 -0
- package/dist/config/duration.d.ts.map +1 -0
- package/dist/config/duration.js +25 -0
- package/dist/config/duration.js.map +1 -0
- package/dist/config/index.d.ts +5 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +4 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/load.d.ts +26 -0
- package/dist/config/load.d.ts.map +1 -0
- package/dist/config/load.js +306 -0
- package/dist/config/load.js.map +1 -0
- package/dist/config/result.d.ts +18 -0
- package/dist/config/result.d.ts.map +1 -0
- package/dist/config/result.js +7 -0
- package/dist/config/result.js.map +1 -0
- package/dist/config/schema.d.ts +77 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +35 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/factory/build.d.ts +39 -0
- package/dist/factory/build.d.ts.map +1 -0
- package/dist/factory/build.js +85 -0
- package/dist/factory/build.js.map +1 -0
- package/dist/gate/gate.d.ts +12 -0
- package/dist/gate/gate.d.ts.map +1 -0
- package/dist/gate/gate.js +22 -0
- package/dist/gate/gate.js.map +1 -0
- package/dist/gate/index.d.ts +2 -0
- package/dist/gate/index.d.ts.map +1 -0
- package/dist/gate/index.js +2 -0
- package/dist/gate/index.js.map +1 -0
- package/dist/global/index.d.ts +3 -0
- package/dist/global/index.d.ts.map +1 -0
- package/dist/global/index.js +3 -0
- package/dist/global/index.js.map +1 -0
- package/dist/global/stage.d.ts +13 -0
- package/dist/global/stage.d.ts.map +1 -0
- package/dist/global/stage.js +24 -0
- package/dist/global/stage.js.map +1 -0
- package/dist/global/store.d.ts +30 -0
- package/dist/global/store.d.ts.map +1 -0
- package/dist/global/store.js +65 -0
- package/dist/global/store.js.map +1 -0
- package/dist/lock/file-lock.d.ts +16 -0
- package/dist/lock/file-lock.d.ts.map +1 -0
- package/dist/lock/file-lock.js +51 -0
- package/dist/lock/file-lock.js.map +1 -0
- package/dist/loop/branch.d.ts +14 -0
- package/dist/loop/branch.d.ts.map +1 -0
- package/dist/loop/branch.js +24 -0
- package/dist/loop/branch.js.map +1 -0
- package/dist/loop/engine.d.ts +37 -0
- package/dist/loop/engine.d.ts.map +1 -0
- package/dist/loop/engine.js +204 -0
- package/dist/loop/engine.js.map +1 -0
- package/dist/loop/index.d.ts +6 -0
- package/dist/loop/index.d.ts.map +1 -0
- package/dist/loop/index.js +3 -0
- package/dist/loop/index.js.map +1 -0
- package/dist/loop/ports.d.ts +97 -0
- package/dist/loop/ports.d.ts.map +1 -0
- package/dist/loop/ports.js +2 -0
- package/dist/loop/ports.js.map +1 -0
- package/dist/loop/record.d.ts +26 -0
- package/dist/loop/record.d.ts.map +1 -0
- package/dist/loop/record.js +2 -0
- package/dist/loop/record.js.map +1 -0
- package/dist/publish/gh.d.ts +24 -0
- package/dist/publish/gh.d.ts.map +1 -0
- package/dist/publish/gh.js +109 -0
- package/dist/publish/gh.js.map +1 -0
- package/dist/publish/githost.d.ts +54 -0
- package/dist/publish/githost.d.ts.map +1 -0
- package/dist/publish/githost.js +33 -0
- package/dist/publish/githost.js.map +1 -0
- package/dist/publish/github-publisher.d.ts +30 -0
- package/dist/publish/github-publisher.d.ts.map +1 -0
- package/dist/publish/github-publisher.js +51 -0
- package/dist/publish/github-publisher.js.map +1 -0
- package/dist/publish/index.d.ts +4 -0
- package/dist/publish/index.d.ts.map +1 -0
- package/dist/publish/index.js +4 -0
- package/dist/publish/index.js.map +1 -0
- package/dist/respond/index.d.ts +4 -0
- package/dist/respond/index.d.ts.map +1 -0
- package/dist/respond/index.js +4 -0
- package/dist/respond/index.js.map +1 -0
- package/dist/respond/respond.d.ts +42 -0
- package/dist/respond/respond.d.ts.map +1 -0
- package/dist/respond/respond.js +128 -0
- package/dist/respond/respond.js.map +1 -0
- package/dist/respond/select.d.ts +22 -0
- package/dist/respond/select.d.ts.map +1 -0
- package/dist/respond/select.js +31 -0
- package/dist/respond/select.js.map +1 -0
- package/dist/respond/store.d.ts +25 -0
- package/dist/respond/store.d.ts.map +1 -0
- package/dist/respond/store.js +49 -0
- package/dist/respond/store.js.map +1 -0
- package/dist/secrets/redact.d.ts +11 -0
- package/dist/secrets/redact.d.ts.map +1 -0
- package/dist/secrets/redact.js +21 -0
- package/dist/secrets/redact.js.map +1 -0
- package/dist/source/index.d.ts +2 -0
- package/dist/source/index.d.ts.map +1 -0
- package/dist/source/index.js +2 -0
- package/dist/source/index.js.map +1 -0
- package/dist/source/linear.d.ts +61 -0
- package/dist/source/linear.d.ts.map +1 -0
- package/dist/source/linear.js +166 -0
- package/dist/source/linear.js.map +1 -0
- package/dist/store/events.d.ts +105 -0
- package/dist/store/events.d.ts.map +1 -0
- package/dist/store/events.js +64 -0
- package/dist/store/events.js.map +1 -0
- package/dist/store/file-store.d.ts +49 -0
- package/dist/store/file-store.d.ts.map +1 -0
- package/dist/store/file-store.js +188 -0
- package/dist/store/file-store.js.map +1 -0
- package/dist/store/index.d.ts +3 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/index.js +3 -0
- package/dist/store/index.js.map +1 -0
- package/dist/version.d.ts +3 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +21 -0
- package/dist/version.js.map +1 -0
- package/package.json +52 -0
- package/templates/content-loop/README.md +23 -0
- package/templates/content-loop/ghostrail.toml +36 -0
- package/templates/content-loop/prompts/draft.md +29 -0
- package/templates/fix-bugs-local/README.md +23 -0
- package/templates/fix-bugs-local/ghostrail.toml +37 -0
- package/templates/fix-bugs-local/prompts/fix-bug.md +27 -0
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { stageArtifacts } from "../global/stage.js";
|
|
3
|
+
import { branchName } from "./branch.js";
|
|
4
|
+
const nullLogger = { info: () => { }, warn: () => { } };
|
|
5
|
+
/** Branch prefix for factory work. */
|
|
6
|
+
const BRANCH_PREFIX = "fix";
|
|
7
|
+
/** Emit an event to the sink if present; recording never breaks a run. */
|
|
8
|
+
async function emitEvent(sink, event) {
|
|
9
|
+
if (sink === undefined)
|
|
10
|
+
return;
|
|
11
|
+
try {
|
|
12
|
+
await sink.emit(event);
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
// recording is best-effort
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/** Emit the gate steps, PR, and outcome captured in a finished item's result. */
|
|
19
|
+
async function recordResult(sink, runId, result) {
|
|
20
|
+
if (sink === undefined)
|
|
21
|
+
return;
|
|
22
|
+
const ts = Date.now();
|
|
23
|
+
for (const step of result.gate?.steps ?? []) {
|
|
24
|
+
await emitEvent(sink, { type: "gate_step", runId, ts, ...step });
|
|
25
|
+
}
|
|
26
|
+
if (result.prUrl !== undefined) {
|
|
27
|
+
const match = result.prUrl.match(/\/pull\/(\d+)/);
|
|
28
|
+
await emitEvent(sink, {
|
|
29
|
+
type: "pr_opened",
|
|
30
|
+
runId,
|
|
31
|
+
ts,
|
|
32
|
+
prNumber: match ? Number(match[1]) : 0,
|
|
33
|
+
prUrl: result.prUrl,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
await emitEvent(sink, {
|
|
37
|
+
type: "outcome",
|
|
38
|
+
runId,
|
|
39
|
+
ts,
|
|
40
|
+
state: result.state,
|
|
41
|
+
...(result.error === undefined ? {} : { error: result.error }),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
/** Swallow errors from a best-effort cleanup call so it can't mask the real outcome. */
|
|
45
|
+
async function ignoreErrors(action) {
|
|
46
|
+
try {
|
|
47
|
+
await action();
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
// best-effort; nothing to do
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Run one factory tick: discover eligible work, and for each item (up to the
|
|
55
|
+
* `max_items_per_run` guardrail) claim it, provision an isolated workspace, run
|
|
56
|
+
* the agent, gate a successful change, and route the outcome to a PR (done),
|
|
57
|
+
* back to a human (blocked), or to a reset (failed/noop). The whole tick runs
|
|
58
|
+
* under a single global lock so only one tick executes at a time; if the lock
|
|
59
|
+
* is already held, nothing runs.
|
|
60
|
+
*
|
|
61
|
+
* The loop owns no tracker, git, or agent specifics: every side effect goes
|
|
62
|
+
* through the injected ports, and the agent and gate run their commands through
|
|
63
|
+
* the backend. Auto-merge is never performed here; a green run ends at an open
|
|
64
|
+
* pull request.
|
|
65
|
+
*/
|
|
66
|
+
export async function runTick(deps, config) {
|
|
67
|
+
const logger = deps.logger ?? nullLogger;
|
|
68
|
+
const acquired = await deps.lock.acquire();
|
|
69
|
+
if (!acquired) {
|
|
70
|
+
logger.warn("another tick holds the lock; skipping");
|
|
71
|
+
return { lockAcquired: false, results: [] };
|
|
72
|
+
}
|
|
73
|
+
const results = [];
|
|
74
|
+
try {
|
|
75
|
+
const eligible = await deps.source.listEligible();
|
|
76
|
+
const items = eligible.slice(0, config.guardrails.maxItemsPerRun);
|
|
77
|
+
logger.info(`discovered ${eligible.length} eligible item(s), taking ${items.length}`);
|
|
78
|
+
for (const item of items) {
|
|
79
|
+
results.push(await runItem(deps, config, item, logger));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
await deps.lock.release();
|
|
84
|
+
}
|
|
85
|
+
return { lockAcquired: true, results };
|
|
86
|
+
}
|
|
87
|
+
async function runItem(deps, config, item, logger) {
|
|
88
|
+
let workspace;
|
|
89
|
+
const runId = randomUUID();
|
|
90
|
+
try {
|
|
91
|
+
const claimed = await deps.source.claim(item);
|
|
92
|
+
if (!claimed) {
|
|
93
|
+
logger.info(`${item.id}: claim lost, skipping`);
|
|
94
|
+
return { itemId: item.id, state: "skipped" };
|
|
95
|
+
}
|
|
96
|
+
await emitEvent(deps.events, {
|
|
97
|
+
type: "claimed",
|
|
98
|
+
runId,
|
|
99
|
+
ts: Date.now(),
|
|
100
|
+
itemId: item.id,
|
|
101
|
+
title: item.title,
|
|
102
|
+
});
|
|
103
|
+
workspace = await deps.backend.provision({
|
|
104
|
+
repoPath: deps.repoPath,
|
|
105
|
+
baseBranch: config.factory.baseBranch,
|
|
106
|
+
branch: branchName(BRANCH_PREFIX, item.id, item.title),
|
|
107
|
+
});
|
|
108
|
+
await emitEvent(deps.events, {
|
|
109
|
+
type: "provisioned",
|
|
110
|
+
runId,
|
|
111
|
+
ts: Date.now(),
|
|
112
|
+
backend: workspace.backend,
|
|
113
|
+
branch: workspace.branch,
|
|
114
|
+
});
|
|
115
|
+
if (deps.globalStore !== undefined && config.artifacts.length > 0) {
|
|
116
|
+
await stageArtifacts(deps.backend, workspace, deps.globalStore, config.artifacts, logger);
|
|
117
|
+
}
|
|
118
|
+
const outcome = await deps.agent.run({
|
|
119
|
+
backend: deps.backend,
|
|
120
|
+
workspace,
|
|
121
|
+
item,
|
|
122
|
+
agent: config.agent,
|
|
123
|
+
guardrails: config.guardrails,
|
|
124
|
+
});
|
|
125
|
+
await emitEvent(deps.events, {
|
|
126
|
+
type: "agent_finished",
|
|
127
|
+
runId,
|
|
128
|
+
ts: Date.now(),
|
|
129
|
+
status: outcome.status,
|
|
130
|
+
});
|
|
131
|
+
const result = await route(deps, config, item, workspace, outcome, logger);
|
|
132
|
+
await recordResult(deps.events, runId, result);
|
|
133
|
+
return result;
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
137
|
+
logger.warn(`${item.id}: errored, resetting: ${message}`);
|
|
138
|
+
await ignoreErrors(() => deps.source.reset(item));
|
|
139
|
+
await emitEvent(deps.events, {
|
|
140
|
+
type: "outcome",
|
|
141
|
+
runId,
|
|
142
|
+
ts: Date.now(),
|
|
143
|
+
state: "failed",
|
|
144
|
+
error: message,
|
|
145
|
+
});
|
|
146
|
+
return { itemId: item.id, state: "failed", error: message };
|
|
147
|
+
}
|
|
148
|
+
finally {
|
|
149
|
+
if (workspace !== undefined) {
|
|
150
|
+
await ignoreErrors(() => deps.backend.teardown(workspace));
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
async function route(deps, config, item, workspace, outcome, logger) {
|
|
155
|
+
switch (outcome.status) {
|
|
156
|
+
case "noop":
|
|
157
|
+
logger.info(`${item.id}: no change`);
|
|
158
|
+
return { itemId: item.id, state: "noop" };
|
|
159
|
+
case "blocked":
|
|
160
|
+
logger.info(`${item.id}: blocked, handing back to a human`);
|
|
161
|
+
await deps.source.comment(item, outcome.questions);
|
|
162
|
+
await deps.source.reassignToHuman(item);
|
|
163
|
+
await deps.source.reset(item);
|
|
164
|
+
return { itemId: item.id, state: "blocked", summary: outcome.questions };
|
|
165
|
+
case "failed":
|
|
166
|
+
logger.info(`${item.id}: agent failed, resetting`);
|
|
167
|
+
await deps.source.comment(item, outcome.error);
|
|
168
|
+
await deps.source.reset(item);
|
|
169
|
+
return { itemId: item.id, state: "failed", error: outcome.error };
|
|
170
|
+
case "done":
|
|
171
|
+
return routeDone(deps, config, item, workspace, outcome.summary, logger);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
async function routeDone(deps, config, item, workspace, summary, logger) {
|
|
175
|
+
if (config.gate.commands.length > 0) {
|
|
176
|
+
const gate = await deps.gate.run({
|
|
177
|
+
backend: deps.backend,
|
|
178
|
+
workspace,
|
|
179
|
+
commands: config.gate.commands,
|
|
180
|
+
timeoutMs: config.guardrails.timeoutMs,
|
|
181
|
+
});
|
|
182
|
+
if (!gate.passed) {
|
|
183
|
+
const failed = gate.steps.find((step) => step.exitCode !== 0);
|
|
184
|
+
const reason = failed ? `gate failed at step "${failed.name}"` : "gate failed";
|
|
185
|
+
logger.info(`${item.id}: ${reason}, resetting`);
|
|
186
|
+
await deps.source.comment(item, reason);
|
|
187
|
+
await deps.source.reset(item);
|
|
188
|
+
return { itemId: item.id, state: "failed", error: reason, gate };
|
|
189
|
+
}
|
|
190
|
+
if (!config.output.openPr) {
|
|
191
|
+
return { itemId: item.id, state: "done", summary, gate };
|
|
192
|
+
}
|
|
193
|
+
const pr = await deps.publisher.openPullRequest(item, workspace, summary);
|
|
194
|
+
logger.info(`${item.id}: opened ${pr.url}`);
|
|
195
|
+
return { itemId: item.id, state: "done", summary, gate, prUrl: pr.url };
|
|
196
|
+
}
|
|
197
|
+
if (!config.output.openPr) {
|
|
198
|
+
return { itemId: item.id, state: "done", summary };
|
|
199
|
+
}
|
|
200
|
+
const pr = await deps.publisher.openPullRequest(item, workspace, summary);
|
|
201
|
+
logger.info(`${item.id}: opened ${pr.url}`);
|
|
202
|
+
return { itemId: item.id, state: "done", summary, prUrl: pr.url };
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/loop/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { branchName, slugify } from "./branch.js";
|
|
2
|
+
export { type LoopDeps, runTick } from "./engine.js";
|
|
3
|
+
export type { Agent, AgentContext, AgentOutcome, Gate, GateContext, GateResult, GateStepResult, Logger, Lock, Publisher, PullRequest, Source, WorkItem, } from "./ports.js";
|
|
4
|
+
export type { RunResult, RunState, TickResult } from "./record.js";
|
|
5
|
+
export type { Backend, Workspace } from "../backend/types.js";
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/loop/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,KAAK,QAAQ,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACrD,YAAY,EACV,KAAK,EACL,YAAY,EACZ,YAAY,EACZ,IAAI,EACJ,WAAW,EACX,UAAU,EACV,cAAc,EACd,MAAM,EACN,IAAI,EACJ,SAAS,EACT,WAAW,EACX,MAAM,EACN,QAAQ,GACT,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACnE,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/loop/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAiB,OAAO,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { Backend, Workspace } from "../backend/types.js";
|
|
2
|
+
import type { AgentConfig, Guardrails } from "../config/schema.js";
|
|
3
|
+
/**
|
|
4
|
+
* The adapter ports the loop engine orchestrates. The engine depends only on
|
|
5
|
+
* these interfaces (dependency inversion); the concrete Linear source, the
|
|
6
|
+
* claude-code agent, and the gate runner implement them. Isolation is the
|
|
7
|
+
* five-verb {@link Backend} from `../backend`; the agent and gate run their
|
|
8
|
+
* commands through it, so they work the same on every backend.
|
|
9
|
+
*/
|
|
10
|
+
/** A unit of work drawn from a tracker. */
|
|
11
|
+
export interface WorkItem {
|
|
12
|
+
/** Tracker identifier, e.g. "TJ-123". */
|
|
13
|
+
id: string;
|
|
14
|
+
title: string;
|
|
15
|
+
url?: string;
|
|
16
|
+
}
|
|
17
|
+
/** Where work comes from (Linear, GitHub Issues, Beads). */
|
|
18
|
+
export interface Source {
|
|
19
|
+
/** Items currently eligible for the factory, most-ready first. */
|
|
20
|
+
listEligible(): Promise<WorkItem[]>;
|
|
21
|
+
/**
|
|
22
|
+
* Attempt to claim an item so no other run picks it up. Idempotent: returns
|
|
23
|
+
* false if the item is already claimed (by this or another run).
|
|
24
|
+
*/
|
|
25
|
+
claim(item: WorkItem): Promise<boolean>;
|
|
26
|
+
comment(item: WorkItem, body: string): Promise<void>;
|
|
27
|
+
/** Hand the item back to a human (reassign) when a decision is needed. */
|
|
28
|
+
reassignToHuman(item: WorkItem): Promise<void>;
|
|
29
|
+
/** Return the item to the eligible pool (e.g. after a failure). */
|
|
30
|
+
reset(item: WorkItem): Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
/** The outcome an agent reports after working an item. */
|
|
33
|
+
export type AgentOutcome = {
|
|
34
|
+
status: "done";
|
|
35
|
+
summary: string;
|
|
36
|
+
} | {
|
|
37
|
+
status: "blocked";
|
|
38
|
+
questions: string;
|
|
39
|
+
} | {
|
|
40
|
+
status: "failed";
|
|
41
|
+
error: string;
|
|
42
|
+
} | {
|
|
43
|
+
status: "noop";
|
|
44
|
+
};
|
|
45
|
+
/** Everything an agent needs to work one item in its provisioned workspace. */
|
|
46
|
+
export interface AgentContext {
|
|
47
|
+
backend: Backend;
|
|
48
|
+
workspace: Workspace;
|
|
49
|
+
item: WorkItem;
|
|
50
|
+
agent: AgentConfig;
|
|
51
|
+
guardrails: Guardrails;
|
|
52
|
+
}
|
|
53
|
+
/** The inner loop: a coding agent that only ever writes files in the workspace. */
|
|
54
|
+
export interface Agent {
|
|
55
|
+
run(context: AgentContext): Promise<AgentOutcome>;
|
|
56
|
+
}
|
|
57
|
+
export interface GateStepResult {
|
|
58
|
+
name: string;
|
|
59
|
+
exitCode: number;
|
|
60
|
+
durationMs: number;
|
|
61
|
+
}
|
|
62
|
+
export interface GateResult {
|
|
63
|
+
passed: boolean;
|
|
64
|
+
steps: GateStepResult[];
|
|
65
|
+
}
|
|
66
|
+
/** Inputs for one gate run in a provisioned workspace. */
|
|
67
|
+
export interface GateContext {
|
|
68
|
+
backend: Backend;
|
|
69
|
+
workspace: Workspace;
|
|
70
|
+
commands: readonly string[];
|
|
71
|
+
/** Per-command wall-clock cap. */
|
|
72
|
+
timeoutMs?: number;
|
|
73
|
+
}
|
|
74
|
+
/** The oracle: runs the CI-mirror commands in the workspace, in order. */
|
|
75
|
+
export interface Gate {
|
|
76
|
+
run(context: GateContext): Promise<GateResult>;
|
|
77
|
+
}
|
|
78
|
+
export interface PullRequest {
|
|
79
|
+
number: number;
|
|
80
|
+
url: string;
|
|
81
|
+
}
|
|
82
|
+
/** Opens the pull request for a green run. Never merges. */
|
|
83
|
+
export interface Publisher {
|
|
84
|
+
openPullRequest(item: WorkItem, workspace: Workspace, summary: string): Promise<PullRequest>;
|
|
85
|
+
}
|
|
86
|
+
/** A single-holder lock (the `flock` analog) so only one run executes at a time. */
|
|
87
|
+
export interface Lock {
|
|
88
|
+
/** Acquire the lock; returns false if it is already held. */
|
|
89
|
+
acquire(): Promise<boolean>;
|
|
90
|
+
release(): Promise<void>;
|
|
91
|
+
}
|
|
92
|
+
/** Structured progress sink; a no-op logger is a valid default. */
|
|
93
|
+
export interface Logger {
|
|
94
|
+
info(message: string): void;
|
|
95
|
+
warn(message: string): void;
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=ports.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ports.d.ts","sourceRoot":"","sources":["../../src/loop/ports.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ports.js","sourceRoot":"","sources":["../../src/loop/ports.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { GateResult } from "./ports.js";
|
|
2
|
+
/**
|
|
3
|
+
* Terminal state of a single item's run.
|
|
4
|
+
* - `done` — gate passed (or no gate) and the item was routed to a PR.
|
|
5
|
+
* - `blocked` — the agent hit a decision; questions posted, item handed back.
|
|
6
|
+
* - `failed` — the agent failed, the gate went red, or an error was thrown.
|
|
7
|
+
* - `noop` — the agent made no change.
|
|
8
|
+
* - `skipped` — the claim was lost to another run; nothing was done.
|
|
9
|
+
*/
|
|
10
|
+
export type RunState = "done" | "blocked" | "failed" | "noop" | "skipped";
|
|
11
|
+
/** What happened to one work item during a tick. */
|
|
12
|
+
export interface RunResult {
|
|
13
|
+
itemId: string;
|
|
14
|
+
state: RunState;
|
|
15
|
+
prUrl?: string;
|
|
16
|
+
gate?: GateResult;
|
|
17
|
+
summary?: string;
|
|
18
|
+
error?: string;
|
|
19
|
+
}
|
|
20
|
+
/** The result of a whole tick. */
|
|
21
|
+
export interface TickResult {
|
|
22
|
+
/** False when the global lock was already held, so nothing ran. */
|
|
23
|
+
lockAcquired: boolean;
|
|
24
|
+
results: RunResult[];
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=record.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../../src/loop/record.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;;;;;;;GAOG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;AAE1E,oDAAoD;AACpD,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,QAAQ,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,kCAAkC;AAClC,MAAM,WAAW,UAAU;IACzB,mEAAmE;IACnE,YAAY,EAAE,OAAO,CAAC;IACtB,OAAO,EAAE,SAAS,EAAE,CAAC;CACtB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record.js","sourceRoot":"","sources":["../../src/loop/record.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { GitHost, OpenPr, PrComment, PrRef, PrSpec } from "./githost.js";
|
|
2
|
+
/** Runs `gh` with the given args (in the repo) and resolves its result. */
|
|
3
|
+
export type GhRunner = (args: readonly string[]) => Promise<{
|
|
4
|
+
exitCode: number;
|
|
5
|
+
stdout: string;
|
|
6
|
+
stderr: string;
|
|
7
|
+
}>;
|
|
8
|
+
/** Build `gh pr create` args from a PR spec (one `--label` per label, in order). */
|
|
9
|
+
export declare function ghOpenPrArgs(spec: PrSpec): string[];
|
|
10
|
+
/** Parse `gh pr list --json number,url,headRefName` output into open PRs. */
|
|
11
|
+
export declare function parseOpenPrList(stdout: string): OpenPr[];
|
|
12
|
+
/** Parse `gh pr view --json comments` output into comments. */
|
|
13
|
+
export declare function parseCommentList(stdout: string): PrComment[];
|
|
14
|
+
/** The GitHub implementation of {@link GitHost} over the `gh` CLI. */
|
|
15
|
+
export declare class GhHost implements GitHost {
|
|
16
|
+
private readonly run;
|
|
17
|
+
constructor(run: GhRunner);
|
|
18
|
+
openPr(spec: PrSpec): Promise<PrRef>;
|
|
19
|
+
listOpenPrs(label: string): Promise<OpenPr[]>;
|
|
20
|
+
listComments(prNumber: number): Promise<PrComment[]>;
|
|
21
|
+
postComment(prNumber: number, body: string): Promise<void>;
|
|
22
|
+
private exec;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=gh.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gh.d.ts","sourceRoot":"","sources":["../../src/publish/gh.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAG9E,2EAA2E;AAC3E,MAAM,MAAM,QAAQ,GAAG,CACrB,IAAI,EAAE,SAAS,MAAM,EAAE,KACpB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEnE,oFAAoF;AACpF,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAgBnD;AAED,6EAA6E;AAC7E,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAYxD;AAED,+DAA+D;AAC/D,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,CAqB5D;AAWD,sEAAsE;AACtE,qBAAa,MAAO,YAAW,OAAO;IACpC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAW;gBAEnB,GAAG,EAAE,QAAQ;IAInB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAKpC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAc7C,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAKpD,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAIlD,IAAI;CASnB"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { parsePrUrl } from "./githost.js";
|
|
2
|
+
/** Build `gh pr create` args from a PR spec (one `--label` per label, in order). */
|
|
3
|
+
export function ghOpenPrArgs(spec) {
|
|
4
|
+
const args = [
|
|
5
|
+
"pr",
|
|
6
|
+
"create",
|
|
7
|
+
"--base",
|
|
8
|
+
spec.baseBranch,
|
|
9
|
+
"--head",
|
|
10
|
+
spec.headBranch,
|
|
11
|
+
"--title",
|
|
12
|
+
spec.title,
|
|
13
|
+
"--body",
|
|
14
|
+
spec.body,
|
|
15
|
+
];
|
|
16
|
+
if (spec.draft === true)
|
|
17
|
+
args.push("--draft");
|
|
18
|
+
for (const label of spec.labels)
|
|
19
|
+
args.push("--label", label);
|
|
20
|
+
return args;
|
|
21
|
+
}
|
|
22
|
+
/** Parse `gh pr list --json number,url,headRefName` output into open PRs. */
|
|
23
|
+
export function parseOpenPrList(stdout) {
|
|
24
|
+
const rows = safeJsonArray(stdout);
|
|
25
|
+
const prs = [];
|
|
26
|
+
for (const row of rows) {
|
|
27
|
+
if (row === null || typeof row !== "object")
|
|
28
|
+
continue;
|
|
29
|
+
const record = row;
|
|
30
|
+
const { number, url, headRefName } = record;
|
|
31
|
+
if (typeof number === "number" && typeof url === "string" && typeof headRefName === "string") {
|
|
32
|
+
prs.push({ number, url, headBranch: headRefName });
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return prs;
|
|
36
|
+
}
|
|
37
|
+
/** Parse `gh pr view --json comments` output into comments. */
|
|
38
|
+
export function parseCommentList(stdout) {
|
|
39
|
+
let parsed;
|
|
40
|
+
try {
|
|
41
|
+
parsed = JSON.parse(stdout);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
const comments = parsed?.comments;
|
|
47
|
+
if (!Array.isArray(comments))
|
|
48
|
+
return [];
|
|
49
|
+
const result = [];
|
|
50
|
+
for (const row of comments) {
|
|
51
|
+
if (row === null || typeof row !== "object")
|
|
52
|
+
continue;
|
|
53
|
+
const record = row;
|
|
54
|
+
const author = record.author?.login;
|
|
55
|
+
const { body, createdAt } = record;
|
|
56
|
+
if (typeof author === "string" && typeof body === "string" && typeof createdAt === "string") {
|
|
57
|
+
result.push({ author, body, createdAt });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
62
|
+
function safeJsonArray(text) {
|
|
63
|
+
try {
|
|
64
|
+
const value = JSON.parse(text);
|
|
65
|
+
return Array.isArray(value) ? value : [];
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/** The GitHub implementation of {@link GitHost} over the `gh` CLI. */
|
|
72
|
+
export class GhHost {
|
|
73
|
+
run;
|
|
74
|
+
constructor(run) {
|
|
75
|
+
this.run = run;
|
|
76
|
+
}
|
|
77
|
+
async openPr(spec) {
|
|
78
|
+
const result = await this.exec(ghOpenPrArgs(spec));
|
|
79
|
+
return parsePrUrl(result.stdout);
|
|
80
|
+
}
|
|
81
|
+
async listOpenPrs(label) {
|
|
82
|
+
const result = await this.exec([
|
|
83
|
+
"pr",
|
|
84
|
+
"list",
|
|
85
|
+
"--label",
|
|
86
|
+
label,
|
|
87
|
+
"--state",
|
|
88
|
+
"open",
|
|
89
|
+
"--json",
|
|
90
|
+
"number,url,headRefName",
|
|
91
|
+
]);
|
|
92
|
+
return parseOpenPrList(result.stdout);
|
|
93
|
+
}
|
|
94
|
+
async listComments(prNumber) {
|
|
95
|
+
const result = await this.exec(["pr", "view", String(prNumber), "--json", "comments"]);
|
|
96
|
+
return parseCommentList(result.stdout);
|
|
97
|
+
}
|
|
98
|
+
async postComment(prNumber, body) {
|
|
99
|
+
await this.exec(["pr", "comment", String(prNumber), "--body", body]);
|
|
100
|
+
}
|
|
101
|
+
async exec(args) {
|
|
102
|
+
const result = await this.run(args);
|
|
103
|
+
if (result.exitCode !== 0) {
|
|
104
|
+
throw new Error(`gh ${args.join(" ")} failed: ${result.stderr.trim() || result.stdout.trim()}`);
|
|
105
|
+
}
|
|
106
|
+
return result;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=gh.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gh.js","sourceRoot":"","sources":["../../src/publish/gh.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { WorkItem } from "../loop/ports.js";
|
|
2
|
+
/** Hidden marker in bodies ghostrail authors, so the respond pass never acts on its own. */
|
|
3
|
+
export declare const GHOSTRAIL_MARKER = "<!-- ghostrail -->";
|
|
4
|
+
export interface PrSpec {
|
|
5
|
+
baseBranch: string;
|
|
6
|
+
headBranch: string;
|
|
7
|
+
title: string;
|
|
8
|
+
body: string;
|
|
9
|
+
labels: readonly string[];
|
|
10
|
+
/** Open as a draft PR (the content-factory default). */
|
|
11
|
+
draft?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface PrRef {
|
|
14
|
+
number: number;
|
|
15
|
+
url: string;
|
|
16
|
+
}
|
|
17
|
+
/** An open PR as listed by the host. */
|
|
18
|
+
export interface OpenPr {
|
|
19
|
+
number: number;
|
|
20
|
+
url: string;
|
|
21
|
+
headBranch: string;
|
|
22
|
+
}
|
|
23
|
+
/** A comment on a PR. */
|
|
24
|
+
export interface PrComment {
|
|
25
|
+
/** Login/handle of the comment's author. */
|
|
26
|
+
author: string;
|
|
27
|
+
body: string;
|
|
28
|
+
/** ISO-8601 timestamp. */
|
|
29
|
+
createdAt: string;
|
|
30
|
+
}
|
|
31
|
+
/** A code-hosting provider (GitHub today), abstracted so the flows are testable. */
|
|
32
|
+
export interface GitHost {
|
|
33
|
+
openPr(spec: PrSpec): Promise<PrRef>;
|
|
34
|
+
listOpenPrs(label: string): Promise<OpenPr[]>;
|
|
35
|
+
listComments(prNumber: number): Promise<PrComment[]>;
|
|
36
|
+
postComment(prNumber: number, body: string): Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Extract the PR number and URL from `gh pr create` output, which prints the PR
|
|
40
|
+
* URL (e.g. `https://github.com/owner/repo/pull/42`) on its own line. Throws if
|
|
41
|
+
* no PR URL is present.
|
|
42
|
+
*/
|
|
43
|
+
export declare function parsePrUrl(stdout: string): PrRef;
|
|
44
|
+
/**
|
|
45
|
+
* Build the git commit message for an item: `<type>: <title> (<id>)`.
|
|
46
|
+
* The type defaults to `fix`.
|
|
47
|
+
*/
|
|
48
|
+
export declare function commitMessage(id: string, title: string, type?: string): string;
|
|
49
|
+
/**
|
|
50
|
+
* Build the PR body: the agent's summary, a footer linking the tracker item, and
|
|
51
|
+
* the hidden ghostrail marker so the respond pass can recognize its own PRs.
|
|
52
|
+
*/
|
|
53
|
+
export declare function prBody(item: WorkItem, summary: string): string;
|
|
54
|
+
//# sourceMappingURL=githost.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"githost.d.ts","sourceRoot":"","sources":["../../src/publish/githost.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD,4FAA4F;AAC5F,eAAO,MAAM,gBAAgB,uBAAuB,CAAC;AAErD,MAAM,WAAW,MAAM;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,wDAAwD;IACxD,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,KAAK;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wCAAwC;AACxC,MAAM,WAAW,MAAM;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,yBAAyB;AACzB,MAAM,WAAW,SAAS;IACxB,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,0BAA0B;IAC1B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,oFAAoF;AACpF,MAAM,WAAW,OAAO;IACtB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IACrC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9C,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IACrD,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5D;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,CAMhD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,SAAQ,GAAG,MAAM,CAE7E;AAED;;;GAGG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAK9D"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** Hidden marker in bodies ghostrail authors, so the respond pass never acts on its own. */
|
|
2
|
+
export const GHOSTRAIL_MARKER = "<!-- ghostrail -->";
|
|
3
|
+
/**
|
|
4
|
+
* Extract the PR number and URL from `gh pr create` output, which prints the PR
|
|
5
|
+
* URL (e.g. `https://github.com/owner/repo/pull/42`) on its own line. Throws if
|
|
6
|
+
* no PR URL is present.
|
|
7
|
+
*/
|
|
8
|
+
export function parsePrUrl(stdout) {
|
|
9
|
+
const match = stdout.match(/https?:\/\/\S+\/pull\/(\d+)/);
|
|
10
|
+
if (match === null || match[1] === undefined) {
|
|
11
|
+
throw new Error(`could not find a PR URL in output: ${stdout.trim()}`);
|
|
12
|
+
}
|
|
13
|
+
return { number: Number(match[1]), url: match[0] };
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Build the git commit message for an item: `<type>: <title> (<id>)`.
|
|
17
|
+
* The type defaults to `fix`.
|
|
18
|
+
*/
|
|
19
|
+
export function commitMessage(id, title, type = "fix") {
|
|
20
|
+
return `${type}: ${title} (${id})`;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Build the PR body: the agent's summary, a footer linking the tracker item, and
|
|
24
|
+
* the hidden ghostrail marker so the respond pass can recognize its own PRs.
|
|
25
|
+
*/
|
|
26
|
+
export function prBody(item, summary) {
|
|
27
|
+
const lines = [summary.trim(), "", `Factory run for ${item.id}.`];
|
|
28
|
+
if (item.url !== undefined && item.url.length > 0)
|
|
29
|
+
lines.push(item.url);
|
|
30
|
+
lines.push("", GHOSTRAIL_MARKER);
|
|
31
|
+
return lines.join("\n");
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=githost.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"githost.js","sourceRoot":"","sources":["../../src/publish/githost.ts"],"names":[],"mappings":"AAEA,4FAA4F;AAC5F,MAAM,CAAC,MAAM,gBAAgB,GAAG,oBAAoB,CAAC;AAyCrD;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,MAAc;IACvC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;IAC1D,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CAAC,sCAAsC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACzE,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AACrD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,EAAU,EAAE,KAAa,EAAE,IAAI,GAAG,KAAK;IACnE,OAAO,GAAG,IAAI,KAAK,KAAK,KAAK,EAAE,GAAG,CAAC;AACrC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,MAAM,CAAC,IAAc,EAAE,OAAe;IACpD,MAAM,KAAK,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,mBAAmB,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;IAClE,IAAI,IAAI,CAAC,GAAG,KAAK,SAAS,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACxE,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,gBAAgB,CAAC,CAAC;IACjC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
|