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,30 @@
|
|
|
1
|
+
import type { Backend, Workspace } from "../backend/types.js";
|
|
2
|
+
import type { Publisher, PullRequest, WorkItem } from "../loop/ports.js";
|
|
3
|
+
import type { GitHost } from "./githost.js";
|
|
4
|
+
export interface PublisherOptions {
|
|
5
|
+
baseBranch: string;
|
|
6
|
+
/** Labels to apply to opened PRs. Defaults to `["ghostrail"]`. */
|
|
7
|
+
labels?: readonly string[];
|
|
8
|
+
/** Conventional-commit type for the commit + PR title. Defaults to `fix`. */
|
|
9
|
+
commitType?: string;
|
|
10
|
+
/** Open PRs as drafts (the content-factory default). */
|
|
11
|
+
draft?: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Opens the pull request for a green run and never merges. It commits the
|
|
15
|
+
* agent's file changes and pushes the branch through the backend (so it works
|
|
16
|
+
* wherever the workspace lives), then opens the PR through the {@link GitHost}.
|
|
17
|
+
* The commit fails loudly if the agent produced no changes.
|
|
18
|
+
*/
|
|
19
|
+
export declare class GitHubPublisher implements Publisher {
|
|
20
|
+
private readonly backend;
|
|
21
|
+
private readonly host;
|
|
22
|
+
private readonly baseBranch;
|
|
23
|
+
private readonly labels;
|
|
24
|
+
private readonly commitType;
|
|
25
|
+
private readonly draft;
|
|
26
|
+
constructor(backend: Backend, host: GitHost, options: PublisherOptions);
|
|
27
|
+
openPullRequest(item: WorkItem, workspace: Workspace, summary: string): Promise<PullRequest>;
|
|
28
|
+
private git;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=github-publisher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-publisher.d.ts","sourceRoot":"","sources":["../../src/publish/github-publisher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACzE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAG5C,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wDAAwD;IACxD,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;GAKG;AACH,qBAAa,eAAgB,YAAW,SAAS;IAC/C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;IAClC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAU;IAC/B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;IAC3C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAU;gBAEpB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB;IAShE,eAAe,CACnB,IAAI,EAAE,QAAQ,EACd,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,WAAW,CAAC;YA0BT,GAAG;CAQlB"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { commitMessage, prBody } from "./githost.js";
|
|
2
|
+
/**
|
|
3
|
+
* Opens the pull request for a green run and never merges. It commits the
|
|
4
|
+
* agent's file changes and pushes the branch through the backend (so it works
|
|
5
|
+
* wherever the workspace lives), then opens the PR through the {@link GitHost}.
|
|
6
|
+
* The commit fails loudly if the agent produced no changes.
|
|
7
|
+
*/
|
|
8
|
+
export class GitHubPublisher {
|
|
9
|
+
backend;
|
|
10
|
+
host;
|
|
11
|
+
baseBranch;
|
|
12
|
+
labels;
|
|
13
|
+
commitType;
|
|
14
|
+
draft;
|
|
15
|
+
constructor(backend, host, options) {
|
|
16
|
+
this.backend = backend;
|
|
17
|
+
this.host = host;
|
|
18
|
+
this.baseBranch = options.baseBranch;
|
|
19
|
+
this.labels = options.labels ?? ["ghostrail"];
|
|
20
|
+
this.commitType = options.commitType ?? "fix";
|
|
21
|
+
this.draft = options.draft ?? false;
|
|
22
|
+
}
|
|
23
|
+
async openPullRequest(item, workspace, summary) {
|
|
24
|
+
await this.git(workspace, ["add", "-A"]);
|
|
25
|
+
const commit = await this.backend.exec(workspace, [
|
|
26
|
+
"git",
|
|
27
|
+
"commit",
|
|
28
|
+
"-m",
|
|
29
|
+
commitMessage(item.id, item.title, this.commitType),
|
|
30
|
+
]);
|
|
31
|
+
if (commit.exitCode !== 0) {
|
|
32
|
+
throw new Error(`commit failed (no changes to commit?): ${commit.stderr.trim() || commit.stdout.trim()}`);
|
|
33
|
+
}
|
|
34
|
+
await this.git(workspace, ["push", "-u", "origin", workspace.branch]);
|
|
35
|
+
return this.host.openPr({
|
|
36
|
+
baseBranch: this.baseBranch,
|
|
37
|
+
headBranch: workspace.branch,
|
|
38
|
+
title: commitMessage(item.id, item.title, this.commitType),
|
|
39
|
+
body: prBody(item, summary),
|
|
40
|
+
labels: this.labels,
|
|
41
|
+
draft: this.draft,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
async git(workspace, args) {
|
|
45
|
+
const result = await this.backend.exec(workspace, ["git", ...args]);
|
|
46
|
+
if (result.exitCode !== 0) {
|
|
47
|
+
throw new Error(`git ${args.join(" ")} failed: ${result.stderr.trim() || result.stdout.trim()}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=github-publisher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-publisher.js","sourceRoot":"","sources":["../../src/publish/github-publisher.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAYrD;;;;;GAKG;AACH,MAAM,OAAO,eAAe;IACT,OAAO,CAAU;IACjB,IAAI,CAAU;IACd,UAAU,CAAS;IACnB,MAAM,CAAoB;IAC1B,UAAU,CAAS;IACnB,KAAK,CAAU;IAEhC,YAAY,OAAgB,EAAE,IAAa,EAAE,OAAyB;QACpE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;QACrC,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,WAAW,CAAC,CAAC;QAC9C,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,KAAK,CAAC;QAC9C,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,KAAK,CAAC;IACtC,CAAC;IAED,KAAK,CAAC,eAAe,CACnB,IAAc,EACd,SAAoB,EACpB,OAAe;QAEf,MAAM,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;QACzC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE;YAChD,KAAK;YACL,QAAQ;YACR,IAAI;YACJ,aAAa,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,CAAC;SACpD,CAAC,CAAC;QACH,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CACb,0CAA0C,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CACzF,CAAC;QACJ,CAAC;QAED,MAAM,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;QAEtE,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;YACtB,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,UAAU,EAAE,SAAS,CAAC,MAAM;YAC5B,KAAK,EAAE,aAAa,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,CAAC;YAC1D,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC;YAC3B,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,KAAK,EAAE,IAAI,CAAC,KAAK;SAClB,CAAC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,GAAG,CAAC,SAAoB,EAAE,IAAuB;QAC7D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;QACpE,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CACb,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAChF,CAAC;QACJ,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { GhHost, type GhRunner, ghOpenPrArgs, parseCommentList, parseOpenPrList } from "./gh.js";
|
|
2
|
+
export { type GitHost, GHOSTRAIL_MARKER, commitMessage, type OpenPr, type PrComment, type PrRef, type PrSpec, parsePrUrl, prBody, } from "./githost.js";
|
|
3
|
+
export { GitHubPublisher, type PublisherOptions } from "./github-publisher.js";
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/publish/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,QAAQ,EAAE,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AACjG,OAAO,EACL,KAAK,OAAO,EACZ,gBAAgB,EAChB,aAAa,EACb,KAAK,MAAM,EACX,KAAK,SAAS,EACd,KAAK,KAAK,EACV,KAAK,MAAM,EACX,UAAU,EACV,MAAM,GACP,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,eAAe,EAAE,KAAK,gBAAgB,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/publish/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAiB,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AACjG,OAAO,EAEL,gBAAgB,EAChB,aAAa,EAKb,UAAU,EACV,MAAM,GACP,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,eAAe,EAAyB,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { FEEDBACK_PATH, type RespondConfig, type RespondDeps, type RespondResult, type RespondState, renderFeedback, respondTick, } from "./respond.js";
|
|
2
|
+
export { latestTimestamp, type SelectOptions, selectNewComments } from "./select.js";
|
|
3
|
+
export { FileWatermarkStore, MemoryWatermarkStore, type WatermarkStore } from "./store.js";
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/respond/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,cAAc,EACd,WAAW,GACZ,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,eAAe,EAAE,KAAK,aAAa,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACrF,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/respond/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EAKb,cAAc,EACd,WAAW,GACZ,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,eAAe,EAAsB,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACrF,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAuB,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Backend } from "../backend/types.js";
|
|
2
|
+
import type { AgentConfig, Guardrails } from "../config/schema.js";
|
|
3
|
+
import type { Agent, Logger } from "../loop/ports.js";
|
|
4
|
+
import { type GitHost, type PrComment } from "../publish/githost.js";
|
|
5
|
+
import type { WatermarkStore } from "./store.js";
|
|
6
|
+
/** Where the respond pass drops the human feedback for the agent to read. */
|
|
7
|
+
export declare const FEEDBACK_PATH = ".ghostrail/feedback.md";
|
|
8
|
+
export interface RespondDeps {
|
|
9
|
+
repoPath: string;
|
|
10
|
+
host: GitHost;
|
|
11
|
+
backend: Backend;
|
|
12
|
+
agent: Agent;
|
|
13
|
+
watermarks: WatermarkStore;
|
|
14
|
+
logger?: Logger;
|
|
15
|
+
}
|
|
16
|
+
export interface RespondConfig {
|
|
17
|
+
/** Label that marks factory PRs, e.g. "ghostrail". */
|
|
18
|
+
label: string;
|
|
19
|
+
/** Bot logins whose comments are ignored. */
|
|
20
|
+
selfLogins: readonly string[];
|
|
21
|
+
/** Agent config for the respond prompt (its `prompt` is the respond template). */
|
|
22
|
+
agent: AgentConfig;
|
|
23
|
+
guardrails: Guardrails;
|
|
24
|
+
}
|
|
25
|
+
export type RespondState = "responded" | "blocked" | "noop" | "failed";
|
|
26
|
+
export interface RespondResult {
|
|
27
|
+
prNumber: number;
|
|
28
|
+
state: RespondState;
|
|
29
|
+
summary?: string;
|
|
30
|
+
}
|
|
31
|
+
/** Render fresh human comments into the feedback document the agent reads. */
|
|
32
|
+
export declare function renderFeedback(comments: readonly PrComment[]): string;
|
|
33
|
+
/**
|
|
34
|
+
* The respond pass: for every open factory PR, act only on human comments newer
|
|
35
|
+
* than the per-PR watermark that do not carry the ghostrail marker (so it never
|
|
36
|
+
* acts on its own). For each such PR it checks out the PR branch, hands the
|
|
37
|
+
* agent the new feedback, and — on a successful change — commits, pushes to the
|
|
38
|
+
* same branch, and posts a summary comment; it never opens a new PR and never
|
|
39
|
+
* merges. The watermark advances once a PR's new comments have been handled.
|
|
40
|
+
*/
|
|
41
|
+
export declare function respondTick(deps: RespondDeps, config: RespondConfig): Promise<RespondResult[]>;
|
|
42
|
+
//# sourceMappingURL=respond.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"respond.d.ts","sourceRoot":"","sources":["../../src/respond/respond.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAa,MAAM,qBAAqB,CAAC;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,KAAK,EAAE,KAAK,EAAgB,MAAM,EAAY,MAAM,kBAAkB,CAAC;AAC9E,OAAO,EAAoB,KAAK,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEpG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,6EAA6E;AAC7E,eAAO,MAAM,aAAa,2BAA2B,CAAC;AAItD,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;IACb,UAAU,EAAE,cAAc,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,sDAAsD;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,kFAAkF;IAClF,KAAK,EAAE,WAAW,CAAC;IACnB,UAAU,EAAE,UAAU,CAAC;CACxB;AAED,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEvE,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,YAAY,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,8EAA8E;AAC9E,wBAAgB,cAAc,CAAC,QAAQ,EAAE,SAAS,SAAS,EAAE,GAAG,MAAM,CAGrE;AAOD;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,aAAa,EAAE,CAAC,CAU1B"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { writeWorkspaceFile } from "../backend/fs.js";
|
|
2
|
+
import { GHOSTRAIL_MARKER } from "../publish/githost.js";
|
|
3
|
+
import { latestTimestamp, selectNewComments } from "./select.js";
|
|
4
|
+
/** Where the respond pass drops the human feedback for the agent to read. */
|
|
5
|
+
export const FEEDBACK_PATH = ".ghostrail/feedback.md";
|
|
6
|
+
const nullLogger = { info: () => { }, warn: () => { } };
|
|
7
|
+
/** Render fresh human comments into the feedback document the agent reads. */
|
|
8
|
+
export function renderFeedback(comments) {
|
|
9
|
+
const blocks = comments.map((c) => `> from @${c.author} at ${c.createdAt}\n\n${c.body.trim()}`);
|
|
10
|
+
return `# New feedback to address\n\n${blocks.join("\n\n---\n\n")}\n`;
|
|
11
|
+
}
|
|
12
|
+
/** Comment body ghostrail posts, always carrying the marker so it never re-reads its own. */
|
|
13
|
+
function markedComment(body) {
|
|
14
|
+
return `${body}\n\n${GHOSTRAIL_MARKER}`;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The respond pass: for every open factory PR, act only on human comments newer
|
|
18
|
+
* than the per-PR watermark that do not carry the ghostrail marker (so it never
|
|
19
|
+
* acts on its own). For each such PR it checks out the PR branch, hands the
|
|
20
|
+
* agent the new feedback, and — on a successful change — commits, pushes to the
|
|
21
|
+
* same branch, and posts a summary comment; it never opens a new PR and never
|
|
22
|
+
* merges. The watermark advances once a PR's new comments have been handled.
|
|
23
|
+
*/
|
|
24
|
+
export async function respondTick(deps, config) {
|
|
25
|
+
const logger = deps.logger ?? nullLogger;
|
|
26
|
+
const prs = await deps.host.listOpenPrs(config.label);
|
|
27
|
+
logger.info(`respond: ${prs.length} open ${config.label} PR(s)`);
|
|
28
|
+
const results = [];
|
|
29
|
+
for (const pr of prs) {
|
|
30
|
+
results.push(await respondToPr(deps, config, pr, logger));
|
|
31
|
+
}
|
|
32
|
+
return results;
|
|
33
|
+
}
|
|
34
|
+
async function respondToPr(deps, config, pr, logger) {
|
|
35
|
+
const comments = await deps.host.listComments(pr.number);
|
|
36
|
+
const since = await deps.watermarks.get(pr.number);
|
|
37
|
+
const fresh = selectNewComments(comments, {
|
|
38
|
+
selfLogins: config.selfLogins,
|
|
39
|
+
marker: GHOSTRAIL_MARKER,
|
|
40
|
+
...(since === undefined ? {} : { since }),
|
|
41
|
+
});
|
|
42
|
+
if (fresh.length === 0) {
|
|
43
|
+
return { prNumber: pr.number, state: "noop" };
|
|
44
|
+
}
|
|
45
|
+
let workspace;
|
|
46
|
+
try {
|
|
47
|
+
workspace = await deps.backend.provision({
|
|
48
|
+
repoPath: deps.repoPath,
|
|
49
|
+
baseBranch: pr.headBranch,
|
|
50
|
+
branch: pr.headBranch,
|
|
51
|
+
mode: "attach",
|
|
52
|
+
});
|
|
53
|
+
await writeWorkspaceFile(deps.backend, workspace, FEEDBACK_PATH, renderFeedback(fresh));
|
|
54
|
+
const item = {
|
|
55
|
+
id: `PR-${pr.number}`,
|
|
56
|
+
title: `respond to PR #${pr.number}`,
|
|
57
|
+
url: pr.url,
|
|
58
|
+
};
|
|
59
|
+
const outcome = await deps.agent.run({
|
|
60
|
+
backend: deps.backend,
|
|
61
|
+
workspace,
|
|
62
|
+
item,
|
|
63
|
+
agent: config.agent,
|
|
64
|
+
guardrails: config.guardrails,
|
|
65
|
+
});
|
|
66
|
+
const result = await routeRespond(deps, pr, workspace, outcome, logger);
|
|
67
|
+
const mark = latestTimestamp(fresh);
|
|
68
|
+
if (mark !== undefined)
|
|
69
|
+
await deps.watermarks.set(pr.number, mark);
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
74
|
+
logger.warn(`respond #${pr.number}: errored: ${message}`);
|
|
75
|
+
return { prNumber: pr.number, state: "failed", summary: message };
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
if (workspace !== undefined) {
|
|
79
|
+
try {
|
|
80
|
+
await deps.backend.teardown(workspace);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// best-effort
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
async function routeRespond(deps, pr, workspace, outcome, logger) {
|
|
89
|
+
switch (outcome.status) {
|
|
90
|
+
case "blocked":
|
|
91
|
+
await deps.host.postComment(pr.number, markedComment(outcome.questions));
|
|
92
|
+
return { prNumber: pr.number, state: "blocked", summary: outcome.questions };
|
|
93
|
+
case "failed":
|
|
94
|
+
await deps.host.postComment(pr.number, markedComment(`The factory hit an error addressing the latest feedback: ${outcome.error}`));
|
|
95
|
+
return { prNumber: pr.number, state: "failed", summary: outcome.error };
|
|
96
|
+
case "noop":
|
|
97
|
+
await deps.host.postComment(pr.number, markedComment("No changes were needed for the latest feedback."));
|
|
98
|
+
return { prNumber: pr.number, state: "noop" };
|
|
99
|
+
case "done": {
|
|
100
|
+
const committed = await commitAndPush(deps.backend, workspace);
|
|
101
|
+
if (!committed) {
|
|
102
|
+
await deps.host.postComment(pr.number, markedComment("No changes were needed for the latest feedback."));
|
|
103
|
+
return { prNumber: pr.number, state: "noop" };
|
|
104
|
+
}
|
|
105
|
+
await deps.host.postComment(pr.number, markedComment(outcome.summary));
|
|
106
|
+
logger.info(`respond #${pr.number}: pushed an update`);
|
|
107
|
+
return { prNumber: pr.number, state: "responded", summary: outcome.summary };
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/** Commit and push the agent's changes to the PR branch. Returns false if there was nothing to commit. */
|
|
112
|
+
async function commitAndPush(backend, workspace) {
|
|
113
|
+
await backend.exec(workspace, ["git", "add", "-A"]);
|
|
114
|
+
const commit = await backend.exec(workspace, [
|
|
115
|
+
"git",
|
|
116
|
+
"commit",
|
|
117
|
+
"-m",
|
|
118
|
+
"respond: address review feedback",
|
|
119
|
+
]);
|
|
120
|
+
if (commit.exitCode !== 0)
|
|
121
|
+
return false;
|
|
122
|
+
const push = await backend.exec(workspace, ["git", "push", "origin", workspace.branch]);
|
|
123
|
+
if (push.exitCode !== 0) {
|
|
124
|
+
throw new Error(`git push failed: ${push.stderr.trim() || push.stdout.trim()}`);
|
|
125
|
+
}
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=respond.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"respond.js","sourceRoot":"","sources":["../../src/respond/respond.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { PrComment } from "../publish/githost.js";
|
|
2
|
+
export interface SelectOptions {
|
|
3
|
+
/** Author logins that are the bot itself; their comments are always ignored. */
|
|
4
|
+
selfLogins: readonly string[];
|
|
5
|
+
/** Only comments strictly after this ISO-8601 timestamp count as new. */
|
|
6
|
+
since?: string;
|
|
7
|
+
/** Marker identifying ghostrail-authored comments, which are ignored. */
|
|
8
|
+
marker: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Select the human comments the respond pass should act on: authored by someone
|
|
12
|
+
* other than the bot (case-insensitive login match), not carrying the ghostrail
|
|
13
|
+
* marker, and, when a `since` watermark is given, created strictly after it.
|
|
14
|
+
* Order is preserved.
|
|
15
|
+
*/
|
|
16
|
+
export declare function selectNewComments(comments: readonly PrComment[], options: SelectOptions): PrComment[];
|
|
17
|
+
/**
|
|
18
|
+
* The latest `createdAt` across the comments (lexicographic max, valid for
|
|
19
|
+
* ISO-8601), or undefined when there are none. Used as the next watermark.
|
|
20
|
+
*/
|
|
21
|
+
export declare function latestTimestamp(comments: readonly PrComment[]): string | undefined;
|
|
22
|
+
//# sourceMappingURL=select.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select.d.ts","sourceRoot":"","sources":["../../src/respond/select.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvD,MAAM,WAAW,aAAa;IAC5B,gFAAgF;IAChF,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,yEAAyE;IACzE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,SAAS,SAAS,EAAE,EAC9B,OAAO,EAAE,aAAa,GACrB,SAAS,EAAE,CAQb;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,SAAS,SAAS,EAAE,GAAG,MAAM,GAAG,SAAS,CAMlF"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Select the human comments the respond pass should act on: authored by someone
|
|
3
|
+
* other than the bot (case-insensitive login match), not carrying the ghostrail
|
|
4
|
+
* marker, and, when a `since` watermark is given, created strictly after it.
|
|
5
|
+
* Order is preserved.
|
|
6
|
+
*/
|
|
7
|
+
export function selectNewComments(comments, options) {
|
|
8
|
+
const self = new Set(options.selfLogins.map((login) => login.toLowerCase()));
|
|
9
|
+
return comments.filter((comment) => {
|
|
10
|
+
if (self.has(comment.author.toLowerCase()))
|
|
11
|
+
return false;
|
|
12
|
+
if (comment.body.includes(options.marker))
|
|
13
|
+
return false;
|
|
14
|
+
if (options.since !== undefined && comment.createdAt <= options.since)
|
|
15
|
+
return false;
|
|
16
|
+
return true;
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The latest `createdAt` across the comments (lexicographic max, valid for
|
|
21
|
+
* ISO-8601), or undefined when there are none. Used as the next watermark.
|
|
22
|
+
*/
|
|
23
|
+
export function latestTimestamp(comments) {
|
|
24
|
+
let latest;
|
|
25
|
+
for (const comment of comments) {
|
|
26
|
+
if (latest === undefined || comment.createdAt > latest)
|
|
27
|
+
latest = comment.createdAt;
|
|
28
|
+
}
|
|
29
|
+
return latest;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=select.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select.js","sourceRoot":"","sources":["../../src/respond/select.ts"],"names":[],"mappings":"AAWA;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAC/B,QAA8B,EAC9B,OAAsB;IAEtB,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IAC7E,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE;QACjC,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;YAAE,OAAO,KAAK,CAAC;QACzD,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC;YAAE,OAAO,KAAK,CAAC;QACxD,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,KAAK;YAAE,OAAO,KAAK,CAAC;QACpF,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,QAA8B;IAC5D,IAAI,MAA0B,CAAC;IAC/B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,MAAM,KAAK,SAAS,IAAI,OAAO,CAAC,SAAS,GAAG,MAAM;YAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IACrF,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** Per-PR watermark: the timestamp of the newest comment already handled. */
|
|
2
|
+
export interface WatermarkStore {
|
|
3
|
+
get(prNumber: number): Promise<string | undefined>;
|
|
4
|
+
set(prNumber: number, iso: string): Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
/** An in-memory watermark store, for tests and ephemeral runs. */
|
|
7
|
+
export declare class MemoryWatermarkStore implements WatermarkStore {
|
|
8
|
+
private readonly marks;
|
|
9
|
+
get(prNumber: number): Promise<string | undefined>;
|
|
10
|
+
set(prNumber: number, iso: string): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* A JSON-file watermark store keyed by PR number. Reads are tolerant of a
|
|
14
|
+
* missing or malformed file (treated as empty); each write persists the whole
|
|
15
|
+
* map. Suitable for the local-by-default run; a shared store arrives with the
|
|
16
|
+
* persistent run store in a later phase.
|
|
17
|
+
*/
|
|
18
|
+
export declare class FileWatermarkStore implements WatermarkStore {
|
|
19
|
+
private readonly path;
|
|
20
|
+
constructor(path: string);
|
|
21
|
+
get(prNumber: number): Promise<string | undefined>;
|
|
22
|
+
set(prNumber: number, iso: string): Promise<void>;
|
|
23
|
+
private read;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/respond/store.ts"],"names":[],"mappings":"AAGA,6EAA6E;AAC7E,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACnD,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnD;AAED,kEAAkE;AAClE,qBAAa,oBAAqB,YAAW,cAAc;IACzD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA6B;IAEnD,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAIlD,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAIlD;AAED;;;;;GAKG;AACH,qBAAa,kBAAmB,YAAW,cAAc;IACvD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;gBAElB,IAAI,EAAE,MAAM;IAIlB,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAKlD,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAOzC,IAAI;CAYnB"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname } from "node:path";
|
|
3
|
+
/** An in-memory watermark store, for tests and ephemeral runs. */
|
|
4
|
+
export class MemoryWatermarkStore {
|
|
5
|
+
marks = new Map();
|
|
6
|
+
get(prNumber) {
|
|
7
|
+
return Promise.resolve(this.marks.get(prNumber));
|
|
8
|
+
}
|
|
9
|
+
set(prNumber, iso) {
|
|
10
|
+
this.marks.set(prNumber, iso);
|
|
11
|
+
return Promise.resolve();
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* A JSON-file watermark store keyed by PR number. Reads are tolerant of a
|
|
16
|
+
* missing or malformed file (treated as empty); each write persists the whole
|
|
17
|
+
* map. Suitable for the local-by-default run; a shared store arrives with the
|
|
18
|
+
* persistent run store in a later phase.
|
|
19
|
+
*/
|
|
20
|
+
export class FileWatermarkStore {
|
|
21
|
+
path;
|
|
22
|
+
constructor(path) {
|
|
23
|
+
this.path = path;
|
|
24
|
+
}
|
|
25
|
+
async get(prNumber) {
|
|
26
|
+
const marks = await this.read();
|
|
27
|
+
return marks[String(prNumber)];
|
|
28
|
+
}
|
|
29
|
+
async set(prNumber, iso) {
|
|
30
|
+
const marks = await this.read();
|
|
31
|
+
marks[String(prNumber)] = iso;
|
|
32
|
+
await mkdir(dirname(this.path), { recursive: true });
|
|
33
|
+
await writeFile(this.path, `${JSON.stringify(marks, null, 2)}\n`, "utf8");
|
|
34
|
+
}
|
|
35
|
+
async read() {
|
|
36
|
+
try {
|
|
37
|
+
const raw = await readFile(this.path, "utf8");
|
|
38
|
+
const parsed = JSON.parse(raw);
|
|
39
|
+
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
40
|
+
return parsed;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// missing or malformed: start empty
|
|
45
|
+
}
|
|
46
|
+
return {};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/respond/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC,kEAAkE;AAClE,MAAM,OAAO,oBAAoB;IACd,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IAEnD,GAAG,CAAC,QAAgB;QAClB,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;IACnD,CAAC;IAED,GAAG,CAAC,QAAgB,EAAE,GAAW;QAC/B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QAC9B,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,OAAO,kBAAkB;IACZ,IAAI,CAAS;IAE9B,YAAY,IAAY;QACtB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,QAAgB;QACxB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QAChC,OAAO,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,QAAgB,EAAE,GAAW;QACrC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QAChC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,GAAG,CAAC;QAC9B,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACrD,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC5E,CAAC;IAEO,KAAK,CAAC,IAAI;QAChB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAC9C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAY,CAAC;YAC1C,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC5E,OAAO,MAAgC,CAAC;YAC1C,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,oCAAoC;QACtC,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;CACF"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Placeholder written in place of a redacted secret. */
|
|
2
|
+
export declare const REDACTION = "***";
|
|
3
|
+
/**
|
|
4
|
+
* Replace every occurrence of each known secret value in `text` with `***`.
|
|
5
|
+
* Secrets shorter than {@link MIN_SECRET_LENGTH} are ignored so trivial values
|
|
6
|
+
* don't blank out unrelated text. Redaction is applied before anything is
|
|
7
|
+
* logged or shipped, and never after. Purely a string transform; the input
|
|
8
|
+
* `secrets` is not mutated.
|
|
9
|
+
*/
|
|
10
|
+
export declare function redactSecrets(text: string, secrets: readonly string[]): string;
|
|
11
|
+
//# sourceMappingURL=redact.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact.d.ts","sourceRoot":"","sources":["../../src/secrets/redact.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,eAAO,MAAM,SAAS,QAAQ,CAAC;AAK/B;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAO9E"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Placeholder written in place of a redacted secret. */
|
|
2
|
+
export const REDACTION = "***";
|
|
3
|
+
/** Minimum secret length to redact, so short/empty values don't over-match. */
|
|
4
|
+
const MIN_SECRET_LENGTH = 6;
|
|
5
|
+
/**
|
|
6
|
+
* Replace every occurrence of each known secret value in `text` with `***`.
|
|
7
|
+
* Secrets shorter than {@link MIN_SECRET_LENGTH} are ignored so trivial values
|
|
8
|
+
* don't blank out unrelated text. Redaction is applied before anything is
|
|
9
|
+
* logged or shipped, and never after. Purely a string transform; the input
|
|
10
|
+
* `secrets` is not mutated.
|
|
11
|
+
*/
|
|
12
|
+
export function redactSecrets(text, secrets) {
|
|
13
|
+
let result = text;
|
|
14
|
+
for (const secret of secrets) {
|
|
15
|
+
if (secret.length < MIN_SECRET_LENGTH)
|
|
16
|
+
continue;
|
|
17
|
+
result = result.split(secret).join(REDACTION);
|
|
18
|
+
}
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=redact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact.js","sourceRoot":"","sources":["../../src/secrets/redact.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,MAAM,CAAC,MAAM,SAAS,GAAG,KAAK,CAAC;AAE/B,+EAA+E;AAC/E,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAE5B;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,OAA0B;IACpE,IAAI,MAAM,GAAG,IAAI,CAAC;IAClB,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,MAAM,CAAC,MAAM,GAAG,iBAAiB;YAAE,SAAS;QAChD,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAChD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/source/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,eAAe,EACf,KAAK,eAAe,EACpB,YAAY,EACZ,KAAK,mBAAmB,EACxB,eAAe,GAChB,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/source/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,eAAe,EAEf,YAAY,EAEZ,eAAe,GAChB,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { EligibleFilter } from "../config/schema.js";
|
|
2
|
+
import type { Source, WorkItem } from "../loop/ports.js";
|
|
3
|
+
/**
|
|
4
|
+
* Issues a Linear GraphQL operation and resolves the `data` payload. Injectable
|
|
5
|
+
* so the network layer can be faked in tests. Implementations should throw on a
|
|
6
|
+
* transport error or a GraphQL `errors` array.
|
|
7
|
+
*/
|
|
8
|
+
export type LinearRequester = (query: string, variables: Record<string, unknown>) => Promise<Record<string, unknown>>;
|
|
9
|
+
export declare const LINEAR_ENDPOINT = "https://api.linear.app/graphql";
|
|
10
|
+
/**
|
|
11
|
+
* A default requester over `fetch`, authenticating with a Linear personal API
|
|
12
|
+
* key (sent verbatim in the Authorization header, per Linear's API).
|
|
13
|
+
*/
|
|
14
|
+
export declare function createFetchRequester(apiKey: string, endpoint?: string, fetchImpl?: typeof fetch): LinearRequester;
|
|
15
|
+
/** A Linear issue node as returned by the eligible-issues query. */
|
|
16
|
+
interface IssueNode {
|
|
17
|
+
id: string;
|
|
18
|
+
identifier: string;
|
|
19
|
+
title: string;
|
|
20
|
+
url: string;
|
|
21
|
+
}
|
|
22
|
+
export declare const ELIGIBLE_ISSUES_QUERY = "\nquery EligibleIssues($filter: IssueFilter!, $first: Int!) {\n issues(filter: $filter, first: $first, orderBy: updatedAt) {\n nodes { id identifier title url }\n }\n}";
|
|
23
|
+
/**
|
|
24
|
+
* Build the Linear `IssueFilter` for an eligibility spec: state name, each label
|
|
25
|
+
* (via `and`), unassigned, and optionally scoped to a team key. Only the
|
|
26
|
+
* provided fields are included.
|
|
27
|
+
*/
|
|
28
|
+
export declare function buildIssueFilter(eligible: EligibleFilter, teamKey?: string): Record<string, unknown>;
|
|
29
|
+
/** Extract issue nodes from an `issues` query payload, ignoring malformed nodes. */
|
|
30
|
+
export declare function parseIssueNodes(data: Record<string, unknown>): IssueNode[];
|
|
31
|
+
export interface LinearSourceOptions {
|
|
32
|
+
teamKey: string;
|
|
33
|
+
eligible: EligibleFilter;
|
|
34
|
+
/** State to claim into; defaults to "In Progress". */
|
|
35
|
+
inProgressState?: string;
|
|
36
|
+
/** State to reset to; defaults to the eligible state, else "Todo". */
|
|
37
|
+
resetState?: string;
|
|
38
|
+
maxItems?: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The Linear implementation of the {@link Source} port, over the GraphQL API
|
|
42
|
+
* (a headless `claude -p` has no Linear MCP). Claiming an item moves it to the
|
|
43
|
+
* in-progress state and assigns it to the acting user, which removes it from the
|
|
44
|
+
* eligible pool; reset returns it to the reset state, unassigned.
|
|
45
|
+
*/
|
|
46
|
+
export declare class LinearSource implements Source {
|
|
47
|
+
private readonly request;
|
|
48
|
+
private readonly opts;
|
|
49
|
+
private bootstrap?;
|
|
50
|
+
private readonly uuidByIdentifier;
|
|
51
|
+
constructor(request: LinearRequester, opts: LinearSourceOptions);
|
|
52
|
+
listEligible(): Promise<WorkItem[]>;
|
|
53
|
+
claim(item: WorkItem): Promise<boolean>;
|
|
54
|
+
comment(item: WorkItem, body: string): Promise<void>;
|
|
55
|
+
reassignToHuman(item: WorkItem): Promise<void>;
|
|
56
|
+
reset(item: WorkItem): Promise<void>;
|
|
57
|
+
private ensureBootstrap;
|
|
58
|
+
private uuidFor;
|
|
59
|
+
}
|
|
60
|
+
export {};
|
|
61
|
+
//# sourceMappingURL=linear.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linear.d.ts","sourceRoot":"","sources":["../../src/source/linear.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEzD;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,CAC5B,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC/B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAEtC,eAAO,MAAM,eAAe,mCAAmC,CAAC;AAEhE;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,MAAwB,EAClC,SAAS,GAAE,OAAO,KAAa,GAC9B,eAAe,CAgBjB;AAED,oEAAoE;AACpE,UAAU,SAAS;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED,eAAO,MAAM,qBAAqB,iLAKhC,CAAC;AAEH;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,cAAc,EACxB,OAAO,CAAC,EAAE,MAAM,GACf,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASzB;AAED,oFAAoF;AACpF,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAAE,CAkB1E;AA0BD,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,cAAc,CAAC;IACzB,sDAAsD;IACtD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sEAAsE;IACtE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;GAKG;AACH,qBAAa,YAAa,YAAW,MAAM;IACzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkB;IAC1C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAEnB;IACF,OAAO,CAAC,SAAS,CAAC,CAAY;IAC9B,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA6B;gBAElD,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,mBAAmB;IAWzD,YAAY,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IAUnC,KAAK,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;IAUvC,OAAO,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpD,eAAe,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ9C,KAAK,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;YAS5B,eAAe;YAmBf,OAAO;CAKtB"}
|