tono 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/LICENSE +21 -674
  2. package/README.md +300 -0
  3. package/dist/cli/commands/config.js +86 -0
  4. package/dist/cli/commands/config.js.map +1 -0
  5. package/dist/cli/commands/configure.js +260 -0
  6. package/dist/cli/commands/configure.js.map +1 -0
  7. package/dist/cli/commands/gateway.js +194 -0
  8. package/dist/cli/commands/gateway.js.map +1 -0
  9. package/dist/cli/commands/init.js +89 -0
  10. package/dist/cli/commands/init.js.map +1 -0
  11. package/dist/cli/commands/open.js +23 -0
  12. package/dist/cli/commands/open.js.map +1 -0
  13. package/dist/cli/commands/start.js +116 -0
  14. package/dist/cli/commands/start.js.map +1 -0
  15. package/dist/cli/index.js +78 -0
  16. package/dist/cli/index.js.map +1 -0
  17. package/dist/cli/launchd.js +56 -0
  18. package/dist/cli/launchd.js.map +1 -0
  19. package/dist/cli/prompt.js +46 -0
  20. package/dist/cli/prompt.js.map +1 -0
  21. package/dist/server/agents/claude-code.js +80 -0
  22. package/dist/server/agents/claude-code.js.map +1 -0
  23. package/dist/server/agents/codex.js +52 -0
  24. package/dist/server/agents/codex.js.map +1 -0
  25. package/dist/server/agents/opencode.js +50 -0
  26. package/dist/server/agents/opencode.js.map +1 -0
  27. package/dist/server/agents/registry.js +16 -0
  28. package/dist/server/agents/registry.js.map +1 -0
  29. package/dist/server/agents/types.js +40 -0
  30. package/dist/server/agents/types.js.map +1 -0
  31. package/dist/server/app.js +325 -0
  32. package/dist/server/app.js.map +1 -0
  33. package/dist/server/config/load.js +91 -0
  34. package/dist/server/config/load.js.map +1 -0
  35. package/dist/server/config/manager.js +38 -0
  36. package/dist/server/config/manager.js.map +1 -0
  37. package/dist/server/config/schema.json +151 -0
  38. package/dist/server/db/client.js +136 -0
  39. package/dist/server/db/client.js.map +1 -0
  40. package/dist/server/db/queries.js +158 -0
  41. package/dist/server/db/queries.js.map +1 -0
  42. package/dist/server/db/schema.sql +61 -0
  43. package/dist/server/events.js +5 -0
  44. package/dist/server/events.js.map +1 -0
  45. package/dist/server/git/worktrees.js +225 -0
  46. package/dist/server/git/worktrees.js.map +1 -0
  47. package/dist/server/github/gh.js +172 -0
  48. package/dist/server/github/gh.js.map +1 -0
  49. package/dist/server/pty/manager.js +129 -0
  50. package/dist/server/pty/manager.js.map +1 -0
  51. package/dist/server/pty/ring-buffer.js +40 -0
  52. package/dist/server/pty/ring-buffer.js.map +1 -0
  53. package/dist/server/server.js +36 -0
  54. package/dist/server/server.js.map +1 -0
  55. package/dist/server/workers/github-poller.js +185 -0
  56. package/dist/server/workers/github-poller.js.map +1 -0
  57. package/dist/server/workers/pr-watcher.js +111 -0
  58. package/dist/server/workers/pr-watcher.js.map +1 -0
  59. package/dist/server/workers/scheduler.js +209 -0
  60. package/dist/server/workers/scheduler.js.map +1 -0
  61. package/dist/server/ws/pty.js +72 -0
  62. package/dist/server/ws/pty.js.map +1 -0
  63. package/dist/shared/types.js +23 -0
  64. package/dist/shared/types.js.map +1 -0
  65. package/dist/shared/version.js +18 -0
  66. package/dist/shared/version.js.map +1 -0
  67. package/dist/web/assets/index-5VFn-lxF.js +129 -0
  68. package/dist/web/assets/index-CZHd5NaX.css +1 -0
  69. package/dist/web/index.html +19 -0
  70. package/package.json +79 -6
  71. package/scripts/fix-node-pty.mjs +35 -0
  72. package/index.js +0 -2
