@ci-kit/roundtable 0.0.1 → 0.3.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.
@@ -0,0 +1,190 @@
1
+ import { access, mkdir, writeFile } from 'node:fs/promises';
2
+ import { resolve, join } from 'node:path';
3
+
4
+ const TABLE = `---
5
+ title: \u6BCF\u65E5\u4F8B\u4F1A
6
+ schedule: daily
7
+ budget:
8
+ total: 12
9
+ perSeat: 4
10
+
11
+ phases:
12
+ - id: propose
13
+ seats: [editor]
14
+ - id: discuss
15
+ seats: [writer, guard]
16
+ - id: produce
17
+ seats: [writer]
18
+ - id: review
19
+ seats: [guard]
20
+ vetoable: true
21
+ - id: converge
22
+ seats: [host]
23
+
24
+ onVeto: re-propose
25
+ maxAttempts: 3
26
+ ---
27
+
28
+ \u8FD9\u662F\u4E00\u4E2A\u793A\u4F8B\u5706\u684C\u3002\u6539\u5B8C frontmatter \u5C31\u80FD\u7528\uFF0C\u6B63\u6587\u53EF\u4EE5\u7559\u7A7A\u3002
29
+
30
+ ## propose
31
+
32
+ \u4ECE\u7ED9\u5B9A\u6750\u6599\u91CC\u63D0\u51FA\u4E00\u4E2A\u5177\u4F53\u3001\u53EF\u6267\u884C\u3001\u503C\u5F97\u73B0\u5728\u505A\u7684\u8BAE\u9898\u3002
33
+
34
+ ## converge
35
+
36
+ \u6C47\u603B\u672C\u8F6E\u7684\u7ED3\u8BBA\u3001\u9057\u7559\u5206\u6B67\u548C\u4E0B\u4E00\u6B65\u52A8\u4F5C\u3002
37
+ `;
38
+ const SEATS = [
39
+ {
40
+ name: "editor.md",
41
+ content: `---
42
+ id: editor
43
+ role: \u9009\u9898\u7F16\u8F91
44
+
45
+ identity:
46
+ name: \u6797\u5C0F\u6EE1
47
+ avatar: \u270D\uFE0F
48
+ title: \u8DD1\u4E86\u516D\u5E74\u4E00\u7EBF\u7684\u8001\u7F16\u8F91
49
+ background: \u89C1\u8FC7\u592A\u591A\u7EB8\u4E0A\u65B9\u6848\uFF0C\u4E60\u60EF\u5148\u95EE\u95E8\u5E97\u771F\u80FD\u8FD9\u4E48\u505A\u5417
50
+
51
+ persona:
52
+ stance: \u5B81\u53EF\u9009\u5C0F\uFF0C\u53EF\u9009\u5177\u4F53
53
+ personality: [\u8F83\u771F, \u5BF9\u6A21\u7CCA\u8BF4\u8F9E\u654F\u611F]
54
+ style: \u76F4\u63A5\u3001\u77ED\u53E5
55
+ speech: \u5148\u7ED9\u7ED3\u8BBA\u518D\u7ED9\u7406\u7531\uFF0C\u4E00\u6B21\u53EA\u95EE\u4E00\u4E2A\u95EE\u9898
56
+ values: \u4E00\u4E2A\u5199\u4E0D\u51FA\u52A8\u4F5C\u7684\u9009\u9898\uFF0C\u4E0D\u662F\u9009\u9898
57
+ quirks: \u63D0\u5230\u6570\u636E\u5FC5\u8FFD\u95EE\u53E3\u5F84
58
+ avoid: \u4E0D\u8BC4\u4EF7\u6587\u98CE
59
+
60
+ seat:
61
+ phase: [propose]
62
+ canPropose: true
63
+ budget: 2
64
+ ---
65
+
66
+ \u4F60\u8D1F\u8D23\u4ECE\u6750\u6599\u91CC\u6311\u51FA\u4E00\u4E2A\u503C\u5F97\u505A\u7684\u5177\u4F53\u8BAE\u9898\u3002
67
+
68
+ ## \u804C\u8D23
69
+ - \u7ED9\u51FA\u4E00\u4E2A\u8BAE\u9898\u548C\u9009\u62E9\u5B83\u7684\u7406\u7531
70
+ - \u8BF4\u660E\u4E3A\u4EC0\u4E48\u662F\u73B0\u5728
71
+ - \u4E0D\u5199\u6B63\u6587\uFF0C\u53EA\u5B9A\u65B9\u5411
72
+ `
73
+ },
74
+ {
75
+ name: "writer.md",
76
+ content: `---
77
+ id: writer
78
+ role: \u4F5C\u8005
79
+
80
+ identity:
81
+ name: \u9648\u9ED8
82
+ avatar: \u270F\uFE0F
83
+ title: \u5199\u4E1C\u897F\u7684\u4EBA
84
+
85
+ persona:
86
+ stance: \u5148\u505A\u51FA\u6765\u518D\u8BA8\u8BBA
87
+ style: \u5177\u4F53\u3001\u4E0D\u7ED5\u5F2F
88
+
89
+ seat:
90
+ phase: [discuss, produce]
91
+ budget: 4
92
+ ---
93
+
94
+ \u4F60\u8D1F\u8D23\u628A\u65B9\u5411\u843D\u6210\u5B9E\u9645\u7ED3\u679C\u3002
95
+
96
+ ## \u804C\u8D23
97
+ - \u8BA8\u8BBA\u9636\u6BB5\uFF1A\u5BF9\u8BAE\u9898\u7ED9\u51FA\u53EF\u884C\u6027\u4E0E\u98CE\u9669\u5224\u65AD
98
+ - \u4EA7\u51FA\u9636\u6BB5\uFF1A\u6309\u5DF2\u8FBE\u6210\u7684\u65B9\u5411\u5199\u51FA\u5B8C\u6574\u7ED3\u679C
99
+ `
100
+ },
101
+ {
102
+ name: "guard.md",
103
+ content: `---
104
+ id: guard
105
+ role: \u4E8B\u5B9E\u5BA1\u6838
106
+
107
+ identity:
108
+ name: \u5468\u614E
109
+ avatar: \u{1F6E1}\uFE0F
110
+ title: \u505A\u4E86\u5341\u5E74\u4E8B\u5B9E\u6838\u67E5\u7684\u8001\u5BA1\u6838
111
+
112
+ persona:
113
+ stance: \u5B81\u53EF\u9519\u6740\uFF0C\u4E0D\u53EF\u653E\u8FC7
114
+ personality: [\u8F83\u771F, \u4E0D\u7559\u60C5\u9762]
115
+ style: \u51B7\u9759\u3001\u9010\u6761
116
+
117
+ seat:
118
+ phase: [discuss, review]
119
+ sees: none
120
+ canVeto: true
121
+ weight: 2
122
+ budget: 3
123
+ output: json
124
+ ---
125
+
126
+ \u4F60\u8D1F\u8D23\u6838\u5BF9\u4EA7\u51FA\u662F\u5426\u6709\u4F9D\u636E\u3002
127
+
128
+ ## \u8F93\u51FA
129
+ \u53EA\u8FD4\u56DE JSON\uFF1A{"verdict":"pass \u6216 reject","score":0,"issues":[],"reason":"\u5426\u51B3\u7406\u7531\uFF0C\u901A\u8FC7\u65F6\u7559\u7A7A"}
130
+ `
131
+ },
132
+ {
133
+ name: "host.md",
134
+ content: `---
135
+ id: host
136
+ role: \u4E3B\u6301
137
+
138
+ identity:
139
+ name: \u4F55\u4E00
140
+ avatar: \u{1F3AF}
141
+ title: \u8D1F\u8D23\u6536\u53E3\u7684\u4EBA
142
+
143
+ persona:
144
+ stance: \u8BA9\u5171\u8BC6\u53EF\u6267\u884C
145
+
146
+ seat:
147
+ phase: [converge]
148
+ lead: true
149
+ budget: 2
150
+ ---
151
+
152
+ \u4F60\u8D1F\u8D23\u6536\u53E3\u3002
153
+
154
+ ## \u804C\u8D23
155
+ - \u7ED9\u51FA\u7ED3\u8BBA
156
+ - \u5217\u51FA\u4ECD\u672A\u89E3\u51B3\u7684\u5206\u6B67
157
+ - \u7ED9\u51FA\u4E0B\u4E00\u6B65\u52A8\u4F5C
158
+ `
159
+ }
160
+ ];
161
+ async function writeExample(dir, force = false) {
162
+ const target = resolve(dir);
163
+ const files = [
164
+ {
165
+ path: join(target, "table.md"),
166
+ content: TABLE
167
+ },
168
+ ...SEATS.map((seat) => ({
169
+ path: join(target, "seats", seat.name),
170
+ content: seat.content
171
+ }))
172
+ ];
173
+ if (!force) {
174
+ for (const file of files) {
175
+ const exists = await access(file.path).then(() => true).catch(() => false);
176
+ if (exists) {
177
+ throw new Error(`${file.path} already exists; pass --force to overwrite`);
178
+ }
179
+ }
180
+ }
181
+ const written = [];
182
+ for (const file of files) {
183
+ await mkdir(join(file.path, ".."), { recursive: true });
184
+ await writeFile(file.path, file.content, "utf8");
185
+ written.push(file.path);
186
+ }
187
+ return written;
188
+ }
189
+
190
+ export { writeExample };
package/dist/cli.mjs CHANGED
@@ -1,26 +1,84 @@
1
1
  #!/usr/bin/env node
