@pat-lewczuk/cezar 0.1.3 → 0.1.4

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 (123) hide show
  1. package/dist/core/claude-ui-mapper.d.ts +57 -0
  2. package/dist/core/claude-ui-mapper.js +370 -0
  3. package/dist/core/claude-ui-mapper.js.map +1 -0
  4. package/dist/core/codex-ui-mapper.d.ts +53 -0
  5. package/dist/core/codex-ui-mapper.js +411 -0
  6. package/dist/core/codex-ui-mapper.js.map +1 -0
  7. package/dist/core/opencode-ui-mapper.d.ts +105 -0
  8. package/dist/core/opencode-ui-mapper.js +578 -0
  9. package/dist/core/opencode-ui-mapper.js.map +1 -0
  10. package/dist/core/process-usage.d.ts +63 -0
  11. package/dist/core/process-usage.js +181 -0
  12. package/dist/core/process-usage.js.map +1 -0
  13. package/dist/core/tool-display.d.ts +27 -0
  14. package/dist/core/tool-display.js +150 -0
  15. package/dist/core/tool-display.js.map +1 -0
  16. package/dist/core/ui-events.d.ts +294 -0
  17. package/dist/core/ui-events.js +25 -0
  18. package/dist/core/ui-events.js.map +1 -0
  19. package/dist/index.js +0 -0
  20. package/dist/pack-check.d.ts +17 -0
  21. package/dist/pack-check.js +27 -0
  22. package/dist/pack-check.js.map +1 -0
  23. package/dist/runs/title-summary.d.ts +15 -0
  24. package/dist/runs/title-summary.js +84 -0
  25. package/dist/runs/title-summary.js.map +1 -0
  26. package/dist/runs/ui-event-sink.d.ts +81 -0
  27. package/dist/runs/ui-event-sink.js +210 -0
  28. package/dist/runs/ui-event-sink.js.map +1 -0
  29. package/dist/server/capabilities.d.ts +18 -0
  30. package/dist/server/capabilities.js +23 -0
  31. package/dist/server/capabilities.js.map +1 -0
  32. package/dist/server/forge/github.d.ts +39 -0
  33. package/dist/server/forge/github.js +369 -0
  34. package/dist/server/forge/github.js.map +1 -0
  35. package/dist/server/forge/index.d.ts +24 -0
  36. package/dist/server/forge/index.js +45 -0
  37. package/dist/server/forge/index.js.map +1 -0
  38. package/dist/server/forge/types.d.ts +80 -0
  39. package/dist/server/forge/types.js +2 -0
  40. package/dist/server/forge/types.js.map +1 -0
  41. package/dist/server/git-changes.d.ts +182 -0
  42. package/dist/server/git-changes.js +424 -0
  43. package/dist/server/git-changes.js.map +1 -0
  44. package/dist/server/open-in-app.d.ts +19 -0
  45. package/dist/server/open-in-app.js +134 -0
  46. package/dist/server/open-in-app.js.map +1 -0
  47. package/dist/server/static-ui.d.ts +49 -0
  48. package/dist/server/static-ui.js +92 -0
  49. package/dist/server/static-ui.js.map +1 -0
  50. package/dist/update-check.d.ts +12 -0
  51. package/dist/update-check.js +41 -0
  52. package/dist/update-check.js.map +1 -0
  53. package/package.json +1 -1
  54. package/web/app/node_modules/.vite/vitest/ca84d1343b96baa8137c943ed1860e522cacb238/results.json +1 -0
  55. package/web/app/src/components/app-shell-container.tsx +76 -0
  56. package/web/dist/assets/arrow-left-BE957rJs.js +1 -0
  57. package/web/dist/assets/bundle-mjs-DLPpRFyl.js +1 -0
  58. package/web/dist/assets/chunk-BO2N2NFS-f5igTtpB.js +131 -0
  59. package/web/dist/assets/compare-variants-D6fPL9cS.js +1 -0
  60. package/web/dist/assets/core-BuMqAF_1.js +12 -0
  61. package/web/dist/assets/css-BsVw1vtW.js +1 -0
  62. package/web/dist/assets/dialog-BEgEWFDS.js +1 -0
  63. package/web/dist/assets/diff-view-CctnJHWe.js +4 -0
  64. package/web/dist/assets/diff-woXpYk--.js +1 -0
  65. package/web/dist/assets/dist-CW7M_Jhs.js +1 -0
  66. package/web/dist/assets/ellipsis-vertical-DJPAfccS.js +1 -0
  67. package/web/dist/assets/engine-javascript-FQvzRocB.js +141 -0
  68. package/web/dist/assets/folder-RbRLfIX-.js +1 -0
  69. package/web/dist/assets/git-pull-request-DJkAMT0f.js +1 -0
  70. package/web/dist/assets/git-toolbar-D8OPPqBP.js +1 -0
  71. package/web/dist/assets/github-BYIHwIJB.js +1 -0
  72. package/web/dist/assets/go-rLFTqkRN.js +1 -0
  73. package/web/dist/assets/highlighted-body-OFNGDK62-DGHHie_q.js +1 -0
  74. package/web/dist/assets/highlighter-BKVEsACy.js +3 -0
  75. package/web/dist/assets/html-BY76lXLH.js +1 -0
  76. package/web/dist/assets/index-9qG98Orw.js +11 -0
  77. package/web/dist/assets/index-Bz_r8Jt3.css +2 -0
  78. package/web/dist/assets/input-BRsSo4xH.js +1 -0
  79. package/web/dist/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
  80. package/web/dist/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
  81. package/web/dist/assets/javascript-BgS3c2Ky.js +1 -0
  82. package/web/dist/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  83. package/web/dist/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  84. package/web/dist/assets/json-qhed-kSA.js +1 -0
  85. package/web/dist/assets/jsonc-CYpm1nAK.js +1 -0
  86. package/web/dist/assets/jsx-Bz0zcwM4.js +1 -0
  87. package/web/dist/assets/lib-CNGa3Dig.js +1 -0
  88. package/web/dist/assets/loader-circle-BV3DO9mE.js +1 -0
  89. package/web/dist/assets/markdown-BYOwaDjH.js +1 -0
  90. package/web/dist/assets/markdown-CR_HLGTs.js +1 -0
  91. package/web/dist/assets/mermaid-GHXKKRXX-DM2VsGBG.js +1 -0
  92. package/web/dist/assets/open-mercato-toBr6SOa.svg +11 -0
  93. package/web/dist/assets/python-gzcpVVnB.js +1 -0
  94. package/web/dist/assets/react-dom-Ddtik4qM.js +1 -0
  95. package/web/dist/assets/refresh-cw-DCa-Rlwz.js +1 -0
  96. package/web/dist/assets/repo-git-XTqlVOl2.js +1 -0
  97. package/web/dist/assets/run-diff-C7mfxj7f.js +3 -0
  98. package/web/dist/assets/run-header-CfVeY3uM.js +1 -0
  99. package/web/dist/assets/rust-Cfkwpbl8.js +1 -0
  100. package/web/dist/assets/search-x-CoCyl7zT.js +1 -0
  101. package/web/dist/assets/shellscript-CLZ0U2zV.js +1 -0
  102. package/web/dist/assets/skill-detail-C9cniyId.js +1 -0
  103. package/web/dist/assets/skills-DXgY1uXJ.js +1 -0
  104. package/web/dist/assets/skills-ynuO5oCr.js +1 -0
  105. package/web/dist/assets/sql-BsFa4tDR.js +1 -0
  106. package/web/dist/assets/square-terminal-B6PZX4Qp.js +1 -0
  107. package/web/dist/assets/tab-link-phWEqSBy.js +1 -0
  108. package/web/dist/assets/task-changes-DYwnPnTN.js +1 -0
  109. package/web/dist/assets/task-commits-DZzxEzbn.js +1 -0
  110. package/web/dist/assets/task-files-FOAAz2FB.js +2 -0
  111. package/web/dist/assets/task-thread-Bncxe8Os.js +5 -0
  112. package/web/dist/assets/toaster-BS2E1bhz.js +43 -0
  113. package/web/dist/assets/trash-2-CDtxmmc8.js +1 -0
  114. package/web/dist/assets/triangle-alert-6su4Js5O.js +1 -0
  115. package/web/dist/assets/tsx-udAQXfEw.js +1 -0
  116. package/web/dist/assets/typescript-bsJCZSQ-.js +1 -0
  117. package/web/dist/assets/upload-Bp7hQxll.js +1 -0
  118. package/web/dist/assets/use-desktop-eHm2iTXX.js +3 -0
  119. package/web/dist/assets/utils-rQGbOrwc.js +1 -0
  120. package/web/dist/assets/workflows-Dg2wQg6i.js +11 -0
  121. package/web/dist/assets/x-Br_jIDBw.js +1 -0
  122. package/web/dist/assets/yaml-rwi0_p6S.js +1 -0
  123. package/web/dist/index.html +67 -0
