teamshare-bridge 0.26.6 → 0.26.8

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/dist/bridge/daemon-support.d.ts +9 -0
  2. package/dist/bridge/daemon-support.js +12 -0
  3. package/dist/bridge/daemon-support.js.map +1 -1
  4. package/dist/bridge/daemon.js +37 -0
  5. package/dist/bridge/daemon.js.map +1 -1
  6. package/dist/bridge/local-server.d.ts +12 -0
  7. package/dist/bridge/local-server.js +36 -0
  8. package/dist/bridge/local-server.js.map +1 -1
  9. package/dist/cli/commands/research.js +25 -2
  10. package/dist/cli/commands/research.js.map +1 -1
  11. package/dist/lib/api.d.ts +4 -3
  12. package/dist/lib/api.js +3 -2
  13. package/dist/lib/api.js.map +1 -1
  14. package/dist/lib/browser/batch.d.ts +67 -2
  15. package/dist/lib/browser/batch.js +109 -4
  16. package/dist/lib/browser/batch.js.map +1 -1
  17. package/dist/lib/browser/download.d.ts +19 -0
  18. package/dist/lib/browser/download.js +251 -0
  19. package/dist/lib/browser/download.js.map +1 -0
  20. package/dist/lib/browser/render-image.d.ts +30 -0
  21. package/dist/lib/browser/render-image.js +285 -0
  22. package/dist/lib/browser/render-image.js.map +1 -0
  23. package/dist/lib/browser/session.d.ts +79 -1
  24. package/dist/lib/browser/session.js +174 -3
  25. package/dist/lib/browser/session.js.map +1 -1
  26. package/dist/lib/browser/stage-file.d.ts +17 -0
  27. package/dist/lib/browser/stage-file.js +23 -0
  28. package/dist/lib/browser/stage-file.js.map +1 -1
  29. package/dist/lib/browser/xlsx-template.d.ts +59 -0
  30. package/dist/lib/browser/xlsx-template.js +380 -0
  31. package/dist/lib/browser/xlsx-template.js.map +1 -0
  32. package/dist/lib/git/question-pause.d.ts +9 -0
  33. package/dist/lib/git/question-pause.js +14 -0
  34. package/dist/lib/git/question-pause.js.map +1 -1
  35. package/dist/lib/harness/opencode-control.d.ts +14 -0
  36. package/dist/lib/harness/opencode-control.js +63 -0
  37. package/dist/lib/harness/opencode-control.js.map +1 -0
  38. package/dist/lib/harness/session-store.d.ts +33 -0
  39. package/dist/lib/harness/session-store.js +38 -0
  40. package/dist/lib/harness/session-store.js.map +1 -1
  41. package/dist/lib/harness/spawn.js +56 -18
  42. package/dist/lib/harness/spawn.js.map +1 -1
  43. package/dist/lib/orchestrator/handlers/browser.js +181 -1
  44. package/dist/lib/orchestrator/handlers/browser.js.map +1 -1
  45. package/package.json +1 -1