2
2
  import process from 'node:process';
3
3
  import { cac } from 'cac';
4
+ import { loadRoundtable, defaultOutDir, runRoundtable, resumeRoundtable, RoundtableConfigError } from './index.mjs';
5
+ import 'node:fs/promises';
6
+ import 'node:path';
7
+ import 'node:crypto';
8
+ import '@ci-kit/ai';
4
9
 
5
- const version = "0.0.1";
10
+ const version = "0.3.0";
6
11
  const pkg = {
7
12
  version: version};
8
13
 
9
14
  const cli = cac("ci-kit-roundtable");
15
+ function reportError(error) {
16
+ const message = error instanceof RoundtableConfigError ? `config: ${error.message}` : error instanceof Error ? error.message : String(error);
17
+ process.stderr.write(`ci-kit-roundtable: ${message}
18
+ `);
19
+ process.exit(2);
20
+ }
10
21
  cli.command("check", "Validate table.md and seats without calling a model").option("--config <dir>", "Roundtable directory", { default: ".ci-kit/roundtable" }).action(async (options) => {
11
- const { checkRoundtable } = await import('./index.mjs');
12
- await checkRoundtable({ configDir: options.config ?? ".ci-kit/roundtable" });
22
+ try {
23
+ const loaded = await loadRoundtable({ configDir: options.config ?? ".ci-kit/roundtable" });
24
+ const phases = loaded.phases.map((phase) => `${phase.id}(${phase.seats.join(", ")})`).join(" \u2192 ");
25
+ process.stdout.write(`roundtable: ok \xB7 ${loaded.seats.length} seats \xB7 ${loaded.phases.length} phases
26
+ `);
27
+ process.stdout.write(` ${phases}
28
+ `);
29
+ process.stdout.write(` title: ${loaded.table.title}
30
+ `);
31
+ } catch (error) {
32
+ reportError(error);
33
+ }
13
34
  });