@@ -0,0 +1,369 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+ import { z } from 'zod';
4
+ import { autosaveCommit } from '../../git-worktree.js';
5
+ /**
6
+ * The GitHub forge driver — all `gh`-CLI logic in one place, moved here from
7
+ * `src/server/github.ts` (tab listing) and `src/server/pr.ts` (draft PRs)
8
+ * behind the `ForgeDriver` seam. Those modules remain as thin delegates.
9
+ * `/api/github`'s response shape is this driver's serialization and is
10
+ * protected by BACKWARD_COMPATIBILITY.md — additive changes only.
11
+ */
12
+ const exec = promisify(execFile);
13
+ // `gh … --json` output — validated at the boundary, extras stripped.
14
+ const ghAuthor = z.object({ login: z.string() }).nullish();
15
+ // `color` is the 6-hex GitHub label color (no `#`), '' when gh omits it.
16
+ const ghLabel = z.object({ name: z.string(), color: z.string().default('') });
17
+ const ghIssueSchema = z.object({
18
+ number: z.number(),
19
+ title: z.string(),
20
+ author: ghAuthor,
21
+ createdAt: z.string(),
22
+ labels: z.array(ghLabel).default([]),
23
+ body: z.string().nullish(),
24
+ url: z.string(),
25
+ });
26
+ const ghPrSchema = ghIssueSchema.extend({
27
+ isDraft: z.boolean().default(false),
28
+ additions: z.number().default(0),
29
+ deletions: z.number().default(0),
30
+ statusCheckRollup: z
31
+ .array(z.object({ state: z.string().nullish(), status: z.string().nullish(), conclusion: z.string().nullish() }))
32
+ .nullish(),
33
+ });
34
+ const ghPrViewSchema = z.object({
35
+ number: z.number(),
36
+ url: z.string(),
37
+ state: z.string().default('OPEN'),
38
+ isDraft: z.boolean().default(false),
39
+ statusCheckRollup: z
40
+ .array(z.object({ state: z.string().nullish(), status: z.string().nullish(), conclusion: z.string().nullish() }))
41
+ .nullish(),
42
+ });
43
+ function rollupToChecks(rollup) {
44
+ if (!rollup || rollup.length === 0)
45
+ return null;
46
+ const states = rollup.map((r) => (r.conclusion || r.state || r.status || '').toUpperCase());
47
+ if (states.some((s) => ['FAILURE', 'ERROR', 'TIMED_OUT', 'ACTION_REQUIRED'].includes(s)))
48
+ return 'failing';
49
+ if (states.some((s) => ['PENDING', 'IN_PROGRESS', 'QUEUED', 'EXPECTED', ''].includes(s)))
50
+ return 'pending';
51
+ return 'passing';
52
+ }
53
+ async function gh(repoRoot, args, timeout = 15_000) {
54
+ const { stdout } = await exec('gh', args, {
55
+ cwd: repoRoot,
56
+ timeout,
57
+ maxBuffer: 50 * 1024 * 1024,
58
+ });
59
+ return stdout;
60
+ }
61
+ /* Reads degrade to `available: false` with a hint — never an error (plan rule
62
+ 7): no `gh`, no remote, offline all land on the same quiet path. A short
63
+ cache keeps tab switches from hammering the GitHub API; a cached fetch with
64
+ a bigger limit than asked serves fine (it's a superset). */
65
+ let cache = null;
66
+ const CACHE_MS = 60_000;
67
+ export const GH_MAX_LIMIT = 1000;
68
+ export async function fetchGithub(repoRoot, refresh = false, limit = 30) {
69
+ if (process.env.CEZ_DRY_RUN === '1')
70
+ return mockGithub();
71
+ const capped = Math.min(Math.max(limit, 1), GH_MAX_LIMIT);
72
+ if (!refresh && cache && Date.now() - cache.at < CACHE_MS && cache.limit >= capped) {
73
+ return cache.data;
74
+ }
75
+ try {
76
+ // No `comments` field — `gh … --json comments` ships full comment bodies.
77
+ // Big fetches (the GUI's follow-up "give me everything" shot) get a
78
+ // longer wall clock — statusCheckRollup on hundreds of PRs is slow.
79
+ const timeout = capped > 100 ? 60_000 : 15_000;
80
+ const fields = 'number,title,author,createdAt,labels,body,url';
81
+ const [repoOut, issuesOut, prsOut] = await Promise.all([
82
+ gh(repoRoot, ['repo', 'view', '--json', 'nameWithOwner', '--jq', '.nameWithOwner'], timeout),
83
+ gh(repoRoot, ['issue', 'list', '--limit', String(capped), '--json', fields], timeout),
84
+ gh(repoRoot, ['pr', 'list', '--limit', String(capped), '--json', `${fields},isDraft,additions,deletions,statusCheckRollup`], timeout),
85
+ ]);
86
+ // One repo-wide label→color map, filled as we flatten each item's labels.
87
+ const labelColors = {};
88
+ const recordColor = (l) => {
89
+ if (l.color && !labelColors[l.name])
90
+ labelColors[l.name] = l.color;
91
+ };
92
+ const issues = z.array(ghIssueSchema).parse(JSON.parse(issuesOut)).map((i) => {
93
+ i.labels.forEach(recordColor);
94
+ return {
95
+ kind: 'issue',
96
+ number: i.number,
97
+ title: i.title,
98
+ author: i.author?.login ?? '?',
99
+ createdAt: i.createdAt,
100
+ labels: i.labels.map((l) => l.name),
101
+ body: (i.body ?? '').slice(0, 8_000),
102
+ url: i.url,
103
+ comments: 0,
104
+ };
105
+ });
106
+ const prs = z.array(ghPrSchema).parse(JSON.parse(prsOut)).map((p) => {
107
+ p.labels.forEach(recordColor);
108
+ return {
109
+ kind: 'pr',
110
+ number: p.number,
111
+ title: p.title,
112
+ author: p.author?.login ?? '?',
113
+ createdAt: p.createdAt,
114
+ labels: [...p.labels.map((l) => l.name), ...(p.isDraft ? ['draft'] : [])],
115
+ body: (p.body ?? '').slice(0, 8_000),
116
+ url: p.url,
117
+ comments: 0,
118
+ isDraft: p.isDraft,
119
+ additions: p.additions,
120
+ deletions: p.deletions,
121
+ checks: rollupToChecks(p.statusCheckRollup),
122
+ };
123
+ });
124
+ const data = {
125
+ available: true,
126
+ repo: repoOut.trim() || undefined,
127
+ syncedAt: new Date().toISOString(),
128
+ issues,
129
+ prs,
130
+ labelColors,
131
+ };
132
+ cache = { at: Date.now(), limit: capped, data };
133
+ return data;
134
+ }
135
+ catch (err) {
136
+ const message = err instanceof Error ? err.message : String(err);
137
+ const reason = /ENOENT/.test(message)
138
+ ? 'gh CLI not found — install it and run `gh auth login`'
139
+ : firstLine(message);
140
+ return { available: false, reason, issues: [], prs: [] };
141
+ }
142
+ }
143
+ function firstLine(s) {
144
+ return s.split('\n').find((l) => l.trim().length > 0)?.trim() ?? 'gh failed';
145
+ }
146
+ /** CEZ_DRY_RUN=1 — a small fixed catalog so the GitHub tab is demoable offline. */
147
+ function mockGithub() {
148
+ const mk = (over) => ({
149
+ author: 'mock',
150
+ createdAt: new Date(Date.now() - over.number * 3_600_000).toISOString(),
151
+ labels: [],
152
+ url: `https://github.com/mock/repo/${over.kind === 'pr' ? 'pull' : 'issues'}/${over.number}`,
153
+ comments: 0,
154
+ ...over,
155
+ });
156
+ return {
157
+ available: true,
158
+ repo: 'mock/repo',
159
+ syncedAt: new Date().toISOString(),
160
+ issues: [
161
+ mk({ kind: 'issue', number: 142, title: 'Login form drops session on refresh', labels: ['bug', 'auth'], comments: 3, body: 'Repro: log in, hit reload — you land back on /login. The session cookie is set correctly, but the client store rehydrates before the cookie check resolves, so the auth guard redirects.' }),
162
+ mk({ kind: 'issue', number: 139, title: 'Add --json flag to cez CLI output', labels: ['enhancement', 'cli'], comments: 1, body: 'For scripting it would help if `cez list` and `cez status` could emit machine-readable JSON instead of the table view.' }),
163
+ mk({ kind: 'issue', number: 135, title: 'Flaky e2e: worktree cleanup race on cancel', labels: ['bug', 'flaky-test'], comments: 6, body: 'Cancelling a run while the agent holds a file lock leaves a dangling worktree. The next run on the same branch then fails with "worktree already exists".' }),
164
+ ],
165
+ prs: [
166
+ mk({ kind: 'pr', number: 128, title: 'Fix flaky auth test in CI', labels: ['tests'], checks: 'passing', additions: 6, deletions: 3, body: 'Loosens the timing assertion in refresh.test.ts to a realistic budget.' }),
167
+ mk({ kind: 'pr', number: 124, title: 'Rate limit /api/runs', labels: ['server', 'draft'], isDraft: true, checks: 'failing', additions: 118, deletions: 7, comments: 4, body: 'Draft: token-bucket middleware on the runs router. Still needs the config surface and README docs before review.' }),
168
+ ],
169
+ labelColors: {
170
+ bug: 'd73a4a',
171
+ auth: '5319e7',
172
+ enhancement: 'a2eeef',
173
+ cli: '0e8a16',
174
+ 'flaky-test': 'fbca04',
175
+ tests: 'c5def5',
176
+ server: '1d76db',
177
+ draft: '6a737d',
178
+ },
179
+ };
180
+ }
181
+ // ---- draft-PR creation (review gate, spec 009) ------------------------------
182
+ // Final autosave-commit → `git push -u origin cez/<id8>` → `gh pr create
183
+ // --draft`, all executed in the task worktree (gh picks the repo up from the
184
+ // worktree's remote). Every failure maps to a one-line human error — the GUI
185
+ // shows it as a toast plus the manual `git merge <branch>` fallback. Never throws.
186
+ const PR_URL_RE = /https:\/\/github\.com\/[^/\s]+\/[^/\s]+\/pull\/\d+/;
187
+ const PUSH_TIMEOUT_MS = 60_000;
188
+ const PROGRESS_LINES_MAX = 10;
189
+ export async function createDraftPr(input) {
190
+ const { run } = input;
191
+ const worktree = run.worktreePath;
192
+ const branch = run.branch;
193
+ if (!worktree || !branch) {
194
+ return { ok: false, error: 'this task has no worktree/branch to publish' };
195
+ }
196
+ // Final autosave: the branch must hold everything before it leaves the box.
197
+ await autosaveCommit(worktree);
198
+ // DRY-RUN (CEZ_DRY_RUN=1): no push, no gh — simulate success with a fake PR
199
+ // URL so the whole review → PR flow is testable without GitHub.
200
+ if (process.env.CEZ_DRY_RUN === '1') {
201
+ return { ok: true, url: 'https://github.com/open-mercato/demo/pull/777', dryRun: true };
202
+ }
203
+ const remote = await execTool(['remote', 'get-url', 'origin'], worktree, 'git');
204
+ if (!remote.ok || !remote.stdout.trim()) {
205
+ return { ok: false, error: 'no git remote — add one (git remote add origin <url>) or merge the branch locally' };
206
+ }
207
+ const push = await execTool(['push', '-u', 'origin', branch], worktree, 'git', PUSH_TIMEOUT_MS);
208
+ if (!push.ok) {
209
+ return { ok: false, error: `git push failed — ${tail(push.stderr) || 'unknown error'}` };
210
+ }
211
+ const body = buildPrBody(input.handoffText, run.task);
212
+ // Target the branch the worktree forked from (config `baseBranch`) — without
213
+ // --base, gh aims at the repo default (main) even when work started on
214
+ // develop. `origin/x` normalizes to `x`; a raw sha (detached-HEAD fork
215
+ // point) can't be a PR base, so gh falls back to the default branch.
216
+ const prBase = run.baseBranch?.replace(/^origin\//, '');
217
+ const baseArgs = prBase && !/^[0-9a-f]{7,40}$/i.test(prBase) ? ['--base', prBase] : [];
218
+ const pr = await execTool(['pr', 'create', '--draft', '--head', branch, ...baseArgs, '--title', run.title, '--body', body], worktree, 'gh', PUSH_TIMEOUT_MS);
219
+ if (!pr.ok) {
220
+ if (pr.notFound) {
221
+ return { ok: false, error: 'gh not found — install the GitHub CLI and run `gh auth login`, or merge the branch locally' };
222
+ }
223
+ const hint = /auth|log ?in|credential/i.test(pr.stderr) ? ' (try `gh auth login`)' : '';
224
+ return { ok: false, error: `gh pr create failed — ${tail(pr.stderr) || 'unknown error'}${hint}` };
225
+ }
226
+ // gh prints the PR URL on stdout; some versions echo it to stderr instead.
227
+ const match = PR_URL_RE.exec(`${pr.stdout}\n${pr.stderr}`);
228
+ if (!match) {
229
+ return { ok: false, error: 'gh pr create returned no PR URL — check `gh pr list` manually' };
230
+ }
231
+ return { ok: true, url: match[0], dryRun: false };
232
+ }
233
+ /**
234
+ * PR body from the handoff journal: the "## Goal" section (task text as
235
+ * fallback) + the first ~10 lines of "## Progress log" (newest first) +
236
+ * the cezar footer.
237
+ */
238
+ export function buildPrBody(handoffText, task) {
239
+ const goal = section(handoffText, '## Goal') || task.trim();
240
+ const progress = section(handoffText, '## Progress log')
241
+ .split('\n')
242
+ .filter((l) => l.trim())
243
+ .slice(0, PROGRESS_LINES_MAX)
244
+ .join('\n');
245
+ const parts = ['## Goal', '', goal];
246
+ if (progress)
247
+ parts.push('', '## Progress log', '', progress);
248
+ parts.push('', '---', '', '🤖 made with cezar');
249
+ return parts.join('\n');
250
+ }
251
+ /** Text of one `## Header` section, up to the next `## ` header. */
252
+ function section(text, header) {
253
+ const start = text.indexOf(`${header}\n`);
254
+ if (start < 0)
255
+ return '';
256
+ const rest = text.slice(start + header.length + 1);
257
+ const next = rest.indexOf('\n## ');
258
+ return (next >= 0 ? rest.slice(0, next) : rest).trim();
259
+ }
260
+ /** Last 3 stderr lines, pipe-joined — enough context, toast-sized. */
261
+ function tail(stderr) {
262
+ return stderr.trim().split('\n').slice(-3).join(' | ').slice(0, 300);
263
+ }
264
+ function execTool(args, cwd, bin, timeoutMs = 30_000) {
265
+ return new Promise((resolve) => {
266
+ execFile(bin, args, { cwd, timeout: timeoutMs, maxBuffer: 4 * 1024 * 1024, encoding: 'utf8' }, (err, stdout, stderr) => resolve({
267
+ ok: !err,
268
+ stdout: stdout ?? '',
269
+ stderr: stderr ?? '',
270
+ notFound: err?.code === 'ENOENT',
271
+ }));
272
+ });
273
+ }
274
+ // ---- the driver -------------------------------------------------------------
275
+ /** Cached availability probe so `GET /api/health` never pays a full listing. */
276
+ let detectCache = null;
277
+ async function detectGithub(repoRoot) {
278
+ if (process.env.CEZ_DRY_RUN === '1')
279
+ return { available: true };
280
+ if (detectCache && detectCache.repoRoot === repoRoot && Date.now() - detectCache.at < CACHE_MS) {
281
+ return detectCache.result;
282
+ }
283
+ let result;
284
+ try {
285
+ await gh(repoRoot, ['repo', 'view', '--json', 'nameWithOwner'], 5_000);
286
+ result = { available: true };
287
+ }
288
+ catch (err) {
289
+ const message = err instanceof Error ? err.message : String(err);
290
+ result = {
291
+ available: false,
292
+ reason: /ENOENT/.test(message)
293
+ ? 'gh CLI not found — install it and run `gh auth login`'
294
+ : firstLine(message),
295
+ };
296
+ }
297
+ detectCache = { at: Date.now(), repoRoot, result };
298
+ return result;
299
+ }
300
+ /**
301
+ * Non-blocking availability for `GET /api/health` (#major-health-latency): returns the cached
302
+ * probe immediately, or `null` while kicking off a background probe to warm it. It NEVER shells
303
+ * out to `gh` on the request that reads it, so health stays under the bookmarklet's 800 ms port
304
+ * budget (a `gh repo view` round-trip is ~500–650 ms on its own). `null` is contract-safe — the
305
+ * whole `forge` field is additive, so "unknown until warm" is a valid answer.
306
+ */
307
+ export function detectGithubCached(repoRoot) {
308
+ if (process.env.CEZ_DRY_RUN === '1')
309
+ return { available: true };
310
+ if (detectCache && detectCache.repoRoot === repoRoot && Date.now() - detectCache.at < CACHE_MS) {
311
+ return detectCache.result;
312
+ }
313
+ void detectGithub(repoRoot).catch(() => { }); // warm the cache off the request path
314
+ return null;
315
+ }
316
+ const GH_PR_STATES = {
317
+ MERGED: 'merged',
318
+ CLOSED: 'closed',
319
+ };
320
+ export function createGithubDriver(repoRoot, repoRef) {
321
+ return {
322
+ kind: 'github',
323
+ detect: () => detectGithub(repoRoot),
324
+ detectCached: () => detectGithubCached(repoRoot),
325
+ listIssues: async (opts) => (await fetchGithub(repoRoot, opts?.refresh, opts?.limit)).issues,
326
+ listPRs: async (opts) => (await fetchGithub(repoRoot, opts?.refresh, opts?.limit)).prs,
327
+ createPR: (input) => createDraftPr(input),
328
+ // Null covers everything from "no PR yet" to "gh missing" — the callers
329
+ // (Create PR → View PR flip) treat all of it as "nothing to link".
330
+ prStatus: async (branch) => {
331
+ if (process.env.CEZ_DRY_RUN === '1')
332
+ return null;
333
+ try {
334
+ const out = await gh(repoRoot, ['pr', 'view', branch, '--json', 'number,url,state,isDraft,statusCheckRollup']);
335
+ const pr = ghPrViewSchema.parse(JSON.parse(out));
336
+ return {
337
+ number: pr.number,
338
+ url: pr.url,
339
+ state: GH_PR_STATES[pr.state.toUpperCase()] ?? 'open',
340
+ isDraft: pr.isDraft,
341
+ checks: rollupToChecks(pr.statusCheckRollup) ?? null,
342
+ };
343
+ }
344
+ catch {
345
+ return null;
346
+ }
347
+ },
348
+ viewUrl: (kind, ref) => {
349
+ if (!repoRef)
350
+ return null;
351
+ const base = `https://github.com/${repoRef.owner}/${repoRef.repo}`;
352
+ // Branch names may contain '/' — encode per segment, keep the slashes.
353
+ const path = String(ref).split('/').map(encodeURIComponent).join('/');
354
+ switch (kind) {
355
+ case 'repo':
356
+ return base;
357
+ case 'issue':
358
+ return `${base}/issues/${path}`;
359
+ case 'pr':
360
+ return `${base}/pull/${path}`;
361
+ case 'branch':
362
+ return `${base}/tree/${path}`;
363
+ case 'commit':
364
+ return `${base}/commit/${path}`;
365
+ }
366
+ },
367
+ };
368
+ }
369
+ //# sourceMappingURL=github.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.js","sourceRoot":"","sources":["../../../src/server/forge/github.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { RepoInfo } from '../git.js';
2
+ import type { ForgeDriver } from './types.js';
3
+ /**
4
+ * Forge resolution (cockpit-ui redesign spec §"Forge-driver seam"): map the
5
+ * repo's origin remote to a driver — github.com → the GitHub driver, anything
6
+ * else (GitLab, self-hosted, no remote, not a repo) → null. The health route
7
+ * serializes the result as `forge: {kind, available, reason?} | null`; a null
8
+ * forge means plain-git features only (diffs, commit, push, branches).
9
+ */
10
+ export interface ParsedRemote {
11
+ host: string;
12
+ owner: string;
13
+ repo: string;
14
+ }
15
+ /**
16
+ * Parse a git remote URL into host/owner/repo. Handles the scheme forms
17
+ * (`https://`, `ssh://`, `git://`, with optional credentials and port) and the
18
+ * scp-like form (`git@host:owner/repo.git`). Null for local paths and anything
19
+ * else that doesn't look like a forge remote.
20
+ */
21
+ export declare function parseRemote(remote: string): ParsedRemote | null;
22
+ /** Remote host → driver | null. GitLab lands here later as one more case. */
23
+ export declare function resolveForge(repoInfo: RepoInfo | null): ForgeDriver | null;
24
+ export type { ForgeDriver, ForgeAvailability, ForgeItem, ForgeKind, ForgePrStatus, ForgeRefKind } from './types.js';
@@ -0,0 +1,45 @@
1
+ import { createGithubDriver } from './github.js';
2
+ /**
3
+ * Parse a git remote URL into host/owner/repo. Handles the scheme forms
4
+ * (`https://`, `ssh://`, `git://`, with optional credentials and port) and the
5
+ * scp-like form (`git@host:owner/repo.git`). Null for local paths and anything
6
+ * else that doesn't look like a forge remote.
7
+ */
8
+ export function parseRemote(remote) {
9
+ const r = remote.trim().replace(/\/+$/, '');
10
+ let host;
11
+ let path;
12
+ const url = /^(?:https?|ssh|git|git\+ssh):\/\/(?:[^@/]+@)?([^/:]+)(?::\d+)?\/(.+)$/.exec(r);
13
+ if (url) {
14
+ [, host, path] = url;
15
+ }
16
+ else {
17
+ // scp-like: [user@]host:owner/repo(.git) — a leading '/' (local path)
18
+ // can't match the host group, so plain directories fall through to null.
19
+ const scp = /^(?:[^@/:]+@)?([^:/]+):(.+)$/.exec(r);
20
+ if (!scp)
21
+ return null;
22
+ [, host, path] = scp;
23
+ }
24
+ if (!host || !path)
25
+ return null;
26
+ const parts = path.replace(/\.git$/i, '').split('/').filter(Boolean);
27
+ const owner = parts[parts.length - 2];
28
+ const repo = parts[parts.length - 1];
29
+ if (!owner || !repo)
30
+ return null;
31
+ return { host: host.toLowerCase(), owner, repo };
32
+ }
33
+ /** Remote host → driver | null. GitLab lands here later as one more case. */
34
+ export function resolveForge(repoInfo) {
35
+ if (!repoInfo?.remote)
36
+ return null;
37
+ const parsed = parseRemote(repoInfo.remote);
38
+ if (!parsed)
39
+ return null;
40
+ if (parsed.host === 'github.com') {
41
+ return createGithubDriver(repoInfo.root, { owner: parsed.owner, repo: parsed.repo });
42
+ }
43
+ return null;
44
+ }
45
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/server/forge/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAiBjD;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC5C,IAAI,IAAwB,CAAC;IAC7B,IAAI,IAAwB,CAAC;IAC7B,MAAM,GAAG,GAAG,uEAAuE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5F,IAAI,GAAG,EAAE,CAAC;QACR,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,GAAG,CAAC;IACvB,CAAC;SAAM,CAAC;QACN,sEAAsE;QACtE,yEAAyE;QACzE,MAAM,GAAG,GAAG,8BAA8B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnD,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC;QACtB,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,GAAG,CAAC;IACvB,CAAC;IACD,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAChC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACrE,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACtC,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACrC,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACjC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACnD,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,YAAY,CAAC,QAAyB;IACpD,IAAI,CAAC,QAAQ,EAAE,MAAM;QAAE,OAAO,IAAI,CAAC;IACnC,MAAM,MAAM,GAAG,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC5C,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,IAAI,MAAM,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QACjC,OAAO,kBAAkB,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IACvF,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,80 @@
1
+ import type { RunRecord } from '../../runs/store.js';
2
+ /**
3
+ * Forge-driver seam (cockpit-ui redesign spec §"Forge-driver seam"): every
4
+ * code-forge integration (GitHub today, GitLab later) implements `ForgeDriver`.
5
+ * The interface is shaped strictly around what the cockpit already does via
6
+ * `gh` — issue/PR listing for the GitHub tab, draft-PR creation for the review
7
+ * gate, a per-branch PR probe, and web-URL building. Adding a forge = one new
8
+ * driver file behind `resolveForge`, no route or UI changes.
9
+ */
10
+ export type ForgeKind = 'github';
11
+ /** Availability probe result — mirrors the tab's quiet degradation contract:
12
+ * no CLI, no remote, offline all land on `available:false` + a human hint. */
13
+ export interface ForgeAvailability {
14
+ available: boolean;
15
+ /** Human-readable hint when unavailable (`gh` missing, no remote, offline…). */
16
+ reason?: string;
17
+ }
18
+ /** One issue or pull request, flattened for the cockpit. `/api/github` serves
19
+ * exactly this shape (BACKWARD_COMPATIBILITY.md §2 — do not reshape). */
20
+ export interface ForgeItem {
21
+ kind: 'issue' | 'pr';
22
+ number: number;
23
+ title: string;
24
+ author: string;
25
+ createdAt: string;
26
+ labels: string[];
27
+ body: string;
28
+ url: string;
29
+ comments: number;
30
+ /** PRs only. */
31
+ isDraft?: boolean;
32
+ additions?: number;
33
+ deletions?: number;
34
+ checks?: 'passing' | 'failing' | 'pending' | null;
35
+ }
36
+ export interface ForgeListOptions {
37
+ /** Bypass the driver's short cache. */
38
+ refresh?: boolean;
39
+ /** Max items to fetch (driver-capped). */
40
+ limit?: number;
41
+ }
42
+ /** Where an existing branch's PR stands — feeds the Create PR → View PR flip. */
43
+ export interface ForgePrStatus {
44
+ number: number;
45
+ url: string;
46
+ state: 'open' | 'merged' | 'closed';
47
+ isDraft: boolean;
48
+ checks: 'passing' | 'failing' | 'pending' | null;
49
+ }
50
+ export type ForgeRefKind = 'repo' | 'issue' | 'pr' | 'branch' | 'commit';
51
+ export type DraftPrOutcome = {
52
+ ok: true;
53
+ url: string;
54
+ dryRun: boolean;
55
+ } | {
56
+ ok: false;
57
+ error: string;
58
+ };
59
+ export interface DraftPrInput {
60
+ repoRoot: string;
61
+ run: RunRecord;
62
+ /** The task's handoff.md — becomes the PR body (goal + progress skim). */
63
+ handoffText: string;
64
+ }
65
+ export interface ForgeDriver {
66
+ readonly kind: ForgeKind;
67
+ /** Cheap, cached availability probe. May shell out (used by the GitHub tab). */
68
+ detect(): Promise<ForgeAvailability>;
69
+ /** Non-blocking availability for the health path: cached result, or null while warming — never
70
+ * shells out on the read (keeps /api/health under the bookmarklet's latency budget). */
71
+ detectCached(): ForgeAvailability | null;
72
+ listIssues(opts?: ForgeListOptions): Promise<ForgeItem[]>;
73
+ listPRs(opts?: ForgeListOptions): Promise<ForgeItem[]>;
74
+ /** Draft-PR creation for the review gate (spec 009). Never throws. */
75
+ createPR(input: DraftPrInput): Promise<DraftPrOutcome>;
76
+ /** The branch's open/merged PR, or null when none (or the forge is down). */
77
+ prStatus(branch: string): Promise<ForgePrStatus | null>;
78
+ /** Web URL for a ref on the forge, or null when the remote isn't parseable. */
79
+ viewUrl(kind: ForgeRefKind, ref: string | number): string | null;
80
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/server/forge/types.ts"],"names":[],"mappings":""}