@@ -0,0 +1,61 @@
1
+ -- Tono operational state. Single-process, single-user.
2
+ -- All timestamps stored as ISO-8601 strings (UTC).
3
+
4
+ PRAGMA journal_mode = WAL;
5
+ PRAGMA foreign_keys = ON;
6
+
7
+ CREATE TABLE IF NOT EXISTS schema_version (
8
+ version INTEGER PRIMARY KEY
9
+ );
10
+
11
+ CREATE TABLE IF NOT EXISTS issues_seen (
12
+ repo_slug TEXT NOT NULL,
13
+ issue_number INTEGER NOT NULL,
14
+ trigger_label TEXT NOT NULL,
15
+ kind TEXT NOT NULL DEFAULT 'implement' CHECK (kind IN ('implement','review')),
16
+ first_seen_at TEXT NOT NULL,
17
+ updated_at TEXT NOT NULL,
18
+ PRIMARY KEY (repo_slug, issue_number, trigger_label, kind)
19
+ );
20
+
21
+ CREATE TABLE IF NOT EXISTS tasks (
22
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
23
+ kind TEXT NOT NULL DEFAULT 'implement' CHECK (kind IN ('implement','review')),
24
+ repo_slug TEXT NOT NULL,
25
+ issue_number INTEGER NOT NULL,
26
+ issue_title TEXT NOT NULL,
27
+ issue_body TEXT NOT NULL DEFAULT '',
28
+ branch TEXT NOT NULL,
29
+ agent TEXT NOT NULL,
30
+ agent_session_id TEXT,
31
+ status TEXT NOT NULL CHECK (status IN ('queued','running','completed','pr_open','pr_closed','merged','cleaned','failed')),
32
+ pr_url TEXT,
33
+ exit_code INTEGER,
34
+ created_at TEXT NOT NULL,
35
+ started_at TEXT,
36
+ completed_at TEXT,
37
+ UNIQUE (repo_slug, issue_number, branch, kind)
38
+ );
39
+
40
+ CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks (status);
41
+ CREATE INDEX IF NOT EXISTS idx_tasks_created_at ON tasks (created_at);
42
+ -- idx_tasks_agent_kind is created by the v4 migration in client.ts, not here,
43
+ -- because pre-v4 databases don't yet have the `kind` column when schema.sql runs.
44
+
45
+ CREATE TABLE IF NOT EXISTS sessions (
46
+ id TEXT PRIMARY KEY,
47
+ task_id INTEGER NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
48
+ pid INTEGER,
49
+ worktree_path TEXT NOT NULL,
50
+ started_at TEXT NOT NULL,
51
+ ended_at TEXT
52
+ );
53
+
54
+ CREATE INDEX IF NOT EXISTS idx_sessions_task_id ON sessions (task_id);
55
+
56
+ CREATE TABLE IF NOT EXISTS pr_watch (
57
+ task_id INTEGER PRIMARY KEY REFERENCES tasks(id) ON DELETE CASCADE,
58
+ pr_url TEXT NOT NULL,
59
+ last_state TEXT,
60
+ checked_at TEXT NOT NULL
61
+ );
@@ -0,0 +1,5 @@
1
+ import { EventEmitter } from "node:events";
2
+ export function createBus() {
3
+ return new EventEmitter();
4
+ }
5
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/server/events.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAoC3C,MAAM,UAAU,SAAS;IACvB,OAAO,IAAI,YAAY,EAAa,CAAC;AACvC,CAAC"}
@@ -0,0 +1,225 @@
1
+ import { spawn } from "node:child_process";
2
+ import { existsSync, mkdirSync, rmSync, statSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { expandHome } from "../config/load.js";
5
+ export class GitError extends Error {
6
+ stderr;
7
+ code;
8
+ constructor(message, stderr, code) {
9
+ const full = stderr ? `${message}\n ${stderr.split("\n").map((l) => l.trim()).filter(Boolean).join("\n ")}` : message;
10
+ super(full);
11
+ this.stderr = stderr;
12
+ this.code = code;
13
+ this.name = "GitError";
14
+ }
15
+ }
16
+ function run(args, cwd, timeoutMs = 120_000) {
17
+ return new Promise((resolvePromise, reject) => {
18
+ const child = spawn("git", args, { cwd, stdio: ["ignore", "pipe", "pipe"] });
19
+ let stdout = "";
20
+ let stderr = "";
21
+ const timer = setTimeout(() => {
22
+ child.kill("SIGKILL");
23
+ reject(new GitError(`git ${args.join(" ")} timed out`));
24
+ }, timeoutMs);
25
+ child.stdout.on("data", (b) => (stdout += b.toString()));
26
+ child.stderr.on("data", (b) => (stderr += b.toString()));
27
+ child.on("error", (err) => {
28
+ clearTimeout(timer);
29
+ reject(new GitError(`git failed to start: ${err.message}`));
30
+ });
31
+ child.on("close", (code) => {
32
+ clearTimeout(timer);
33
+ resolvePromise({ stdout, stderr, code: code ?? -1 });
34
+ });
35
+ });
36
+ }
37
+ function check(r, what) {
38
+ if (r.code !== 0)
39
+ throw new GitError(`${what} failed`, r.stderr.trim() || r.stdout.trim(), r.code);
40
+ }
41
+ function bareCloneName(slug) {
42
+ return slug.replace("/", "__");
43
+ }
44
+ function bareClonePath(workspacesRoot, slug) {
45
+ return join(workspacesRoot, ".bare", `${bareCloneName(slug)}.git`);
46
+ }
47
+ export function worktreePath(workspacesRoot, slug, issueNumber) {
48
+ return join(workspacesRoot, `${bareCloneName(slug)}__issue-${issueNumber}`);
49
+ }
50
+ export function reviewWorktreePath(workspacesRoot, slug, prNumber) {
51
+ return join(workspacesRoot, `${bareCloneName(slug)}__pr-review-${prNumber}`);
52
+ }
53
+ export function reviewLocalRef(prNumber) {
54
+ return `refs/tono/pr-${prNumber}`;
55
+ }
56
+ function runCmd(cmd, args, cwd, timeoutMs = 300_000) {
57
+ return new Promise((resolvePromise, reject) => {
58
+ const child = spawn(cmd, args, { cwd, stdio: ["ignore", "pipe", "pipe"] });
59
+ let stdout = "";
60
+ let stderr = "";
61
+ const timer = setTimeout(() => {
62
+ child.kill("SIGKILL");
63
+ reject(new GitError(`${cmd} ${args.join(" ")} timed out`));
64
+ }, timeoutMs);
65
+ child.stdout.on("data", (b) => (stdout += b.toString()));
66
+ child.stderr.on("data", (b) => (stderr += b.toString()));
67
+ child.on("error", (err) => {
68
+ clearTimeout(timer);
69
+ const enoent = err.code === "ENOENT";
70
+ reject(new GitError(enoent ? `\`${cmd}\` not found on PATH` : `${cmd} failed to start: ${err.message}`));
71
+ });
72
+ child.on("close", (code) => {
73
+ clearTimeout(timer);
74
+ resolvePromise({ stdout, stderr, code: code ?? -1 });
75
+ });
76
+ });
77
+ }
78
+ /**
79
+ * Ensure tono has a bare clone for `slug` under `<workspacesRoot>/.bare/`.
80
+ * Uses `gh repo clone` so private repos work with gh's auth, and configures
81
+ * the local credential helper so subsequent fetches keep working.
82
+ */
83
+ export async function ensureBareClone(workspacesRoot, slug) {
84
+ const bareDir = bareClonePath(workspacesRoot, slug);
85
+ if (existsSync(bareDir))
86
+ return bareDir;
87
+ mkdirSync(join(workspacesRoot, ".bare"), { recursive: true });
88
+ const r = await runCmd("gh", ["repo", "clone", slug, bareDir, "--", "--bare"]);
89
+ if (r.code !== 0) {
90
+ throw new GitError(`gh repo clone ${slug} failed`, r.stderr.trim() || r.stdout.trim(), r.code);
91
+ }
92
+ // Make future `git fetch` use gh's token (no need for `gh auth setup-git`).
93
+ await run(["config", "credential.helper", "!gh auth git-credential"], bareDir);
94
+ return bareDir;
95
+ }
96
+ async function isGitRepo(path) {
97
+ try {
98
+ if (!existsSync(path))
99
+ return false;
100
+ if (!statSync(path).isDirectory())
101
+ return false;
102
+ }
103
+ catch {
104
+ return false;
105
+ }
106
+ // Both regular clones (with `.git/`) and bare repos pass `rev-parse --git-dir`.
107
+ const r = await run(["rev-parse", "--git-dir"], path);
108
+ return r.code === 0;
109
+ }
110
+ export async function createWorktree(args) {
111
+ let sourcePath;
112
+ if (args.sourcePath && args.sourcePath.trim().length > 0) {
113
+ sourcePath = expandHome(args.sourcePath);
114
+ if (!(await isGitRepo(sourcePath))) {
115
+ throw new GitError(`repo path is not a git repository: ${sourcePath}\n set 'path' to your local clone, or remove it to let tono bare-clone via gh`);
116
+ }
117
+ }
118
+ else {
119
+ // No user-supplied path → ensure tono's own bare clone exists.
120
+ sourcePath = await ensureBareClone(args.workspacesRoot, args.slug);
121
+ }
122
+ const wtPath = worktreePath(args.workspacesRoot, args.slug, args.issueNumber);
123
+ const branch = `tono/issue-${args.issueNumber}`;
124
+ if (existsSync(wtPath)) {
125
+ return { path: wtPath, branch, sourcePath };
126
+ }
127
+ if (args.fetch !== false) {
128
+ // Fetch only the base branch; minimally invasive on the user's repo.
129
+ const fetchResult = await run(["fetch", "--quiet", "origin", args.baseBranch], sourcePath);
130
+ if (fetchResult.code !== 0) {
131
+ // Fetch failures are recoverable — log and continue using whatever ref the user has.
132
+ // Don't throw; the user might be offline or working on a stale ref intentionally.
133
+ }
134
+ }
135
+ // Try `origin/<baseBranch>` first; fall back to local `<baseBranch>` if no remote tracking.
136
+ const baseRef = `origin/${args.baseBranch}`;
137
+ const tryAdd = await run(["worktree", "add", "-B", branch, wtPath, baseRef], sourcePath);
138
+ if (tryAdd.code !== 0) {
139
+ const fallback = await run(["worktree", "add", "-B", branch, wtPath, args.baseBranch], sourcePath);
140
+ if (fallback.code !== 0) {
141
+ const stderr = (fallback.stderr || tryAdd.stderr).trim();
142
+ throw new GitError(`git worktree add ${wtPath} failed\n tried: ${baseRef} and ${args.baseBranch}`, stderr, fallback.code);
143
+ }
144
+ }
145
+ return { path: wtPath, branch, sourcePath };
146
+ }
147
+ export async function removeWorktree(args) {
148
+ // Default to tono's own bare clone if no user path was supplied.
149
+ const sourcePath = args.sourcePath && args.sourcePath.trim().length > 0
150
+ ? expandHome(args.sourcePath)
151
+ : bareClonePath(args.workspacesRoot, args.slug);
152
+ const wtPath = worktreePath(args.workspacesRoot, args.slug, args.issueNumber);
153
+ if (!existsSync(wtPath))
154
+ return;
155
+ if (await isGitRepo(sourcePath)) {
156
+ await run(["worktree", "remove", "--force", wtPath], sourcePath);
157
+ await run(["worktree", "prune"], sourcePath);
158
+ }
159
+ if (existsSync(wtPath)) {
160
+ rmSync(wtPath, { recursive: true, force: true });
161
+ }
162
+ }
163
+ /**
164
+ * Create a worktree for reviewing a pull request. Differs from createWorktree:
165
+ *
166
+ * - Fetches the PR head into a tono-namespaced ref: `refs/tono/pr-<N>`.
167
+ * - Creates the worktree at `<workspacesRoot>/<slug>__pr-review-<N>/` on a
168
+ * **detached HEAD** at that ref. We don't create a branch; the agent's
169
+ * job is to read and comment, not to push.
170
+ * - Idempotent: if the worktree already exists, returns it.
171
+ */
172
+ export async function createReviewWorktree(args) {
173
+ let sourcePath;
174
+ if (args.sourcePath && args.sourcePath.trim().length > 0) {
175
+ sourcePath = expandHome(args.sourcePath);
176
+ if (!(await isGitRepo(sourcePath))) {
177
+ throw new GitError(`repo path is not a git repository: ${sourcePath}\n set 'path' to your local clone, or remove it to let tono bare-clone via gh`);
178
+ }
179
+ }
180
+ else {
181
+ sourcePath = await ensureBareClone(args.workspacesRoot, args.slug);
182
+ }
183
+ const wtPath = reviewWorktreePath(args.workspacesRoot, args.slug, args.prNumber);
184
+ const localRef = reviewLocalRef(args.prNumber);
185
+ // The "branch" we report back is informational — for review tasks the
186
+ // detached head is at the PR's head commit. We use the local namespaced ref
187
+ // name so the UI has something to display.
188
+ const branch = `tono/pr-${args.prNumber}`;
189
+ if (existsSync(wtPath)) {
190
+ return { path: wtPath, branch, sourcePath };
191
+ }
192
+ // Fetch (or refresh) the PR head into our local ref. `+` allows non-fast-forward
193
+ // overwrite, so re-applying the review label after the PR is force-pushed picks up
194
+ // the latest head.
195
+ const fetchSpec = `+refs/pull/${args.prNumber}/head:${localRef}`;
196
+ const fetchResult = await run(["fetch", "--quiet", "origin", fetchSpec], sourcePath);
197
+ if (fetchResult.code !== 0) {
198
+ throw new GitError(`git fetch ${fetchSpec} failed`, fetchResult.stderr.trim() || fetchResult.stdout.trim(), fetchResult.code);
199
+ }
200
+ const add = await run(["worktree", "add", "--detach", wtPath, localRef], sourcePath);
201
+ if (add.code !== 0) {
202
+ throw new GitError(`git worktree add --detach ${wtPath} ${localRef} failed`, add.stderr.trim() || add.stdout.trim(), add.code);
203
+ }
204
+ return { path: wtPath, branch, sourcePath };
205
+ }
206
+ /** Remove a review worktree and its associated `refs/tono/pr-<N>` ref. */
207
+ export async function removeReviewWorktree(args) {
208
+ const sourcePath = args.sourcePath && args.sourcePath.trim().length > 0
209
+ ? expandHome(args.sourcePath)
210
+ : bareClonePath(args.workspacesRoot, args.slug);
211
+ const wtPath = reviewWorktreePath(args.workspacesRoot, args.slug, args.prNumber);
212
+ const localRef = reviewLocalRef(args.prNumber);
213
+ if (existsSync(wtPath) && (await isGitRepo(sourcePath))) {
214
+ await run(["worktree", "remove", "--force", wtPath], sourcePath);
215
+ await run(["worktree", "prune"], sourcePath);
216
+ }
217
+ if (existsSync(wtPath)) {
218
+ rmSync(wtPath, { recursive: true, force: true });
219
+ }
220
+ // Best-effort: drop the namespaced ref so we don't accumulate refs/tono/pr-* forever.
221
+ if (await isGitRepo(sourcePath)) {
222
+ await run(["update-ref", "-d", localRef], sourcePath);
223
+ }
224
+ }
225
+ //# sourceMappingURL=worktrees.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktrees.js","sourceRoot":"","sources":["../../../src/server/git/worktrees.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,172 @@
1
+ import { spawn } from "node:child_process";
2
+ export class GhError extends Error {
3
+ stderr;
4
+ code;
5
+ constructor(message, stderr, code) {
6
+ super(message);
7
+ this.stderr = stderr;
8
+ this.code = code;
9
+ this.name = "GhError";
10
+ }
11
+ }
12
+ function run(args, opts = {}) {
13
+ return new Promise((resolve, reject) => {
14
+ const child = spawn("gh", args, { stdio: ["pipe", "pipe", "pipe"] });
15
+ let stdout = "";
16
+ let stderr = "";
17
+ const timer = opts.timeoutMs
18
+ ? setTimeout(() => {
19
+ child.kill("SIGKILL");
20
+ reject(new GhError(`gh ${args[0] ?? ""} timed out after ${opts.timeoutMs}ms`));
21
+ }, opts.timeoutMs)
22
+ : null;
23
+ child.stdout.on("data", (b) => (stdout += b.toString()));
24
+ child.stderr.on("data", (b) => (stderr += b.toString()));
25
+ child.on("error", (err) => {
26
+ if (timer)
27
+ clearTimeout(timer);
28
+ if (err.code === "ENOENT") {
29
+ reject(new GhError("`gh` CLI not found on PATH. Install GitHub CLI: https://cli.github.com"));
30
+ }
31
+ else {
32
+ reject(new GhError(`gh failed to start: ${err.message}`));
33
+ }
34
+ });
35
+ child.on("close", (code) => {
36
+ if (timer)
37
+ clearTimeout(timer);
38
+ resolve({ stdout, stderr, code: code ?? -1 });
39
+ });
40
+ if (opts.input !== undefined) {
41
+ child.stdin.write(opts.input);
42
+ child.stdin.end();
43
+ }
44
+ else {
45
+ child.stdin.end();
46
+ }
47
+ });
48
+ }
49
+ export async function authStatus() {
50
+ const r = await run(["auth", "status"], { timeoutMs: 10_000 });
51
+ return { ok: r.code === 0, detail: (r.stdout + r.stderr).trim() };
52
+ }
53
+ export async function issueList(repoSlug, label) {
54
+ const r = await run([
55
+ "issue",
56
+ "list",
57
+ "--repo",
58
+ repoSlug,
59
+ "--label",
60
+ label,
61
+ "--state",
62
+ "open",
63
+ "--limit",
64
+ "100",
65
+ "--json",
66
+ "number,title,body,url,updatedAt,labels",
67
+ ], { timeoutMs: 30_000 });
68
+ if (r.code !== 0) {
69
+ throw new GhError(`gh issue list failed for ${repoSlug}`, r.stderr.trim(), r.code);
70
+ }
71
+ try {
72
+ const parsed = JSON.parse(r.stdout);
73
+ return parsed;
74
+ }
75
+ catch (err) {
76
+ throw new GhError(`gh issue list returned non-JSON for ${repoSlug}: ${err.message}`, r.stdout.slice(0, 500));
77
+ }
78
+ }
79
+ export async function issueView(repoSlug, issueNumber) {
80
+ const r = await run([
81
+ "issue",
82
+ "view",
83
+ String(issueNumber),
84
+ "--repo",
85
+ repoSlug,
86
+ "--json",
87
+ "number,title,body,url,updatedAt,labels",
88
+ ], { timeoutMs: 15_000 });
89
+ if (r.code !== 0) {
90
+ throw new GhError(`gh issue view failed for ${repoSlug}#${issueNumber}`, r.stderr.trim(), r.code);
91
+ }
92
+ try {
93
+ return JSON.parse(r.stdout);
94
+ }
95
+ catch (err) {
96
+ throw new GhError(`gh issue view returned non-JSON for ${repoSlug}#${issueNumber}: ${err.message}`, r.stdout.slice(0, 500));
97
+ }
98
+ }
99
+ export async function prView(url) {
100
+ const r = await run(["pr", "view", url, "--json", "state,mergedAt,url"], { timeoutMs: 15_000 });
101
+ if (r.code !== 0)
102
+ throw new GhError(`gh pr view failed for ${url}`, r.stderr.trim(), r.code);
103
+ return JSON.parse(r.stdout);
104
+ }
105
+ /** List open pull requests on a repo carrying a given label. */
106
+ export async function prList(repoSlug, label) {
107
+ const r = await run([
108
+ "pr",
109
+ "list",
110
+ "--repo",
111
+ repoSlug,
112
+ "--label",
113
+ label,
114
+ "--state",
115
+ "open",
116
+ "--limit",
117
+ "100",
118
+ "--json",
119
+ "number,title,body,url,updatedAt,headRefName,headRefOid,baseRefName,state,labels,author",
120
+ ], { timeoutMs: 30_000 });
121
+ if (r.code !== 0) {
122
+ throw new GhError(`gh pr list failed for ${repoSlug} label=${label}`, r.stderr.trim(), r.code);
123
+ }
124
+ try {
125
+ return JSON.parse(r.stdout);
126
+ }
127
+ catch (err) {
128
+ throw new GhError(`gh pr list returned non-JSON for ${repoSlug}: ${err.message}`, r.stdout.slice(0, 500));
129
+ }
130
+ }
131
+ /**
132
+ * Resolve a PR's head ref name + oid. Used by the review worktree creator to
133
+ * decide what ref to fetch and detach onto.
134
+ */
135
+ export async function prHeadRef(repoSlug, prNumber) {
136
+ const r = await run(["pr", "view", String(prNumber), "--repo", repoSlug, "--json", "headRefName,headRefOid"], { timeoutMs: 15_000 });
137
+ if (r.code !== 0) {
138
+ throw new GhError(`gh pr view failed for ${repoSlug}#${prNumber}`, r.stderr.trim(), r.code);
139
+ }
140
+ return JSON.parse(r.stdout);
141
+ }
142
+ /**
143
+ * Find the most recently created PR for a given branch on a repo. Returns
144
+ * null when no PR exists. Used by the watcher to associate a task with its
145
+ * PR even if we never captured the URL from the agent's stdout.
146
+ */
147
+ export async function prByBranch(repoSlug, branch) {
148
+ const r = await run([
149
+ "pr",
150
+ "list",
151
+ "--repo",
152
+ repoSlug,
153
+ "--head",
154
+ branch,
155
+ "--state",
156
+ "all",
157
+ "--limit",
158
+ "1",
159
+ "--json",
160
+ "url,state,mergedAt",
161
+ ], { timeoutMs: 15_000 });
162
+ if (r.code !== 0) {
163
+ throw new GhError(`gh pr list failed for ${repoSlug} head=${branch}`, r.stderr.trim(), r.code);
164
+ }
165
+ const arr = JSON.parse(r.stdout);
166
+ return arr[0] ?? null;
167
+ }
168
+ export function parsePrUrl(text) {
169
+ const m = text.match(/https:\/\/github\.com\/[\w.-]+\/[\w.-]+\/pull\/\d+/);
170
+ return m ? m[0] : null;
171
+ }
172
+ //# sourceMappingURL=gh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gh.js","sourceRoot":"","sources":["../../../src/server/github/gh.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,129 @@
1
+ import { EventEmitter } from "node:events";
2
+ import { createWriteStream, mkdirSync } from "node:fs";
3
+ import { dirname } from "node:path";
4
+ import * as pty from "node-pty";
5
+ import { RingBuffer } from "./ring-buffer.js";
6
+ const SCROLLBACK_BYTES = 4 * 1024 * 1024;
7
+ export class Session extends EventEmitter {
8
+ id;
9
+ taskId;
10
+ kind;
11
+ label;
12
+ proc;
13
+ startedAt;
14
+ endedAt = null;
15
+ exitCode = null;
16
+ status = "running";
17
+ buffer;
18
+ logStream;
19
+ cols = 120;
20
+ rows = 32;
21
+ constructor(id, taskId, kind, label, proc, startedAt, logFile) {
22
+ super();
23
+ this.id = id;
24
+ this.taskId = taskId;
25
+ this.kind = kind;
26
+ this.label = label;
27
+ this.proc = proc;
28
+ this.startedAt = startedAt;
29
+ this.buffer = new RingBuffer(SCROLLBACK_BYTES);
30
+ mkdirSync(dirname(logFile), { recursive: true });
31
+ this.logStream = createWriteStream(logFile, { flags: "a" });
32
+ proc.onData((data) => {
33
+ const chunk = Buffer.from(data, "utf8");
34
+ this.buffer.push(chunk);
35
+ this.logStream.write(chunk);
36
+ this.emit("data", chunk);
37
+ });
38
+ proc.onExit(({ exitCode, signal }) => {
39
+ this.exitCode = exitCode;
40
+ this.endedAt = new Date();
41
+ this.status = "exited";
42
+ this.logStream.end();
43
+ this.emit("exit", { exitCode, signal: signal ?? 0 });
44
+ });
45
+ }
46
+ get pid() {
47
+ return this.proc.pid;
48
+ }
49
+ scrollback() {
50
+ return this.buffer.snapshot();
51
+ }
52
+ write(data) {
53
+ if (this.status === "exited")
54
+ return;
55
+ this.proc.write(data);
56
+ }
57
+ resize(cols, rows) {
58
+ if (this.status === "exited")
59
+ return;
60
+ if (cols <= 0 || rows <= 0)
61
+ return;
62
+ this.cols = cols;
63
+ this.rows = rows;
64
+ try {
65
+ this.proc.resize(cols, rows);
66
+ }
67
+ catch {
68
+ // pty died between checks; ignore
69
+ }
70
+ }
71
+ size() {
72
+ return { cols: this.cols, rows: this.rows };
73
+ }
74
+ kill(signal = "SIGTERM") {
75
+ if (this.status === "exited")
76
+ return;
77
+ try {
78
+ this.proc.kill(signal);
79
+ }
80
+ catch {
81
+ /* ignore */
82
+ }
83
+ }
84
+ meta() {
85
+ return {
86
+ id: this.id,
87
+ taskId: this.taskId,
88
+ kind: this.kind,
89
+ label: this.label,
90
+ pid: this.pid,
91
+ startedAt: this.startedAt,
92
+ endedAt: this.endedAt,
93
+ exitCode: this.exitCode,
94
+ status: this.status,
95
+ };
96
+ }
97
+ }
98
+ export class PtyManager {
99
+ sessions = new Map();
100
+ spawn(opts) {
101
+ const proc = pty.spawn(opts.spec.command, opts.spec.args, {
102
+ name: "xterm-256color",
103
+ cols: 120,
104
+ rows: 32,
105
+ cwd: opts.spec.cwd,
106
+ env: opts.spec.env,
107
+ });
108
+ const session = new Session(opts.sessionId, opts.taskId, opts.kind ?? (opts.taskId === null ? "shell" : "agent"), opts.label ?? null, proc, new Date(), opts.logFile);
109
+ this.sessions.set(opts.sessionId, session);
110
+ session.once("exit", () => {
111
+ // Keep session in map for scrollback/audit; scheduler decides when to forget.
112
+ });
113
+ return session;
114
+ }
115
+ get(id) {
116
+ return this.sessions.get(id);
117
+ }
118
+ forget(id) {
119
+ this.sessions.delete(id);
120
+ }
121
+ list() {
122
+ return [...this.sessions.values()];
123
+ }
124
+ killAll(signal = "SIGTERM") {
125
+ for (const s of this.sessions.values())
126
+ s.kill(signal);
127
+ }
128
+ }
129
+ //# sourceMappingURL=manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../../src/server/pty/manager.ts"],"names":[],"mappings":"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"}