14
- cli.command("run", "Run one meeting").option("--config <dir>", "Roundtable directory", { default: ".ci-kit/roundtable" }).option("--out <dir>", "Directory for run folders", { default: "roundtable-out" }).option("--topic <text>", "Optional topic override; seats propose their own by default").action(async (options) => {
15
- const { runRoundtable } = await import('./index.mjs');
16
- const result = await runRoundtable({
17
- configDir: options.config ?? ".ci-kit/roundtable",
18
- outDir: options.out,
19
- topic: options.topic
20
- });
21
- process.stdout.write(`roundtable: ${result.status} \xB7 ${result.recordPath}
22
- `);
23
- process.exitCode = result.status === "passed" ? 0 : 1;
35
+ cli.command("run", "Run one meeting").option("--config <dir>", "Roundtable directory", { default: ".ci-kit/roundtable" }).option("--out <dir>", "Directory for run folders", {
36
+ default: defaultOutDir()
37
+ }).option("--topic <text>", "Optional topic override; seats propose their own by default").option("--context <text>", "Material for the seats, repeatable").option("--resume <dir>", "Continue an interrupted run directory").action(async (options) => {
38
+ const rawContext = options.context;
39
+ const context = rawContext === void 0 ? [] : Array.isArray(rawContext) ? rawContext : [rawContext];
40
+ try {
41
+ const common = {
42
+ configDir: String(options.config ?? ".ci-kit/roundtable"),
43
+ topic: options.topic === void 0 ? void 0 : String(options.topic),
44
+ context,
45
+ onProgress: (line) => process.stderr.write(`${line}
46
+ `)
47
+ };
48
+ const result = options.resume === void 0 ? await runRoundtable({
49
+ ...common,
50
+ outDir: options.out === void 0 ? void 0 : String(options.out)
51
+ }) : await resumeRoundtable({
52
+ ...common,
53
+ runDir: String(options.resume)
54
+ });
55
+ const total = result.budgetTotal === void 0 ? "unlimited" : String(result.budgetTotal);
56
+ const summary = `roundtable: ${result.status} \xB7 ${result.record.attempts} attempt \xB7 ${result.used}/${total} calls \xB7 ${result.runDir}`;
57
+ if (result.status === "passed") {
58
+ process.stdout.write(`${summary}
59
+ `);
60
+ } else {
61
+ process.stderr.write(`${summary}
62
+ `);
63
+ }
64
+ process.exitCode = result.status === "passed" ? 0 : 1;
65
+ } catch (error) {
66
+ reportError(error);
67
+ }
68
+ });
69
+ cli.command("init [dir]", "Write an example roundtable you can edit").option("--force", "Overwrite existing files").action(async (dir, options) => {
70
+ try {
71
+ const { writeExample } = await import('./chunks/example.mjs');
72
+ const written = await writeExample(dir ?? ".ci-kit/roundtable", options.force === true);
73
+ process.stdout.write(`roundtable: wrote ${written.length} files
74
+ `);
75
+ for (const path of written) {
76
+ process.stdout.write(` ${path}
77
+ `);
78
+ }
79
+ } catch (error) {
80
+ reportError(error);
81
+ }
24
82
  });
25
83
  cli.help();
26
84
  cli.version(pkg.version);
package/dist/index.d.mts CHANGED
@@ -1,16 +1,230 @@
1
+ import { text } from '@ci-kit/ai';
2
+
3
+ type Sees = 'all' | 'none' | 'lead-only' | string[];
4
+ type Fallback = 'skip' | 'retry' | 'abort';
5
+ type SeatOutput = 'text' | 'json' | 'markdown';
6
+ interface SeatIdentity {
7
+ name: string;
8
+ avatar?: string;
9
+ title?: string;
10
+ background?: string;
11
+ }
12
+ interface SeatPersona {
13
+ /** Decision tendency. Kept apart from expression so verdicts stay reproducible. */
14
+ stance?: string;
15
+ personality: string[];
16
+ style?: string;
17
+ speech?: string;
18
+ values?: string;
19
+ quirks?: string;
20
+ avoid?: string;
21
+ }
22
+ interface SeatPowers {
23
+ /** Phase ids this seat attends; empty means every phase. */
24
+ phase: string[];
25
+ sees: Sees;
26
+ canPropose: boolean;
27
+ canVeto: boolean;
28
+ lead: boolean;
29
+ weight: number;
30
+ priority: number;
31
+ budget?: number;
32
+ fallback: Fallback;
33
+ output: SeatOutput;
34
+ model?: string;
35
+ temperature?: number;
36
+ maxTokens?: number;
37
+ }
38
+ interface Seat {
39
+ id: string;
40
+ role: string;
41
+ enabled: boolean;
42
+ identity: SeatIdentity;
43
+ persona: SeatPersona;
44
+ seat: SeatPowers;
45
+ /** Markdown body, used verbatim as the seat's instructions. */
46
+ body: string;
47
+ /** File the seat came from, for error messages only. */
48
+ source: string;
49
+ }
50
+
51
+ type PhaseMode = 'serial' | 'parallel';
52
+ type OnVeto = 're-propose' | 'revise' | 'abort';
53
+ interface Phase {
54
+ id: string;
55
+ /** Seats named here; empty means "derive from every seat's seat.phase". */
56
+ seats: string[];
57
+ vetoable: boolean;
58
+ requires: string[];
59
+ mode: PhaseMode;
60
+ }
61
+ interface Budget {
62
+ total?: number;
63
+ perSeat?: number;
64
+ }
65
+ interface Table {
66
+ title: string;
67
+ schedule?: string;
68
+ budget: Budget;
69
+ onVeto: OnVeto;
70
+ maxAttempts: number;
71
+ threshold: number;
72
+ phases: Phase[];
73
+ /** Phase ids given the special roles, resolved during validation. */
74
+ special: {
75
+ propose: string;
76
+ converge: string;
77
+ };
78
+ }
79
+
80
+ declare class RoundtableConfigError extends Error {
81
+ constructor(message: string);
82
+ }
83
+ interface LoadedRoundtable {
84
+ table: Table;
85
+ seats: Seat[];
86
+ /** Seats after `enabled` filtering, keyed by id. */
87
+ byId: Map<string, Seat>;
88
+ /** Phases with their participant lists resolved. */
89
+ phases: Phase[];
90
+ configDir: string;
91
+ /** Content fingerprint over table, seats and the roundtable schema. */
92
+ fingerprint: string;
93
+ }
1
94
  /**
2
- * @ci-kit/roundtable
3
- *
4
- * Placeholder package. The design is settled in `ai-docs/design-docs/roundtable/`;
5
- * the implementation has not started yet, so this module exports only the
6
- * names and types that downstream code may already reference.
95
+ * Read and validate a roundtable directory without calling any model.
7
96
  *
8
- * Do not add behaviour here before the design document is followed end to end:
9
- * seat parsing, phase scheduling, programmatic adjudication and resumable runs
10
- * are one unit, and half of them is worse than none.
97
+ * Everything a meeting needs to be well defined is checked here: unknown
98
+ * fields, missing required fields, duplicate ids, phase references and the
99
+ * table/seat membership intersection. A meeting that starts is a meeting that
100
+ * can finish.
11
101
  */
12
- declare const ROUNDTABLE_SCHEMA: 1;
13
- type RoundtableStatus = 'passed' | 'rejected' | 'aborted' | 'failed';
102
+ declare function loadRoundtable(options: {
103
+ configDir: string;
104
+ schema?: number;
105
+ }): Promise<LoadedRoundtable>;
106
+ /** Convenience for the CLI: validate and report, never call a model. */
107
+ declare function checkRoundtable(options: {
108
+ configDir: string;
109
+ env?: NodeJS.ProcessEnv;
110
+ }): Promise<LoadedRoundtable>;
111
+ /** Resolved default output directory. */
112
+ declare function defaultOutDir(cwd?: string): string;
113
+
114
+ /** One seat's turn in a phase, as seen by later seats. */
115
+ interface Statement {
116
+ seat: string;
117
+ name: string;
118
+ role: string;
119
+ phase: string;
120
+ status: StatementStatus;
121
+ content: string;
122
+ structured?: unknown;
123
+ durationMs?: number;
124
+ model?: string;
125
+ usage?: {
126
+ input: number;
127
+ output: number;
128
+ };
129
+ /** One log-safe line when the seat failed. */
130
+ error?: string;
131
+ artifacts?: ArtifactRef[];
132
+ }
133
+ type StatementStatus = 'completed' | 'skipped' | 'failed' | 'budget-exhausted' | 'invalid-veto';
134
+ interface ArtifactRef {
135
+ path: string;
136
+ bytes: number;
137
+ }
138
+
139
+ interface Vote {
140
+ seatId: string;
141
+ weight: number;
142
+ /** `undefined` when the seat failed or was skipped, so it cannot count. */
143
+ vote?: 'pass' | 'reject';
144
+ /** Set when a veto-capable seat wrote `reject` with a reason. */
145
+ veto?: boolean;
146
+ /** Whether the seat actually wrote text for its reason. */
147
+ hasReason?: boolean;
148
+ }
149
+ interface Judgement {
150
+ passed: boolean;
151
+ /** Seats whose valid veto blocked the phase. */
152
+ vetoed: string[];
153
+ /** Seats that voted reject without a valid veto. */
154
+ rejected: string[];
155
+ /** Weighted pass ratio over seats that actually voted. */
156
+ score: number;
157
+ /** Seats whose veto had no reason and was therefore ignored. */
158
+ invalidVetoes: string[];
159
+ }
160
+
161
+ type RoundtableStatus = 'running' | 'passed' | 'rejected' | 'aborted' | 'failed';
162
+ type PhaseStatus = 'completed' | 'skipped' | 'failed' | 'budget-exhausted';
163
+ interface PhaseRecord {
164
+ id: string;
165
+ status: PhaseStatus;
166
+ statements: Statement[];
167
+ judgement?: Judgement;
168
+ /** True when a completed phase had no input from its dependencies. */
169
+ pruned?: boolean;
170
+ }
171
+ interface RoundRecord {
172
+ attempt: number;
173
+ phases: PhaseRecord[];
174
+ }
175
+ interface BudgetState {
176
+ total?: number;
177
+ used: number;
178
+ perSeat: Record<string, number>;
179
+ perSeatLimit: Record<string, number | undefined>;
180
+ }
181
+ /** The AI call the engine depends on; injectable so meetings can be tested offline. */
182
+ type TextCaller = typeof text;
183
+
184
+ declare const RECORD_SCHEMA = 1;
185
+ interface RoundtableRecord {
186
+ schema: number;
187
+ title: string;
188
+ startedAt: string;
189
+ finishedAt?: string;
190
+ status: RoundtableStatus;
191
+ attempts: number;
192
+ verdict: {
193
+ passed: boolean;
194
+ vetoed: string[];
195
+ rejected: string[];
196
+ score: number;
197
+ invalidVetoes: string[];
198
+ };
199
+ rounds: RoundRecord[];
200
+ budget: {
201
+ total?: number;
202
+ used: number;
203
+ perSeat: Record<string, number>;
204
+ };
205
+ /** Files produced under artifacts/, referenced by statements. */
206
+ artifacts?: string[];
207
+ error?: string;
208
+ }
209
+ interface RunState {
210
+ schema: number;
211
+ runId: string;
212
+ /** `running` until the loop settles on a terminal status. */
213
+ status: RoundtableStatus | 'running';
214
+ attempt: number;
215
+ phaseIndex: number;
216
+ phaseId?: string;
217
+ budget: BudgetState;
218
+ fingerprint: string;
219
+ resumable: boolean;
220
+ rounds: RoundRecord[];
221
+ startedAt: string;
222
+ finishedAt?: string;
223
+ topic?: string;
224
+ context: string[];
225
+ error?: string;
226
+ }
227
+
14
228
  interface RoundtableOptions {
15
229
  /** Directory holding `table.md` and `seats/` */
16
230
  configDir: string;
@@ -21,17 +235,45 @@ interface RoundtableOptions {
21
235
  /** Where run directories are written */
22
236
  outDir?: string;
23
237
  env?: NodeJS.ProcessEnv;
238
+ /** Emit one line per statement while the meeting runs. */
239
+ onProgress?: (line: string) => void;
240
+ /** Defaults to `@ci-kit/ai`'s text(); tests pass a stub. */
241
+ callText?: TextCaller;
24
242
  }
25
243
  interface RoundtableResult {
26
244
  status: RoundtableStatus;
27
245
  recordPath: string;
246
+ /** Directory holding record.json, record.md, state.json. */
247
+ runDir: string;
248
+ record: RoundtableRecord;
249
+ /** Total AI calls consumed. */
250
+ used: number;
251
+ budgetTotal?: number;
252
+ }
253
+ /**
254
+ * Run one meeting.
255
+ *
256
+ * Business failure is reported through `status`, never thrown: a rejected
257
+ * meeting is a normal result. Only configuration and usage errors throw,
258
+ * because those mean nothing could start.
259
+ */
260
+ declare function runRoundtable(options: RoundtableOptions): Promise<RoundtableResult>;
261
+ interface ResumeOptions extends Omit<RoundtableOptions, 'outDir'> {
262
+ /** Run directory produced by a previous, interrupted execution. */
263
+ runDir: string;
28
264
  }
29
- /** Validate `table.md` and `seats/*.md` without calling a model. */
30
- declare function loadRoundtable(_options: RoundtableOptions): Promise<never>;
31
- /** Alias kept for the CLI `check` command: no paid calls, config errors only. */
32
- declare function checkRoundtable(_options: RoundtableOptions): Promise<never>;
33
- /** Run one meeting and return its verdict. Business failure is reported via `status`. */
34
- declare function runRoundtable(_options: RoundtableOptions): Promise<RoundtableResult>;
265
+ /**
266
+ * Continue an interrupted run from the phase that did not finish.
267
+ *
268
+ * Rules are fingerprinted: if a seat or the table changed, the previous
269
+ * progress described a different meeting and cannot be resumed. That mirrors
270
+ * "editing a prompt never rewrites an already-published draft".
271
+ *
272
+ * A run that already reached a terminal status is returned as-is rather than
273
+ * re-executed: repeating a finished meeting would spend money to reach the same
274
+ * answer.
275
+ */
276
+ declare function resumeRoundtable(options: ResumeOptions): Promise<RoundtableResult>;
35
277
 
36
- export { ROUNDTABLE_SCHEMA, checkRoundtable, loadRoundtable, runRoundtable };
37
- export type { RoundtableOptions, RoundtableResult, RoundtableStatus };
278
+ export { RECORD_SCHEMA as ROUNDTABLE_SCHEMA, RoundtableConfigError, checkRoundtable, defaultOutDir, loadRoundtable, resumeRoundtable, runRoundtable };
279
+ export type { ArtifactRef, BudgetState, Judgement, LoadedRoundtable, Phase, PhaseMode, PhaseRecord, ResumeOptions, RoundRecord, RoundtableOptions, RoundtableRecord, RoundtableResult, RoundtableStatus, RunState, Seat, SeatIdentity, SeatOutput, SeatPersona, SeatPowers, Statement, StatementStatus, Table, TextCaller, Vote };