@@ -29,3 +29,20 @@ export declare function stageFile(opts: {
29
29
  } | null>;
30
30
  /** Strip anything that could escape the staging directory. */
31
31
  export declare function sanitizeFileName(name: string): string;
32
+ /**
33
+ * Stage agent-authored text (CSV/TSV/JSON/HTML source) as a file.
34
+ * Same confinement as staged downloads: the run's directory only.
35
+ */
36
+ export declare function stageText(opts: {
37
+ runId: string;
38
+ fileName: string;
39
+ text: string;
40
+ }): Promise<{
41
+ path: string;
42
+ bytes: number;
43
+ } | null>;
44
+ /**
45
+ * Ensure the file name carries the required extension (a generated avatar
46
+ * called "logo" still needs ".png" for the site to accept it).
47
+ */
48
+ export declare function ensureExtension(fileName: string, ext: string): string;
@@ -5,6 +5,8 @@ exports.runStagingDir = runStagingDir;
5
5
  exports.safeStagedPath = safeStagedPath;
6
6
  exports.stageFile = stageFile;
7
7
  exports.sanitizeFileName = sanitizeFileName;
8
+ exports.stageText = stageText;
9
+ exports.ensureExtension = ensureExtension;
8
10
  /**
9
11
  * Staging a document's bytes on disk so a browser can ATTACH it to a form.
10
12
  *
@@ -120,4 +122,25 @@ function sanitizeFileName(name) {
120
122
  .slice(0, 120);
121
123
  return cleaned || 'file';
122
124
  }
125
+ /**
126
+ * Stage agent-authored text (CSV/TSV/JSON/HTML source) as a file.
127
+ * Same confinement as staged downloads: the run's directory only.
128
+ */
129
+ async function stageText(opts) {
130
+ if (!opts.text)
131
+ return null;
132
+ return stageFile({
133
+ runId: opts.runId,
134
+ fileName: opts.fileName,
135
+ buffer: Buffer.from(opts.text, 'utf8'),
136
+ });
137
+ }
138
+ /**
139
+ * Ensure the file name carries the required extension (a generated avatar
140
+ * called "logo" still needs ".png" for the site to accept it).
141
+ */
142
+ function ensureExtension(fileName, ext) {
143
+ const name = String(fileName ?? '').trim() || `upload.${ext}`;
144
+ return name.toLowerCase().endsWith(`.${ext}`) ? name : `${name}.${ext}`;
145
+ }
123
146
  //# sourceMappingURL=stage-file.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"stage-file.js","sourceRoot":"","sources":["../../../src/lib/browser/stage-file.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"stage-file.js","sourceRoot":"","sources":["../../../src/lib/browser/stage-file.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ export declare const QA_XLSX_MAX_ROWS = 2000;
2
+ export declare const QA_XLSX_MAX_COLS = 200;
3
+ export declare const QA_TEXT_MAX_BYTES: number;
4
+ export type StagedSheet = {
5
+ name: string;
6
+ headers: string[];
7
+ rows: Array<Record<string, unknown>>;
8
+ rowCount: number;
9
+ truncated: boolean;
10
+ };
11
+ export type ReadStagedResult = {
12
+ ok: boolean;
13
+ kind?: 'xlsx' | 'text';
14
+ sheets?: StagedSheet[];
15
+ text?: string;
16
+ truncated?: boolean;
17
+ error?: string;
18
+ [key: string]: unknown;
19
+ };
20
+ /** Split "Sheet1!B3" / "'My Sheet'!C2" / "B3" into sheet + column + row. */
21
+ export declare function parseCellAddress(addr: string): {
22
+ sheet: string | null;
23
+ col: number;
24
+ row: number;
25
+ } | null;
26
+ export declare function colToLetters(col: number): string;
27
+ /**
28
+ * Read a staged file: spreadsheets come back as sheets + header-keyed rows,
29
+ * text formats come back as text. Caps keep the MCP response small.
30
+ */
31
+ export declare function readStagedFile(opts: {
32
+ runId: string;
33
+ filePath: string;
34
+ sheet?: string;
35
+ maxRows?: number;
36
+ }): Promise<ReadStagedResult>;
37
+ export type FillExcelResult = {
38
+ ok: boolean;
39
+ path?: string;
40
+ fileName?: string;
41
+ bytes?: number;
42
+ error?: string;
43
+ [key: string]: unknown;
44
+ };
45
+ /**
46
+ * Edit a COPY of the staged template: `cells` writes exact addresses
47
+ * ("Sheet1!B3" or "B3" for the first sheet), `rows` appends header-keyed
48
+ * objects after the last used row (matched against the header row, so the
49
+ * agent must have read the template first). Styles, formulas and validation
50
+ * survive — only the addressed cells change.
51
+ */
52
+ export declare function fillStagedSpreadsheet(opts: {
53
+ runId: string;
54
+ templatePath: string;
55
+ fileName?: string;
56
+ cells?: Record<string, unknown>;
57
+ rows?: Array<Record<string, unknown>>;
58
+ sheet?: string;
59
+ }): Promise<FillExcelResult>;
@@ -0,0 +1,380 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.QA_TEXT_MAX_BYTES = exports.QA_XLSX_MAX_COLS = exports.QA_XLSX_MAX_ROWS = void 0;
7
+ exports.parseCellAddress = parseCellAddress;
8
+ exports.colToLetters = colToLetters;
9
+ exports.readStagedFile = readStagedFile;
10
+ exports.fillStagedSpreadsheet = fillStagedSpreadsheet;
11
+ /**
12
+ * Read and fill spreadsheet templates inside the run's staging directory
13
+ * (2026-10, QA files).
14
+ *
15
+ * WHY THIS EXISTS: a QA flow that must "download the template, fill it with
16
+ * test data and upload it" needs the template's STRUCTURE, not a guess at
17
+ * it. The agent reads headers first (`readStagedFile`), writes values into a
18
+ * COPY (`fillExcel` — the original download stays intact for a retry), and
19
+ * `attachFile` picks up the copy. All paths stay inside the run's staging
20
+ * directory, so the `safeStagedPath` guard keeps holding.
21
+ *
22
+ * Implementation notes:
23
+ * - `xlsx-populate` is already a bridge dependency (the workbook builder
24
+ * uses it), so no new package is needed.
25
+ * - `fillExcel` preserves everything it does not touch (styles, formulas,
26
+ * validation) because it edits the template in place rather than
27
+ * rebuilding it.
28
+ * - Text formats (.csv/.tsv/.txt/.json) read as text — the agent composes
29
+ * new content itself and stages it with `stageFile({ text })`.
30
+ */
31
+ const node_fs_1 = require("node:fs");
32
+ const xlsx_populate_1 = __importDefault(require("xlsx-populate"));
33
+ const stage_file_1 = require("./stage-file");
34
+ exports.QA_XLSX_MAX_ROWS = 2000;
35
+ exports.QA_XLSX_MAX_COLS = 200;
36
+ exports.QA_TEXT_MAX_BYTES = 200 * 1024;
37
+ const SPREADSHEET_EXTS = ['.xlsx', '.xlsm'];
38
+ function extOf(path) {
39
+ const i = path.lastIndexOf('.');
40
+ return i >= 0 ? path.slice(i).toLowerCase() : '';
41
+ }
42
+ function cellToJson(v) {
43
+ if (v instanceof Date)
44
+ return v.toISOString();
45
+ return v ?? null;
46
+ }
47
+ /** Split "Sheet1!B3" / "'My Sheet'!C2" / "B3" into sheet + column + row. */
48
+ function parseCellAddress(addr) {
49
+ const m = /^(?:'((?:[^']|'')+)'!|([^!]+)!)?([A-Za-z]+)(\d+)$/.exec(addr.trim());
50
+ if (!m)
51
+ return null;
52
+ const raw = m[1] ?? m[2] ?? null;
53
+ const sheet = raw === null ? null : raw.replace(/''/g, "'");
54
+ const letters = m[3].toUpperCase();
55
+ let col = 0;
56
+ for (const ch of letters) {
57
+ col = col * 26 + (ch.charCodeAt(0) - 64);
58
+ if (col > exports.QA_XLSX_MAX_COLS + 26)
59
+ return null;
60
+ }
61
+ const row = Number(m[4]);
62
+ if (!Number.isInteger(row) || row < 1 || row > exports.QA_XLSX_MAX_ROWS + 100) {
63
+ return null;
64
+ }
65
+ return { sheet, col, row };
66
+ }
67
+ function colToLetters(col) {
68
+ let n = col;
69
+ let s = '';
70
+ while (n > 0) {
71
+ const r = (n - 1) % 26;
72
+ s = String.fromCharCode(65 + r) + s;
73
+ n = Math.floor((n - 1) / 26);
74
+ }
75
+ return s || 'A';
76
+ }
77
+ /**
78
+ * Read a staged file: spreadsheets come back as sheets + header-keyed rows,
79
+ * text formats come back as text. Caps keep the MCP response small.
80
+ */
81
+ async function readStagedFile(opts) {
82
+ const safe = (0, stage_file_1.safeStagedPath)(opts.runId, opts.filePath);
83
+ if (!safe) {
84
+ return {
85
+ ok: false,
86
+ error: "the file is not in this run's staging directory",
87
+ };
88
+ }
89
+ const ext = extOf(safe);
90
+ if (SPREADSHEET_EXTS.includes(ext)) {
91
+ return readWorkbook(safe, opts.sheet, opts.maxRows);
92
+ }
93
+ let stat;
94
+ try {
95
+ stat = (0, node_fs_1.readFileSync)(safe).length;
96
+ }
97
+ catch {
98
+ return { ok: false, error: 'the file could not be read' };
99
+ }
100
+ if (stat > exports.QA_TEXT_MAX_BYTES) {
101
+ return {
102
+ ok: false,
103
+ error: `text file is too large (${Math.round(stat / 1024)} KB, max ${exports.QA_TEXT_MAX_BYTES / 1024} KB) — narrow the download first`,
104
+ };
105
+ }
106
+ try {
107
+ const text = (0, node_fs_1.readFileSync)(safe, 'utf8');
108
+ return { ok: true, kind: 'text', text, truncated: false };
109
+ }
110
+ catch {
111
+ return { ok: false, error: 'the file is not readable as text' };
112
+ }
113
+ }
114
+ async function readWorkbook(path, onlySheet, maxRows) {
115
+ const cap = Math.min(Math.max(typeof maxRows === 'number' ? maxRows : exports.QA_XLSX_MAX_ROWS, 1), exports.QA_XLSX_MAX_ROWS);
116
+ let buffer;
117
+ try {
118
+ buffer = (0, node_fs_1.readFileSync)(path);
119
+ }
120
+ catch {
121
+ return { ok: false, error: 'the file could not be read' };
122
+ }
123
+ let workbook;
124
+ try {
125
+ workbook = await xlsx_populate_1.default.fromDataAsync(buffer);
126
+ }
127
+ catch {
128
+ return { ok: false, error: 'the file is not a readable workbook' };
129
+ }
130
+ const sheets = [];
131
+ let names;
132
+ try {
133
+ names = workbook.sheets().map((s) => s.name());
134
+ }
135
+ catch {
136
+ return { ok: false, error: 'the workbook has no readable sheets' };
137
+ }
138
+ const wanted = onlySheet ? names.filter((n) => n === onlySheet) : names;
139
+ if (onlySheet && wanted.length === 0) {
140
+ return {
141
+ ok: false,
142
+ error: `sheet "${onlySheet}" not found (available: ${names.join(', ') || 'none'})`,
143
+ };
144
+ }
145
+ for (const name of wanted) {
146
+ const sheet = workbook.sheet(name);
147
+ let endCol = 0;
148
+ let endRow = 0;
149
+ try {
150
+ const used = sheet.usedRange();
151
+ if (used) {
152
+ endCol = used.endCell().columnNumber();
153
+ endRow = used.endCell().rowNumber();
154
+ }
155
+ }
156
+ catch {
157
+ /* empty sheet */
158
+ }
159
+ endCol = Math.min(endCol, exports.QA_XLSX_MAX_COLS);
160
+ endRow = Math.min(endRow, cap + 1);
161
+ const grid = [];
162
+ for (let r = 1; r <= endRow; r++) {
163
+ const row = [];
164
+ for (let c = 1; c <= endCol; c++) {
165
+ try {
166
+ row.push(cellToJson(sheet.cell(r, c).value()));
167
+ }
168
+ catch {
169
+ row.push(null);
170
+ }
171
+ }
172
+ grid.push(row);
173
+ }
174
+ // Trim trailing empty columns and rows: a template's used range often
175
+ // overshoots its real content, and the agent must see headers and rows,
176
+ // not phantom "Column C" entries and blank objects.
177
+ const cellEmpty = (v) => v === null ||
178
+ v === undefined ||
179
+ (typeof v === 'string' && v.trim() === '');
180
+ let lastCol = -1;
181
+ for (const row of grid) {
182
+ for (let c = row.length - 1; c > lastCol; c--) {
183
+ if (!cellEmpty(row[c])) {
184
+ lastCol = c;
185
+ break;
186
+ }
187
+ }
188
+ }
189
+ const trimmed = grid
190
+ .map((row) => row.slice(0, lastCol + 1))
191
+ .filter((row, i, all) => {
192
+ if (i === 0)
193
+ return true;
194
+ const rest = all.slice(i);
195
+ return rest.some((r) => r.some((v) => !cellEmpty(v)));
196
+ });
197
+ const headerRow = trimmed[0] ?? [];
198
+ const headers = headerRow.map((h, i) => String(h ?? '').trim() === ''
199
+ ? `Column ${colToLetters(i + 1)}`
200
+ : String(h).trim());
201
+ const rows = trimmed.slice(1).map((cells) => {
202
+ const obj = {};
203
+ headers.forEach((h, i) => {
204
+ obj[h] = cells[i] ?? null;
205
+ });
206
+ return obj;
207
+ });
208
+ sheets.push({
209
+ name,
210
+ headers,
211
+ rows,
212
+ rowCount: rows.length,
213
+ truncated: endRow >= cap + 1,
214
+ });
215
+ }
216
+ return { ok: true, kind: 'xlsx', sheets, truncated: false };
217
+ }
218
+ /**
219
+ * Edit a COPY of the staged template: `cells` writes exact addresses
220
+ * ("Sheet1!B3" or "B3" for the first sheet), `rows` appends header-keyed
221
+ * objects after the last used row (matched against the header row, so the
222
+ * agent must have read the template first). Styles, formulas and validation
223
+ * survive — only the addressed cells change.
224
+ */
225
+ async function fillStagedSpreadsheet(opts) {
226
+ const safe = (0, stage_file_1.safeStagedPath)(opts.runId, opts.templatePath);
227
+ if (!safe) {
228
+ return {
229
+ ok: false,
230
+ error: "the template is not in this run's staging directory",
231
+ };
232
+ }
233
+ if (!SPREADSHEET_EXTS.includes(extOf(safe))) {
234
+ return { ok: false, error: 'only .xlsx templates can be filled' };
235
+ }
236
+ const cells = opts.cells ?? {};
237
+ const rows = Array.isArray(opts.rows) ? opts.rows : [];
238
+ if (Object.keys(cells).length === 0 && rows.length === 0) {
239
+ return { ok: false, error: 'nothing to write — pass cells and/or rows' };
240
+ }
241
+ if (rows.length > exports.QA_XLSX_MAX_ROWS) {
242
+ return {
243
+ ok: false,
244
+ error: `too many rows (${rows.length}, max ${exports.QA_XLSX_MAX_ROWS})`,
245
+ };
246
+ }
247
+ let workbook;
248
+ try {
249
+ workbook = await xlsx_populate_1.default.fromDataAsync((0, node_fs_1.readFileSync)(safe));
250
+ }
251
+ catch {
252
+ return { ok: false, error: 'the template is not a readable workbook' };
253
+ }
254
+ const firstName = (() => {
255
+ try {
256
+ return workbook.sheets()[0]?.name();
257
+ }
258
+ catch {
259
+ return undefined;
260
+ }
261
+ })();
262
+ // Exact-address writes.
263
+ for (const [addr, value] of Object.entries(cells)) {
264
+ const parsed = parseCellAddress(addr);
265
+ if (!parsed) {
266
+ return {
267
+ ok: false,
268
+ error: `bad cell address "${addr}" — use "Sheet1!B3"`,
269
+ };
270
+ }
271
+ const sheetName = parsed.sheet ?? opts.sheet ?? firstName;
272
+ if (!sheetName) {
273
+ return { ok: false, error: 'the workbook has no sheets' };
274
+ }
275
+ let sheet;
276
+ try {
277
+ sheet = workbook.sheet(sheetName);
278
+ }
279
+ catch {
280
+ return { ok: false, error: `sheet "${sheetName}" not found` };
281
+ }
282
+ try {
283
+ sheet.cell(parsed.row, parsed.col).value(value ?? null);
284
+ }
285
+ catch {
286
+ return { ok: false, error: `could not write ${addr}` };
287
+ }
288
+ }
289
+ // Header-keyed row appends.
290
+ if (rows.length > 0) {
291
+ const sheetName = opts.sheet ?? firstName;
292
+ if (!sheetName) {
293
+ return { ok: false, error: 'the workbook has no sheets' };
294
+ }
295
+ let sheet;
296
+ try {
297
+ sheet = workbook.sheet(sheetName);
298
+ }
299
+ catch {
300
+ return { ok: false, error: `sheet "${sheetName}" not found` };
301
+ }
302
+ let lastRow = 0;
303
+ try {
304
+ const used = sheet.usedRange();
305
+ if (used)
306
+ lastRow = used.endCell().rowNumber();
307
+ }
308
+ catch {
309
+ lastRow = 0;
310
+ }
311
+ // Header map from the first row (same rule as the reader).
312
+ const headers = [];
313
+ const probeCols = Math.min(exports.QA_XLSX_MAX_COLS, 200);
314
+ for (let c = 1; c <= probeCols; c++) {
315
+ let v = null;
316
+ try {
317
+ v = sheet.cell(1, c).value();
318
+ }
319
+ catch {
320
+ break;
321
+ }
322
+ if (v === null || v === undefined || String(v).trim() === '')
323
+ break;
324
+ headers.push(String(v).trim());
325
+ }
326
+ if (headers.length === 0) {
327
+ return {
328
+ ok: false,
329
+ error: `sheet "${sheetName}" has no header row — write with cells instead`,
330
+ };
331
+ }
332
+ const unknownKeys = new Set();
333
+ rows.forEach((row, i) => {
334
+ const target = lastRow + 1 + i;
335
+ for (const [key, value] of Object.entries(row)) {
336
+ const idx = headers.indexOf(key);
337
+ if (idx === -1) {
338
+ unknownKeys.add(key);
339
+ continue;
340
+ }
341
+ try {
342
+ sheet.cell(target, idx + 1).value(value ?? null);
343
+ }
344
+ catch {
345
+ /* one bad cell must not lose the row */
346
+ }
347
+ }
348
+ });
349
+ if (unknownKeys.size > 0) {
350
+ return {
351
+ ok: false,
352
+ error: `unknown column(s): ${[...unknownKeys].join(', ')} (headers: ${headers.join(', ')})`,
353
+ };
354
+ }
355
+ }
356
+ let buffer;
357
+ try {
358
+ buffer = Buffer.from(await workbook.outputAsync());
359
+ }
360
+ catch {
361
+ return { ok: false, error: 'the filled workbook could not be rendered' };
362
+ }
363
+ const staged = await (0, stage_file_1.stageFile)({
364
+ runId: opts.runId,
365
+ fileName: opts.fileName && opts.fileName.trim()
366
+ ? opts.fileName.trim()
367
+ : 'filled-template.xlsx',
368
+ buffer,
369
+ });
370
+ if (!staged) {
371
+ return { ok: false, error: 'the filled file could not be staged' };
372
+ }
373
+ return {
374
+ ok: true,
375
+ path: staged.path,
376
+ fileName: staged.path.split(/[\\/]/).pop(),
377
+ bytes: staged.bytes,
378
+ };
379
+ }
380
+ //# sourceMappingURL=xlsx-template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xlsx-template.js","sourceRoot":"","sources":["../../../src/lib/browser/xlsx-template.ts"],"names":[],"mappings":"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"}
@@ -50,3 +50,12 @@ export declare function detectQuestionPause(api: QuestionProbeApi | null, taskId
50
50
  * summary so the board does not read as complete while a human owes an answer.
51
51
  */
52
52
  export declare function pauseSummary(questionBody?: string): string;
53
+ /**
54
+ * The ToolRun status a finished research session reports (2026-10).
55
+ *
56
+ * `ask_human` ends the turn and the process exits 0, so a clean exit is NOT
57
+ * proof the run finished: a pending question means PAUSED. This is exported so
58
+ * the mapping is testable without spawning a harness, and so the bridge never
59
+ * re-derives "paused" from a status string by hand.
60
+ */
61
+ export declare function researchRunStatus(exitCode: number, paused: boolean): 'completed' | 'failed' | 'paused';
@@ -26,6 +26,7 @@
26
26
  Object.defineProperty(exports, "__esModule", { value: true });
27
27
  exports.detectQuestionPause = detectQuestionPause;
28
28
  exports.pauseSummary = pauseSummary;
29
+ exports.researchRunStatus = researchRunStatus;
29
30
  function bodyOf(open) {
30
31
  if (!open || typeof open !== 'object')
31
32
  return undefined;
@@ -70,4 +71,17 @@ function pauseSummary(questionBody) {
70
71
  'from that branch and continue where I stopped.',
71
72
  ].join('\n');
72
73
  }
74
+ /**
75
+ * The ToolRun status a finished research session reports (2026-10).
76
+ *
77
+ * `ask_human` ends the turn and the process exits 0, so a clean exit is NOT
78
+ * proof the run finished: a pending question means PAUSED. This is exported so
79
+ * the mapping is testable without spawning a harness, and so the bridge never
80
+ * re-derives "paused" from a status string by hand.
81
+ */
82
+ function researchRunStatus(exitCode, paused) {
83
+ if (exitCode !== 0)
84
+ return 'failed';
85
+ return paused ? 'paused' : 'completed';
86
+ }
73
87
  //# sourceMappingURL=question-pause.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"question-pause.js","sourceRoot":"","sources":["../../../src/lib/git/question-pause.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;;AA4BH,kDAgBC;AAMD,oCAWC;AA7CD,SAAS,MAAM,CAAC,IAAa;IAC3B,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IACxD,MAAM,IAAI,GAAI,IAA2B,CAAC,IAAI,CAAC;IAC/C,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAC3E,CAAC;AAED;;;;;GAKG;AACI,KAAK,UAAU,mBAAmB,CACvC,GAA4B,EAC5B,MAAiC,EACjC,OAAoC,EAAE;IAEtC,IAAI,IAAI,CAAC,aAAa;QAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IACjD,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAC9C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;QAC/C,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC/B,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IACzE,CAAC;IAAC,MAAM,CAAC;QACP,4EAA4E;QAC5E,2BAA2B;QAC3B,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;IAC9C,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAgB,YAAY,CAAC,YAAqB;IAChD,OAAO;QACL,gFAAgF;QAChF,EAAE;QACF,mBAAmB;QACnB,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,2CAA2C;QACzE,EAAE;QACF,4EAA4E;QAC5E,4EAA4E;QAC5E,gDAAgD;KACjD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"question-pause.js","sourceRoot":"","sources":["../../../src/lib/git/question-pause.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;;AA4BH,kDAgBC;AAMD,oCAWC;AAUD,8CAMC;AA7DD,SAAS,MAAM,CAAC,IAAa;IAC3B,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IACxD,MAAM,IAAI,GAAI,IAA2B,CAAC,IAAI,CAAC;IAC/C,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAC3E,CAAC;AAED;;;;;GAKG;AACI,KAAK,UAAU,mBAAmB,CACvC,GAA4B,EAC5B,MAAiC,EACjC,OAAoC,EAAE;IAEtC,IAAI,IAAI,CAAC,aAAa;QAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IACjD,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAC9C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;QAC/C,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC/B,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IACzE,CAAC;IAAC,MAAM,CAAC;QACP,4EAA4E;QAC5E,2BAA2B;QAC3B,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;IAC9C,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAgB,YAAY,CAAC,YAAqB;IAChD,OAAO;QACL,gFAAgF;QAChF,EAAE;QACF,mBAAmB;QACnB,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,2CAA2C;QACzE,EAAE;QACF,4EAA4E;QAC5E,4EAA4E;QAC5E,gDAAgD;KACjD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,iBAAiB,CAC/B,QAAgB,EAChB,MAAe;IAEf,IAAI,QAAQ,KAAK,CAAC;QAAE,OAAO,QAAQ,CAAC;IACpC,OAAO,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC;AACzC,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Build the CLI argv that interrupts `sessionId`, or null for an invalid id.
3
+ * Exported as a pure function so the contract can be pinned by a unit test.
4
+ */
5
+ export declare function buildOpencodeInterruptArgs(sessionId: string): string[] | null;
6
+ /**
7
+ * Interrupt an OpenCode V2 session on the shared service.
8
+ *
9
+ * Best-effort by contract: a missing CLI, a stopped service, a timeout or an
10
+ * idle session all answer `false` and must NEVER throw - a stop path must not
11
+ * fail because the harness could not be reached. The caller logs the result;
12
+ * the relay-token revocation is the independent backstop.
13
+ */
14
+ export declare function interruptOpencodeSession(sessionId: string, timeoutMs?: number): Promise<boolean>;
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildOpencodeInterruptArgs = buildOpencodeInterruptArgs;
4
+ exports.interruptOpencodeSession = interruptOpencodeSession;
5
+ /**
6
+ * OpenCode V2 session control (2026-10).
7
+ *
8
+ * THE BUG THIS EXISTS FOR: V2 is a client/server product. `opencode run` is a
9
+ * CLIENT attached to a shared background service that owns the session, the
10
+ * model stream and all tool execution. `session.stop` used to kill the CLI's
11
+ * process tree only - the service kept executing the turn, kept calling MCP
12
+ * tools through the run's still-valid relay token, and kept driving the debug
13
+ * browser. The human saw "stopped" while the QA run went on.
14
+ *
15
+ * The service exposes `POST /api/session/{sessionID}/interrupt` (verified from
16
+ * its OpenAPI document). The CLI's `api` subcommand carries the service auth,
17
+ * so this is one short-lived process with a hard timeout - never a long-lived
18
+ * connection and never a direct HTTP call that would need the service token.
19
+ */
20
+ const node_child_process_1 = require("node:child_process");
21
+ const harness_1 = require("./harness");
22
+ /** OpenCode session ids are `ses_` + base62-ish; reject anything else. */
23
+ const OPENCODE_SESSION_ID = /^ses_[A-Za-z0-9]+$/;
24
+ /**
25
+ * Build the CLI argv that interrupts `sessionId`, or null for an invalid id.
26
+ * Exported as a pure function so the contract can be pinned by a unit test.
27
+ */
28
+ function buildOpencodeInterruptArgs(sessionId) {
29
+ if (!OPENCODE_SESSION_ID.test(sessionId))
30
+ return null;
31
+ return ['api', 'POST', `/api/session/${sessionId}/interrupt`];
32
+ }
33
+ /**
34
+ * Interrupt an OpenCode V2 session on the shared service.
35
+ *
36
+ * Best-effort by contract: a missing CLI, a stopped service, a timeout or an
37
+ * idle session all answer `false` and must NEVER throw - a stop path must not
38
+ * fail because the harness could not be reached. The caller logs the result;
39
+ * the relay-token revocation is the independent backstop.
40
+ */
41
+ function interruptOpencodeSession(sessionId, timeoutMs = 15_000) {
42
+ const args = buildOpencodeInterruptArgs(sessionId);
43
+ if (!args)
44
+ return Promise.resolve(false);
45
+ const bin = (0, harness_1.resolveBin)('opencode');
46
+ if (!bin)
47
+ return Promise.resolve(false);
48
+ return new Promise((resolve) => {
49
+ try {
50
+ (0, node_child_process_1.execFile)(bin.file, [...(bin.args ?? []), ...args], { timeout: timeoutMs, windowsHide: true, maxBuffer: 1024 * 1024 }, (err, stdout) => {
51
+ if (err) {
52
+ resolve(false);
53
+ return;
54
+ }
55
+ resolve(/"interrupted"\s*:\s*true/.test(String(stdout ?? '')));
56
+ });
57
+ }
58
+ catch {
59
+ resolve(false);
60
+ }
61
+ });
62
+ }
63
+ //# sourceMappingURL=opencode-control.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode-control.js","sourceRoot":"","sources":["../../../src/lib/harness/opencode-control.ts"],"names":[],"mappings":";;AAyBA,gEAGC;AAUD,4DA0BC;AAhED;;;;;;;;;;;;;;GAcG;AACH,2DAA8C;AAC9C,uCAAuC;AAEvC,0EAA0E;AAC1E,MAAM,mBAAmB,GAAG,oBAAoB,CAAC;AAEjD;;;GAGG;AACH,SAAgB,0BAA0B,CAAC,SAAiB;IAC1D,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,CAAC;IACtD,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,gBAAgB,SAAS,YAAY,CAAC,CAAC;AAChE,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,wBAAwB,CACtC,SAAiB,EACjB,SAAS,GAAG,MAAM;IAElB,MAAM,IAAI,GAAG,0BAA0B,CAAC,SAAS,CAAC,CAAC;IACnD,IAAI,CAAC,IAAI;QAAE,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACzC,MAAM,GAAG,GAAG,IAAA,oBAAU,EAAC,UAAU,CAAC,CAAC;IACnC,IAAI,CAAC,GAAG;QAAE,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACxC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,IAAI,CAAC;YACH,IAAA,6BAAQ,EACN,GAAG,CAAC,IAAI,EACR,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC,EAC9B,EAAE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,GAAG,IAAI,EAAE,EACjE,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE;gBACd,IAAI,GAAG,EAAE,CAAC;oBACR,OAAO,CAAC,KAAK,CAAC,CAAC;oBACf,OAAO;gBACT,CAAC;gBACD,OAAO,CAAC,0BAA0B,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YACjE,CAAC,CACF,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,KAAK,CAAC,CAAC;QACjB,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}