@pat-lewczuk/cezar 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +90 -0
  2. package/dist/core/agent-runner.d.ts +95 -0
  3. package/dist/core/agent-runner.js +8 -0
  4. package/dist/core/agent-runner.js.map +1 -0
  5. package/dist/core/backend-detect.d.ts +14 -0
  6. package/dist/core/backend-detect.js +78 -0
  7. package/dist/core/backend-detect.js.map +1 -0
  8. package/dist/core/claude-cli-runner.d.ts +68 -0
  9. package/dist/core/claude-cli-runner.js +424 -0
  10. package/dist/core/claude-cli-runner.js.map +1 -0
  11. package/dist/core/usage.d.ts +11 -0
  12. package/dist/core/usage.js +15 -0
  13. package/dist/core/usage.js.map +1 -0
  14. package/dist/index.d.ts +2 -0
  15. package/dist/index.js +294 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/runs/store.d.ts +218 -0
  18. package/dist/runs/store.js +286 -0
  19. package/dist/runs/store.js.map +1 -0
  20. package/dist/server/git.d.ts +21 -0
  21. package/dist/server/git.js +54 -0
  22. package/dist/server/git.js.map +1 -0
  23. package/dist/server/open-in-terminal.d.ts +11 -0
  24. package/dist/server/open-in-terminal.js +84 -0
  25. package/dist/server/open-in-terminal.js.map +1 -0
  26. package/dist/server/server.d.ts +12 -0
  27. package/dist/server/server.js +243 -0
  28. package/dist/server/server.js.map +1 -0
  29. package/dist/skills.d.ts +31 -0
  30. package/dist/skills.js +117 -0
  31. package/dist/skills.js.map +1 -0
  32. package/dist/workflows/load.d.ts +15 -0
  33. package/dist/workflows/load.js +58 -0
  34. package/dist/workflows/load.js.map +1 -0
  35. package/dist/workflows/run.d.ts +52 -0
  36. package/dist/workflows/run.js +452 -0
  37. package/dist/workflows/run.js.map +1 -0
  38. package/dist/workflows/types.d.ts +202 -0
  39. package/dist/workflows/types.js +56 -0
  40. package/dist/workflows/types.js.map +1 -0
  41. package/package.json +44 -0
  42. package/scripts/mock-claude.mjs +106 -0
  43. package/web/app.js +634 -0
  44. package/web/index.html +48 -0
  45. package/web/style.css +317 -0
@@ -0,0 +1,243 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { Hono } from 'hono';
5
+ import { serve } from '@hono/node-server';
6
+ import { streamSSE } from 'hono/streaming';
7
+ import { z } from 'zod';
8
+ import { detectEnvironment } from '../core/backend-detect.js';
9
+ import { loadWorkflows } from '../workflows/load.js';
10
+ import { discoverSkills } from '../skills.js';
11
+ import { getDiff, getLog, getRepoInfo, getStatus } from './git.js';
12
+ import { openInTerminal } from './open-in-terminal.js';
13
+ const startRunSchema = z.object({
14
+ workflow: z.string().min(1),
15
+ task: z.string().min(1),
16
+ model: z.string().optional(),
17
+ });
18
+ const messageSchema = z
19
+ .object({
20
+ text: z.string().max(100_000).default(''),
21
+ images: z
22
+ .array(z.object({
23
+ mediaType: z.string().regex(/^image\//),
24
+ // ~5 MB per image once base64-decoded.
25
+ data: z.string().min(1).max(7_000_000),
26
+ }))
27
+ .max(4)
28
+ .default([]),
29
+ })
30
+ .refine((m) => m.text.trim().length > 0 || m.images.length > 0, {
31
+ message: 'message needs text or at least one image',
32
+ });
33
+ export function createApp(deps) {
34
+ const { repoRoot, store, manager, version } = deps;
35
+ const app = new Hono();
36
+ // ---- static GUI ----------------------------------------------------------
37
+ const webDir = resolveWebDir();
38
+ const staticFile = (name, type) => () => {
39
+ // Read per request — the files are tiny and this keeps dev iteration live.
40
+ const body = readFileSync(join(webDir, name));
41
+ return new Response(body, { headers: { 'content-type': type } });
42
+ };
43
+ app.get('/', staticFile('index.html', 'text/html; charset=utf-8'));
44
+ app.get('/app.js', staticFile('app.js', 'text/javascript; charset=utf-8'));
45
+ app.get('/style.css', staticFile('style.css', 'text/css; charset=utf-8'));
46
+ // ---- meta ----------------------------------------------------------------
47
+ app.get('/api/health', async (c) => {
48
+ const [checks, repo] = await Promise.all([detectEnvironment(), getRepoInfo(repoRoot)]);
49
+ return c.json({ version, repoRoot, repo, checks });
50
+ });
51
+ app.get('/api/skills', async (c) => c.json(await discoverSkills(repoRoot)));
52
+ app.get('/api/workflows', async (c) => c.json(await loadWorkflows(repoRoot)));
53
+ // ---- runs ----------------------------------------------------------------
54
+ app.get('/api/runs', (c) => c.json(store.listRuns()));
55
+ // Registered before the `/:id/...` routes so "archive-finished" never
56
+ // matches as a run id.
57
+ app.post('/api/runs/archive-finished', (c) => c.json({ archived: store.archiveFinished() }));
58
+ app.post('/api/runs/:id/archive', async (c) => {
59
+ const id = c.req.param('id');
60
+ const body = (await c.req.json().catch(() => ({})));
61
+ const run = store.setArchived(id, body.archived !== false);
62
+ return run ? c.json(run) : c.json({ error: 'not found' }, 404);
63
+ });
64
+ app.post('/api/runs', async (c) => {
65
+ const parsed = startRunSchema.safeParse(await c.req.json().catch(() => null));
66
+ if (!parsed.success) {
67
+ return c.json({ error: parsed.error.issues.map((i) => i.message).join('; ') }, 400);
68
+ }
69
+ const { workflows } = await loadWorkflows(repoRoot);
70
+ const workflow = workflows.find((w) => w.name === parsed.data.workflow);
71
+ if (!workflow)
72
+ return c.json({ error: `unknown workflow: ${parsed.data.workflow}` }, 404);
73
+ const run = manager.startRun(workflow, { task: parsed.data.task, model: parsed.data.model });
74
+ return c.json(run, 201);
75
+ });
76
+ app.get('/api/runs/:id', (c) => {
77
+ const run = store.getRun(c.req.param('id'));
78
+ return run ? c.json(run) : c.json({ error: 'not found' }, 404);
79
+ });
80
+ app.post('/api/runs/:id/cancel', (c) => {
81
+ const id = c.req.param('id');
82
+ if (!store.getRun(id))
83
+ return c.json({ error: 'not found' }, 404);
84
+ const cancelled = manager.cancel(id);
85
+ return c.json({ cancelled });
86
+ });
87
+ // Live-session participation (spec 002): deliver a user message (text +
88
+ // pasted screenshots) into the run's open claude session.
89
+ app.post('/api/runs/:id/messages', async (c) => {
90
+ const id = c.req.param('id');
91
+ if (!store.getRun(id))
92
+ return c.json({ error: 'not found' }, 404);
93
+ const parsed = messageSchema.safeParse(await c.req.json().catch(() => null));
94
+ if (!parsed.success) {
95
+ return c.json({ error: parsed.error.issues.map((i) => i.message).join('; ') }, 400);
96
+ }
97
+ const content = [
98
+ ...parsed.data.images.map((img) => ({
99
+ type: 'image',
100
+ source: { type: 'base64', media_type: img.mediaType, data: img.data },
101
+ })),
102
+ ...(parsed.data.text.trim()
103
+ ? [{ type: 'text', text: parsed.data.text }]
104
+ : []),
105
+ ];
106
+ const delivered = manager.sendMessage(id, content);
107
+ if (!delivered)
108
+ return c.json({ error: 'session closed' }, 409);
109
+ return c.json({ delivered: true });
110
+ });
111
+ // "Finish": gracefully close a waiting session — the run completes as done.
112
+ app.post('/api/runs/:id/finish', (c) => {
113
+ const id = c.req.param('id');
114
+ if (!store.getRun(id))
115
+ return c.json({ error: 'not found' }, 404);
116
+ const finished = manager.finish(id);
117
+ if (!finished)
118
+ return c.json({ error: 'no open session' }, 409);
119
+ return c.json({ finished: true });
120
+ });
121
+ // "Continue" (spec 003): reopen a finished run's session in-process.
122
+ app.post('/api/runs/:id/continue', async (c) => {
123
+ const id = c.req.param('id');
124
+ if (!store.getRun(id))
125
+ return c.json({ error: 'not found' }, 404);
126
+ const body = (await c.req.json().catch(() => ({})));
127
+ const result = manager.continueRun(id, typeof body.text === 'string' ? body.text : undefined);
128
+ if (!result.ok)
129
+ return c.json({ error: result.error }, 409);
130
+ return c.json({ continued: true });
131
+ });
132
+ // "Open in terminal" (spec 003): hand the session off to a real terminal.
133
+ app.post('/api/runs/:id/open-in-cli', async (c) => {
134
+ const id = c.req.param('id');
135
+ const run = store.getRun(id);
136
+ if (!run)
137
+ return c.json({ error: 'not found' }, 404);
138
+ const sessionId = [...run.steps].reverse().find((s) => s.sessionId)?.sessionId;
139
+ if (!sessionId)
140
+ return c.json({ error: 'no agent session to resume' }, 409);
141
+ const command = `claude --resume ${sessionId}`;
142
+ const opened = await openInTerminal(repoRoot, command);
143
+ if (!opened) {
144
+ return c.json({ error: 'no terminal emulator found', command: `cd '${repoRoot}' && ${command}` }, 409);
145
+ }
146
+ return c.json({ opened: true, command });
147
+ });
148
+ app.delete('/api/runs/:id', (c) => {
149
+ const id = c.req.param('id');
150
+ if (manager.isActive(id))
151
+ return c.json({ error: 'run is active — cancel it first' }, 409);
152
+ return store.deleteRun(id) ? c.json({ deleted: true }) : c.json({ error: 'not found' }, 404);
153
+ });
154
+ // Per-run SSE: full replay from the NDJSON file, then live events. The
155
+ // listener attaches before the replay and buffers, so nothing emitted
156
+ // during the replay is lost or duplicated (dedup by seq).
157
+ app.get('/api/runs/:id/events', (c) => {
158
+ const id = c.req.param('id');
159
+ if (!store.getRun(id))
160
+ return c.json({ error: 'not found' }, 404);
161
+ return streamSSE(c, async (stream) => {
162
+ let replaying = true;
163
+ let maxSeq = 0;
164
+ const buffered = [];
165
+ const writeEvent = (event) => stream.writeSSE({ event: 'run-event', data: JSON.stringify(event) });
166
+ const onEvent = (payload) => {
167
+ if (payload.runId !== id)
168
+ return;
169
+ if (replaying)
170
+ buffered.push(payload.event);
171
+ else
172
+ void writeEvent(payload.event);
173
+ };
174
+ const onRun = (run) => {
175
+ if (run.id !== id)
176
+ return;
177
+ void stream.writeSSE({ event: 'run', data: JSON.stringify(run) });
178
+ };
179
+ store.on('event', onEvent);
180
+ store.on('run', onRun);
181
+ stream.onAbort(() => {
182
+ store.off('event', onEvent);
183
+ store.off('run', onRun);
184
+ });
185
+ for (const event of store.readEvents(id)) {
186
+ maxSeq = Math.max(maxSeq, event.seq);
187
+ await writeEvent(event);
188
+ }
189
+ replaying = false;
190
+ for (const event of buffered) {
191
+ if (event.seq > maxSeq)
192
+ await writeEvent(event);
193
+ }
194
+ const run = store.getRun(id);
195
+ if (run)
196
+ await stream.writeSSE({ event: 'run', data: JSON.stringify(run) });
197
+ while (!stream.aborted) {
198
+ await stream.writeSSE({ event: 'ping', data: '' });
199
+ await stream.sleep(15_000);
200
+ }
201
+ });
202
+ });
203
+ // Global SSE: run-summary updates for the list view.
204
+ app.get('/api/events', (c) => streamSSE(c, async (stream) => {
205
+ const onRun = (run) => void stream.writeSSE({ event: 'run', data: JSON.stringify(run) });
206
+ const onDeleted = (id) => void stream.writeSSE({ event: 'run-deleted', data: JSON.stringify({ id }) });
207
+ store.on('run', onRun);
208
+ store.on('deleted', onDeleted);
209
+ stream.onAbort(() => {
210
+ store.off('run', onRun);
211
+ store.off('deleted', onDeleted);
212
+ });
213
+ while (!stream.aborted) {
214
+ await stream.writeSSE({ event: 'ping', data: '' });
215
+ await stream.sleep(15_000);
216
+ }
217
+ }));
218
+ // ---- repo view -----------------------------------------------------------
219
+ app.get('/api/repo', async (c) => {
220
+ const info = await getRepoInfo(repoRoot);
221
+ if (!info)
222
+ return c.json({ info: null, status: [], log: [] });
223
+ const [status, log] = await Promise.all([getStatus(info.root), getLog(info.root)]);
224
+ return c.json({ info, status, log });
225
+ });
226
+ app.get('/api/repo/diff', async (c) => {
227
+ const info = await getRepoInfo(repoRoot);
228
+ if (!info)
229
+ return c.text('not a git repository');
230
+ return c.text(await getDiff(info.root));
231
+ });
232
+ return app;
233
+ }
234
+ export function startServer(deps, port) {
235
+ const app = createApp(deps);
236
+ return serve({ fetch: app.fetch, port, hostname: '127.0.0.1' });
237
+ }
238
+ function resolveWebDir() {
239
+ const here = dirname(fileURLToPath(import.meta.url));
240
+ // here = <pkg>/dist/server (built) or <pkg>/src/server (tsx dev).
241
+ return join(here, '..', '..', 'web');
242
+ }
243
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * A skill is a Markdown file with optional YAML-ish frontmatter (`name`,
3
+ * `description`). Discovered from the repo's `.ai/skills/` (shared with other
4
+ * agent tooling) and `.ai/cezar/skills/` (cez-local). Adapted from
5
+ * @cezar/core's skill-catalog, trimmed to two on-disk sources.
6
+ */
7
+ export interface Skill {
8
+ name: string;
9
+ description?: string;
10
+ body: string;
11
+ path: string;
12
+ source: 'ai' | 'cezar';
13
+ }
14
+ /**
15
+ * Discover the merged skill catalog for a repo. `.ai/cezar/skills` wins name
16
+ * collisions over `.ai/skills`. Missing directories are fine — an empty
17
+ * catalog is fully supported (steps fall back to their plain prompt).
18
+ */
19
+ export declare function discoverSkills(repoRoot: string): Promise<Skill[]>;
20
+ type FrontmatterValue = string | string[];
21
+ /**
22
+ * Tiny purpose-built frontmatter parser — a leading `---\n … \n---\n` block
23
+ * with `key: value` lines, `key: [a, b]` inline arrays and `key:` + ` - a`
24
+ * block arrays. Deliberately not full YAML so we avoid a parser dependency
25
+ * for skill files.
26
+ */
27
+ export declare function parseFrontmatter(raw: string): {
28
+ frontmatter: Record<string, FrontmatterValue>;
29
+ body: string;
30
+ };
31
+ export {};
package/dist/skills.js ADDED
@@ -0,0 +1,117 @@
1
+ import { readdir, readFile } from 'node:fs/promises';
2
+ import { join, resolve, basename, extname } from 'node:path';
3
+ const SKILL_DIRS = [
4
+ { dir: '.ai/cezar/skills', source: 'cezar' },
5
+ { dir: '.ai/skills', source: 'ai' },
6
+ ];
7
+ /**
8
+ * Discover the merged skill catalog for a repo. `.ai/cezar/skills` wins name
9
+ * collisions over `.ai/skills`. Missing directories are fine — an empty
10
+ * catalog is fully supported (steps fall back to their plain prompt).
11
+ */
12
+ export async function discoverSkills(repoRoot) {
13
+ const lists = await Promise.all(SKILL_DIRS.map(({ dir, source }) => readMarkdownSkills(resolve(repoRoot, dir), source)));
14
+ const merged = [];
15
+ const seen = new Set();
16
+ for (const skills of lists) {
17
+ for (const skill of skills) {
18
+ if (seen.has(skill.name))
19
+ continue;
20
+ seen.add(skill.name);
21
+ merged.push(skill);
22
+ }
23
+ }
24
+ merged.sort((a, b) => a.name.localeCompare(b.name));
25
+ return merged;
26
+ }
27
+ async function readMarkdownSkills(dir, source) {
28
+ let entries;
29
+ try {
30
+ entries = await readdir(dir, { recursive: true });
31
+ }
32
+ catch {
33
+ return [];
34
+ }
35
+ const skills = [];
36
+ for (const rel of entries.filter((e) => extname(e).toLowerCase() === '.md')) {
37
+ const absPath = join(dir, rel);
38
+ let raw;
39
+ try {
40
+ raw = await readFile(absPath, 'utf8');
41
+ }
42
+ catch {
43
+ continue;
44
+ }
45
+ const { frontmatter, body } = parseFrontmatter(raw);
46
+ const name = typeof frontmatter.name === 'string' && frontmatter.name.trim()
47
+ ? frontmatter.name.trim()
48
+ : basename(rel, extname(rel));
49
+ const description = typeof frontmatter.description === 'string' && frontmatter.description.trim()
50
+ ? frontmatter.description.trim()
51
+ : undefined;
52
+ skills.push({ name, description, body, path: absPath, source });
53
+ }
54
+ return skills;
55
+ }
56
+ /**
57
+ * Tiny purpose-built frontmatter parser — a leading `---\n … \n---\n` block
58
+ * with `key: value` lines, `key: [a, b]` inline arrays and `key:` + ` - a`
59
+ * block arrays. Deliberately not full YAML so we avoid a parser dependency
60
+ * for skill files.
61
+ */
62
+ export function parseFrontmatter(raw) {
63
+ // Normalize CRLF and lone CR — otherwise frontmatter is silently dropped.
64
+ const text = raw.replace(/\r\n?/g, '\n');
65
+ if (!text.startsWith('---\n'))
66
+ return { frontmatter: {}, body: raw };
67
+ // Match the closing delimiter only on its own line so a `---` thematic
68
+ // break inside the body doesn't terminate the block early.
69
+ const end = text.indexOf('\n---\n', 4);
70
+ const endAtEof = text.endsWith('\n---') ? text.length - 4 : -1;
71
+ const closeAt = end === -1 ? endAtEof : end;
72
+ if (closeAt === -1)
73
+ return { frontmatter: {}, body: raw };
74
+ const block = text.slice(4, closeAt);
75
+ const afterDelimiter = end === -1 ? -1 : text.indexOf('\n', closeAt + 1);
76
+ const body = afterDelimiter === -1 ? '' : text.slice(afterDelimiter + 1);
77
+ const frontmatter = {};
78
+ const lines = block.split('\n');
79
+ for (let i = 0; i < lines.length; i++) {
80
+ const line = lines[i] ?? '';
81
+ if (!line.trim() || line.trim().startsWith('#'))
82
+ continue;
83
+ const m = /^([A-Za-z0-9_-]+):\s*(.*)$/.exec(line);
84
+ if (!m)
85
+ continue;
86
+ const key = m[1];
87
+ const rest = (m[2] ?? '').trim();
88
+ if (rest === '') {
89
+ const items = [];
90
+ while (i + 1 < lines.length && /^\s*-\s+/.test(lines[i + 1] ?? '')) {
91
+ items.push(stripQuotes((lines[i + 1] ?? '').replace(/^\s*-\s+/, '').trim()));
92
+ i++;
93
+ }
94
+ frontmatter[key] = items;
95
+ continue;
96
+ }
97
+ if (rest.startsWith('[') && rest.endsWith(']')) {
98
+ const inner = rest.slice(1, -1).trim();
99
+ frontmatter[key] = inner
100
+ ? inner
101
+ .split(',')
102
+ .map((s) => stripQuotes(s.trim()))
103
+ .filter((s) => s.length > 0)
104
+ : [];
105
+ continue;
106
+ }
107
+ frontmatter[key] = stripQuotes(rest);
108
+ }
109
+ return { frontmatter, body };
110
+ }
111
+ function stripQuotes(s) {
112
+ if ((s.startsWith('"') && s.endsWith('"')) || (s.startsWith("'") && s.endsWith("'"))) {
113
+ return s.slice(1, -1);
114
+ }
115
+ return s;
116
+ }
117
+ //# sourceMappingURL=skills.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.js","sourceRoot":"","sources":["../src/skills.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { type WorkflowDef } from './types.js';
2
+ export declare const WORKFLOWS_DIR = ".ai/cezar/workflows";
3
+ export interface WorkflowLoadIssue {
4
+ path: string;
5
+ message: string;
6
+ }
7
+ /**
8
+ * Load the workflow catalog: the built-in `quick-task` plus every
9
+ * `.ai/cezar/workflows/*.{yaml,yml}` in the repo. File workflows win name
10
+ * collisions with built-ins. Invalid files are reported, never fatal.
11
+ */
12
+ export declare function loadWorkflows(repoRoot: string): Promise<{
13
+ workflows: WorkflowDef[];
14
+ issues: WorkflowLoadIssue[];
15
+ }>;
@@ -0,0 +1,58 @@
1
+ import { readdir, readFile } from 'node:fs/promises';
2
+ import { extname, join, resolve } from 'node:path';
3
+ import { parse as parseYaml } from 'yaml';
4
+ import { QUICK_TASK_WORKFLOW, workflowFileSchema } from './types.js';
5
+ export const WORKFLOWS_DIR = '.ai/cezar/workflows';
6
+ /**
7
+ * Load the workflow catalog: the built-in `quick-task` plus every
8
+ * `.ai/cezar/workflows/*.{yaml,yml}` in the repo. File workflows win name
9
+ * collisions with built-ins. Invalid files are reported, never fatal.
10
+ */
11
+ export async function loadWorkflows(repoRoot) {
12
+ const dir = resolve(repoRoot, WORKFLOWS_DIR);
13
+ const issues = [];
14
+ const fromFiles = [];
15
+ let entries = [];
16
+ try {
17
+ entries = await readdir(dir);
18
+ }
19
+ catch {
20
+ // no workflows dir — built-ins only
21
+ }
22
+ for (const entry of entries) {
23
+ const ext = extname(entry).toLowerCase();
24
+ if (ext !== '.yaml' && ext !== '.yml')
25
+ continue;
26
+ const path = join(dir, entry);
27
+ try {
28
+ const raw = await readFile(path, 'utf8');
29
+ const parsed = workflowFileSchema.safeParse(parseYaml(raw));
30
+ if (!parsed.success) {
31
+ issues.push({ path, message: parsed.error.issues.map((i) => i.message).join('; ') });
32
+ continue;
33
+ }
34
+ // Steps referenced by onFail.retry must exist and come earlier.
35
+ const ids = parsed.data.steps.map((s) => s.id);
36
+ const badRetry = parsed.data.steps.find((s) => s.onFail && ids.indexOf(s.onFail.retry) >= ids.indexOf(s.id));
37
+ if (badRetry?.onFail) {
38
+ issues.push({
39
+ path,
40
+ message: `step "${badRetry.id}": onFail.retry must reference an earlier step (got "${badRetry.onFail.retry}")`,
41
+ });
42
+ continue;
43
+ }
44
+ fromFiles.push({ ...parsed.data, source: 'file', path });
45
+ }
46
+ catch (err) {
47
+ issues.push({ path, message: err instanceof Error ? err.message : String(err) });
48
+ }
49
+ }
50
+ const fileNames = new Set(fromFiles.map((w) => w.name));
51
+ const workflows = [
52
+ ...fromFiles,
53
+ ...[QUICK_TASK_WORKFLOW].filter((w) => !fileNames.has(w.name)),
54
+ ];
55
+ workflows.sort((a, b) => a.name.localeCompare(b.name));
56
+ return { workflows, issues };
57
+ }
58
+ //# sourceMappingURL=load.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load.js","sourceRoot":"","sources":["../../src/workflows/load.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ import type { ContentBlock } from '../core/agent-runner.js';
2
+ import type { RunRecord, RunStore } from '../runs/store.js';
3
+ import { type WorkflowDef } from './types.js';
4
+ /** An interactive session that hears nothing from the user closes itself. */
5
+ export declare const IDLE_TIMEOUT_MS: number;
6
+ export interface StartRunInput {
7
+ task: string;
8
+ model?: string;
9
+ }
10
+ /**
11
+ * The mini workflow engine: executes a `WorkflowDef` against a repo, one step
12
+ * at a time, persisting every event to the RunStore (which the SSE endpoints
13
+ * relay live to the GUI). No GitHub choreography — agent steps and shell
14
+ * checks with bounded retry loops, plus live sessions: the last agent step
15
+ * stays open for follow-ups (`waiting`) until "finish", idle timeout, or
16
+ * cancel.
17
+ */
18
+ export declare class RunManager {
19
+ private readonly store;
20
+ private readonly repoRoot;
21
+ private readonly active;
22
+ constructor(store: RunStore, repoRoot: string);
23
+ startRun(workflow: WorkflowDef, input: StartRunInput): RunRecord;
24
+ cancel(runId: string): boolean;
25
+ isActive(runId: string): boolean;
26
+ /**
27
+ * Deliver a user message into the run's live claude session (mid-turn or
28
+ * while `waiting`). Returns false when there is no open session — the GUI
29
+ * then offers "Continue" instead.
30
+ */
31
+ sendMessage(runId: string, content: ContentBlock[]): boolean;
32
+ /** Close the open session gracefully — the run then completes as `done`. */
33
+ finish(runId: string): boolean;
34
+ /**
35
+ * "Continue" (spec 003): reopen a finished run's claude session in-process
36
+ * (`claude --resume <sessionId>`) as a new synthetic step. The session then
37
+ * behaves exactly like an interactive step: `waiting` after each turn,
38
+ * messages via sendMessage, closed by finish/idle/cancel.
39
+ */
40
+ continueRun(runId: string, text?: string): {
41
+ ok: boolean;
42
+ error?: string;
43
+ };
44
+ private runContinuation;
45
+ private execute;
46
+ /** Returns an error message, or null on success. */
47
+ private runAgentStep;
48
+ private armIdleTimer;
49
+ private clearIdleTimer;
50
+ private runCheckStep;
51
+ private finishStep;
52
+ }