@nuucognition/flint-cli 0.5.0-alpha.1 → 0.5.2

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.
package/dist/index.js CHANGED
@@ -34,6 +34,7 @@ import {
34
34
  getGitStatus,
35
35
  getIdentity,
36
36
  getInstalledShardsWithVersions,
37
+ getMigrationsForVersion,
37
38
  getPendingQuestion,
38
39
  getPlate,
39
40
  getPreset,
@@ -46,6 +47,7 @@ import {
46
47
  getStatus,
47
48
  getTinderboxStatus,
48
49
  getUnfulfilledCodebases,
50
+ getVersionSteps,
49
51
  hasConflictMarkers,
50
52
  hasUncommittedChanges,
51
53
  hasUnpushedCommits,
@@ -60,6 +62,7 @@ import {
60
62
  isOwnerRepo,
61
63
  isRebaseInProgress,
62
64
  isValidStatus,
65
+ isVersionStepSealed,
63
66
  listPlateTools,
64
67
  listPlates,
65
68
  listPresets,
@@ -89,6 +92,7 @@ import {
89
92
  runMigrations,
90
93
  runPlateTool,
91
94
  runShardScript,
95
+ runSingleMigration,
92
96
  scaffoldNewShard,
93
97
  scanTinderboxFlints,
94
98
  setCurrentRunResult,
@@ -107,7 +111,7 @@ import {
107
111
  updateSession,
108
112
  updateShards,
109
113
  updateSourceRepository
110
- } from "./chunk-67JRCBRR.js";
114
+ } from "./chunk-XWUP7WHQ.js";
111
115
  import {
112
116
  cleanRegistryFile,
113
117
  findFlintByName,
@@ -118,7 +122,7 @@ import {
118
122
  registerFlintByPath,
119
123
  unregisterFlint,
120
124
  upsertFlintEntry
121
- } from "./chunk-O7OVKLLV.js";
125
+ } from "./chunk-C66KJDI7.js";
122
126
  import "./chunk-V7YA5RXL.js";
123
127
  import {
124
128
  generateSourceMeshExportMetadata,
@@ -126,14 +130,14 @@ import {
126
130
  removeSourceMeshExportMetadata,
127
131
  removeSourceRepoMetadata,
128
132
  resolveSource
129
- } from "./chunk-PONDZIXS.js";
133
+ } from "./chunk-M3NSYVYR.js";
130
134
  import {
131
135
  buildExport,
132
136
  buildExportByName,
133
137
  cleanupStaleExports,
134
138
  scanExportEligible,
135
139
  scanExports
136
- } from "./chunk-ZP5A4PAH.js";
140
+ } from "./chunk-VAJMJ47E.js";
137
141
  import {
138
142
  addExportToConfig,
139
143
  addLatticeDeclaration,
@@ -155,7 +159,6 @@ import {
155
159
  hasFlintJson,
156
160
  hasFlintToml,
157
161
  isLocalShard,
158
- parse,
159
162
  readFlintToml,
160
163
  readLatticesState,
161
164
  removeExportFromConfig,
@@ -165,26 +168,853 @@ import {
165
168
  removeSourceRepository,
166
169
  removeWorkspaceRepository,
167
170
  resolveShardMode,
168
- stringify,
169
171
  toKebabCase,
170
172
  writeFlintJson,
171
173
  writeFlintToml
172
- } from "./chunk-XCVQLFHY.js";
174
+ } from "./chunk-CBGQBE6C.js";
173
175
 
174
176
  // src/index.ts
175
177
  import { Command as Command37 } from "commander";
176
- import { readFileSync as readFileSync5, existsSync as existsSync10, cpSync, mkdirSync as mkdirSync4, readdirSync as readdirSync4 } from "fs";
178
+ import { readFileSync as readFileSync10, existsSync as existsSync13, cpSync, mkdirSync as mkdirSync5, readdirSync as readdirSync7 } from "fs";
177
179
  import { fileURLToPath as fileURLToPath3 } from "url";
178
180
  import { dirname as dirname4, join as join18 } from "path";
179
- import { homedir as homedir9 } from "os";
181
+ import { homedir as homedir10 } from "os";
180
182
  import pc42 from "picocolors";
181
183
 
182
- // ../../node_modules/.pnpm/@nuucognition+cli-core@0.0.1-beta.5/node_modules/@nuucognition/cli-core/dist/index.js
184
+ // ../../../main/packages/cli-core/dist/index.js
183
185
  import { homedir } from "os";
184
186
  import { join } from "path";
185
187
  import { mkdir, readFile as fsReadFile, writeFile as fsWriteFile } from "fs/promises";
186
188
  import { readFileSync as fsReadFileSync } from "fs";
187
189
  import { dirname } from "path";
190
+
191
+ // ../../../main/node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/error.js
192
+ function getLineColFromPtr(string, ptr) {
193
+ let lines = string.slice(0, ptr).split(/\r\n|\n|\r/g);
194
+ return [lines.length, lines.pop().length + 1];
195
+ }
196
+ function makeCodeBlock(string, line, column) {
197
+ let lines = string.split(/\r\n|\n|\r/g);
198
+ let codeblock = "";
199
+ let numberLen = (Math.log10(line + 1) | 0) + 1;
200
+ for (let i = line - 1; i <= line + 1; i++) {
201
+ let l = lines[i - 1];
202
+ if (!l)
203
+ continue;
204
+ codeblock += i.toString().padEnd(numberLen, " ");
205
+ codeblock += ": ";
206
+ codeblock += l;
207
+ codeblock += "\n";
208
+ if (i === line) {
209
+ codeblock += " ".repeat(numberLen + column + 2);
210
+ codeblock += "^\n";
211
+ }
212
+ }
213
+ return codeblock;
214
+ }
215
+ var TomlError = class extends Error {
216
+ line;
217
+ column;
218
+ codeblock;
219
+ constructor(message, options) {
220
+ const [line, column] = getLineColFromPtr(options.toml, options.ptr);
221
+ const codeblock = makeCodeBlock(options.toml, line, column);
222
+ super(`Invalid TOML document: ${message}
223
+
224
+ ${codeblock}`, options);
225
+ this.line = line;
226
+ this.column = column;
227
+ this.codeblock = codeblock;
228
+ }
229
+ };
230
+
231
+ // ../../../main/node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/util.js
232
+ function isEscaped(str, ptr) {
233
+ let i = 0;
234
+ while (str[ptr - ++i] === "\\")
235
+ ;
236
+ return --i && i % 2;
237
+ }
238
+ function indexOfNewline(str, start = 0, end = str.length) {
239
+ let idx = str.indexOf("\n", start);
240
+ if (str[idx - 1] === "\r")
241
+ idx--;
242
+ return idx <= end ? idx : -1;
243
+ }
244
+ function skipComment(str, ptr) {
245
+ for (let i = ptr; i < str.length; i++) {
246
+ let c = str[i];
247
+ if (c === "\n")
248
+ return i;
249
+ if (c === "\r" && str[i + 1] === "\n")
250
+ return i + 1;
251
+ if (c < " " && c !== " " || c === "\x7F") {
252
+ throw new TomlError("control characters are not allowed in comments", {
253
+ toml: str,
254
+ ptr
255
+ });
256
+ }
257
+ }
258
+ return str.length;
259
+ }
260
+ function skipVoid(str, ptr, banNewLines, banComments) {
261
+ let c;
262
+ while ((c = str[ptr]) === " " || c === " " || !banNewLines && (c === "\n" || c === "\r" && str[ptr + 1] === "\n"))
263
+ ptr++;
264
+ return banComments || c !== "#" ? ptr : skipVoid(str, skipComment(str, ptr), banNewLines);
265
+ }
266
+ function skipUntil(str, ptr, sep, end, banNewLines = false) {
267
+ if (!end) {
268
+ ptr = indexOfNewline(str, ptr);
269
+ return ptr < 0 ? str.length : ptr;
270
+ }
271
+ for (let i = ptr; i < str.length; i++) {
272
+ let c = str[i];
273
+ if (c === "#") {
274
+ i = indexOfNewline(str, i);
275
+ } else if (c === sep) {
276
+ return i + 1;
277
+ } else if (c === end || banNewLines && (c === "\n" || c === "\r" && str[i + 1] === "\n")) {
278
+ return i;
279
+ }
280
+ }
281
+ throw new TomlError("cannot find end of structure", {
282
+ toml: str,
283
+ ptr
284
+ });
285
+ }
286
+ function getStringEnd(str, seek) {
287
+ let first = str[seek];
288
+ let target = first === str[seek + 1] && str[seek + 1] === str[seek + 2] ? str.slice(seek, seek + 3) : first;
289
+ seek += target.length - 1;
290
+ do
291
+ seek = str.indexOf(target, ++seek);
292
+ while (seek > -1 && first !== "'" && isEscaped(str, seek));
293
+ if (seek > -1) {
294
+ seek += target.length;
295
+ if (target.length > 1) {
296
+ if (str[seek] === first)
297
+ seek++;
298
+ if (str[seek] === first)
299
+ seek++;
300
+ }
301
+ }
302
+ return seek;
303
+ }
304
+
305
+ // ../../../main/node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/date.js
306
+ var DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}(?::\d{2}(?:\.\d+)?)?)?(Z|[-+]\d{2}:\d{2})?$/i;
307
+ var TomlDate = class _TomlDate extends Date {
308
+ #hasDate = false;
309
+ #hasTime = false;
310
+ #offset = null;
311
+ constructor(date) {
312
+ let hasDate = true;
313
+ let hasTime = true;
314
+ let offset = "Z";
315
+ if (typeof date === "string") {
316
+ let match = date.match(DATE_TIME_RE);
317
+ if (match) {
318
+ if (!match[1]) {
319
+ hasDate = false;
320
+ date = `0000-01-01T${date}`;
321
+ }
322
+ hasTime = !!match[2];
323
+ hasTime && date[10] === " " && (date = date.replace(" ", "T"));
324
+ if (match[2] && +match[2] > 23) {
325
+ date = "";
326
+ } else {
327
+ offset = match[3] || null;
328
+ date = date.toUpperCase();
329
+ if (!offset && hasTime)
330
+ date += "Z";
331
+ }
332
+ } else {
333
+ date = "";
334
+ }
335
+ }
336
+ super(date);
337
+ if (!isNaN(this.getTime())) {
338
+ this.#hasDate = hasDate;
339
+ this.#hasTime = hasTime;
340
+ this.#offset = offset;
341
+ }
342
+ }
343
+ isDateTime() {
344
+ return this.#hasDate && this.#hasTime;
345
+ }
346
+ isLocal() {
347
+ return !this.#hasDate || !this.#hasTime || !this.#offset;
348
+ }
349
+ isDate() {
350
+ return this.#hasDate && !this.#hasTime;
351
+ }
352
+ isTime() {
353
+ return this.#hasTime && !this.#hasDate;
354
+ }
355
+ isValid() {
356
+ return this.#hasDate || this.#hasTime;
357
+ }
358
+ toISOString() {
359
+ let iso = super.toISOString();
360
+ if (this.isDate())
361
+ return iso.slice(0, 10);
362
+ if (this.isTime())
363
+ return iso.slice(11, 23);
364
+ if (this.#offset === null)
365
+ return iso.slice(0, -1);
366
+ if (this.#offset === "Z")
367
+ return iso;
368
+ let offset = +this.#offset.slice(1, 3) * 60 + +this.#offset.slice(4, 6);
369
+ offset = this.#offset[0] === "-" ? offset : -offset;
370
+ let offsetDate = new Date(this.getTime() - offset * 6e4);
371
+ return offsetDate.toISOString().slice(0, -1) + this.#offset;
372
+ }
373
+ static wrapAsOffsetDateTime(jsDate, offset = "Z") {
374
+ let date = new _TomlDate(jsDate);
375
+ date.#offset = offset;
376
+ return date;
377
+ }
378
+ static wrapAsLocalDateTime(jsDate) {
379
+ let date = new _TomlDate(jsDate);
380
+ date.#offset = null;
381
+ return date;
382
+ }
383
+ static wrapAsLocalDate(jsDate) {
384
+ let date = new _TomlDate(jsDate);
385
+ date.#hasTime = false;
386
+ date.#offset = null;
387
+ return date;
388
+ }
389
+ static wrapAsLocalTime(jsDate) {
390
+ let date = new _TomlDate(jsDate);
391
+ date.#hasDate = false;
392
+ date.#offset = null;
393
+ return date;
394
+ }
395
+ };
396
+
397
+ // ../../../main/node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/primitive.js
398
+ var INT_REGEX = /^((0x[0-9a-fA-F](_?[0-9a-fA-F])*)|(([+-]|0[ob])?\d(_?\d)*))$/;
399
+ var FLOAT_REGEX = /^[+-]?\d(_?\d)*(\.\d(_?\d)*)?([eE][+-]?\d(_?\d)*)?$/;
400
+ var LEADING_ZERO = /^[+-]?0[0-9_]/;
401
+ var ESCAPE_REGEX = /^[0-9a-f]{2,8}$/i;
402
+ var ESC_MAP = {
403
+ b: "\b",
404
+ t: " ",
405
+ n: "\n",
406
+ f: "\f",
407
+ r: "\r",
408
+ e: "\x1B",
409
+ '"': '"',
410
+ "\\": "\\"
411
+ };
412
+ function parseString(str, ptr = 0, endPtr = str.length) {
413
+ let isLiteral = str[ptr] === "'";
414
+ let isMultiline = str[ptr++] === str[ptr] && str[ptr] === str[ptr + 1];
415
+ if (isMultiline) {
416
+ endPtr -= 2;
417
+ if (str[ptr += 2] === "\r")
418
+ ptr++;
419
+ if (str[ptr] === "\n")
420
+ ptr++;
421
+ }
422
+ let tmp = 0;
423
+ let isEscape;
424
+ let parsed = "";
425
+ let sliceStart = ptr;
426
+ while (ptr < endPtr - 1) {
427
+ let c = str[ptr++];
428
+ if (c === "\n" || c === "\r" && str[ptr] === "\n") {
429
+ if (!isMultiline) {
430
+ throw new TomlError("newlines are not allowed in strings", {
431
+ toml: str,
432
+ ptr: ptr - 1
433
+ });
434
+ }
435
+ } else if (c < " " && c !== " " || c === "\x7F") {
436
+ throw new TomlError("control characters are not allowed in strings", {
437
+ toml: str,
438
+ ptr: ptr - 1
439
+ });
440
+ }
441
+ if (isEscape) {
442
+ isEscape = false;
443
+ if (c === "x" || c === "u" || c === "U") {
444
+ let code = str.slice(ptr, ptr += c === "x" ? 2 : c === "u" ? 4 : 8);
445
+ if (!ESCAPE_REGEX.test(code)) {
446
+ throw new TomlError("invalid unicode escape", {
447
+ toml: str,
448
+ ptr: tmp
449
+ });
450
+ }
451
+ try {
452
+ parsed += String.fromCodePoint(parseInt(code, 16));
453
+ } catch {
454
+ throw new TomlError("invalid unicode escape", {
455
+ toml: str,
456
+ ptr: tmp
457
+ });
458
+ }
459
+ } else if (isMultiline && (c === "\n" || c === " " || c === " " || c === "\r")) {
460
+ ptr = skipVoid(str, ptr - 1, true);
461
+ if (str[ptr] !== "\n" && str[ptr] !== "\r") {
462
+ throw new TomlError("invalid escape: only line-ending whitespace may be escaped", {
463
+ toml: str,
464
+ ptr: tmp
465
+ });
466
+ }
467
+ ptr = skipVoid(str, ptr);
468
+ } else if (c in ESC_MAP) {
469
+ parsed += ESC_MAP[c];
470
+ } else {
471
+ throw new TomlError("unrecognized escape sequence", {
472
+ toml: str,
473
+ ptr: tmp
474
+ });
475
+ }
476
+ sliceStart = ptr;
477
+ } else if (!isLiteral && c === "\\") {
478
+ tmp = ptr - 1;
479
+ isEscape = true;
480
+ parsed += str.slice(sliceStart, tmp);
481
+ }
482
+ }
483
+ return parsed + str.slice(sliceStart, endPtr - 1);
484
+ }
485
+ function parseValue(value, toml, ptr, integersAsBigInt) {
486
+ if (value === "true")
487
+ return true;
488
+ if (value === "false")
489
+ return false;
490
+ if (value === "-inf")
491
+ return -Infinity;
492
+ if (value === "inf" || value === "+inf")
493
+ return Infinity;
494
+ if (value === "nan" || value === "+nan" || value === "-nan")
495
+ return NaN;
496
+ if (value === "-0")
497
+ return integersAsBigInt ? 0n : 0;
498
+ let isInt = INT_REGEX.test(value);
499
+ if (isInt || FLOAT_REGEX.test(value)) {
500
+ if (LEADING_ZERO.test(value)) {
501
+ throw new TomlError("leading zeroes are not allowed", {
502
+ toml,
503
+ ptr
504
+ });
505
+ }
506
+ value = value.replace(/_/g, "");
507
+ let numeric = +value;
508
+ if (isNaN(numeric)) {
509
+ throw new TomlError("invalid number", {
510
+ toml,
511
+ ptr
512
+ });
513
+ }
514
+ if (isInt) {
515
+ if ((isInt = !Number.isSafeInteger(numeric)) && !integersAsBigInt) {
516
+ throw new TomlError("integer value cannot be represented losslessly", {
517
+ toml,
518
+ ptr
519
+ });
520
+ }
521
+ if (isInt || integersAsBigInt === true)
522
+ numeric = BigInt(value);
523
+ }
524
+ return numeric;
525
+ }
526
+ const date = new TomlDate(value);
527
+ if (!date.isValid()) {
528
+ throw new TomlError("invalid value", {
529
+ toml,
530
+ ptr
531
+ });
532
+ }
533
+ return date;
534
+ }
535
+
536
+ // ../../../main/node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/extract.js
537
+ function sliceAndTrimEndOf(str, startPtr, endPtr) {
538
+ let value = str.slice(startPtr, endPtr);
539
+ let commentIdx = value.indexOf("#");
540
+ if (commentIdx > -1) {
541
+ skipComment(str, commentIdx);
542
+ value = value.slice(0, commentIdx);
543
+ }
544
+ return [value.trimEnd(), commentIdx];
545
+ }
546
+ function extractValue(str, ptr, end, depth, integersAsBigInt) {
547
+ if (depth === 0) {
548
+ throw new TomlError("document contains excessively nested structures. aborting.", {
549
+ toml: str,
550
+ ptr
551
+ });
552
+ }
553
+ let c = str[ptr];
554
+ if (c === "[" || c === "{") {
555
+ let [value, endPtr2] = c === "[" ? parseArray(str, ptr, depth, integersAsBigInt) : parseInlineTable(str, ptr, depth, integersAsBigInt);
556
+ if (end) {
557
+ endPtr2 = skipVoid(str, endPtr2);
558
+ if (str[endPtr2] === ",")
559
+ endPtr2++;
560
+ else if (str[endPtr2] !== end) {
561
+ throw new TomlError("expected comma or end of structure", {
562
+ toml: str,
563
+ ptr: endPtr2
564
+ });
565
+ }
566
+ }
567
+ return [value, endPtr2];
568
+ }
569
+ let endPtr;
570
+ if (c === '"' || c === "'") {
571
+ endPtr = getStringEnd(str, ptr);
572
+ let parsed = parseString(str, ptr, endPtr);
573
+ if (end) {
574
+ endPtr = skipVoid(str, endPtr);
575
+ if (str[endPtr] && str[endPtr] !== "," && str[endPtr] !== end && str[endPtr] !== "\n" && str[endPtr] !== "\r") {
576
+ throw new TomlError("unexpected character encountered", {
577
+ toml: str,
578
+ ptr: endPtr
579
+ });
580
+ }
581
+ endPtr += +(str[endPtr] === ",");
582
+ }
583
+ return [parsed, endPtr];
584
+ }
585
+ endPtr = skipUntil(str, ptr, ",", end);
586
+ let slice = sliceAndTrimEndOf(str, ptr, endPtr - +(str[endPtr - 1] === ","));
587
+ if (!slice[0]) {
588
+ throw new TomlError("incomplete key-value declaration: no value specified", {
589
+ toml: str,
590
+ ptr
591
+ });
592
+ }
593
+ if (end && slice[1] > -1) {
594
+ endPtr = skipVoid(str, ptr + slice[1]);
595
+ endPtr += +(str[endPtr] === ",");
596
+ }
597
+ return [
598
+ parseValue(slice[0], str, ptr, integersAsBigInt),
599
+ endPtr
600
+ ];
601
+ }
602
+
603
+ // ../../../main/node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/struct.js
604
+ var KEY_PART_RE = /^[a-zA-Z0-9-_]+[ \t]*$/;
605
+ function parseKey(str, ptr, end = "=") {
606
+ let dot = ptr - 1;
607
+ let parsed = [];
608
+ let endPtr = str.indexOf(end, ptr);
609
+ if (endPtr < 0) {
610
+ throw new TomlError("incomplete key-value: cannot find end of key", {
611
+ toml: str,
612
+ ptr
613
+ });
614
+ }
615
+ do {
616
+ let c = str[ptr = ++dot];
617
+ if (c !== " " && c !== " ") {
618
+ if (c === '"' || c === "'") {
619
+ if (c === str[ptr + 1] && c === str[ptr + 2]) {
620
+ throw new TomlError("multiline strings are not allowed in keys", {
621
+ toml: str,
622
+ ptr
623
+ });
624
+ }
625
+ let eos = getStringEnd(str, ptr);
626
+ if (eos < 0) {
627
+ throw new TomlError("unfinished string encountered", {
628
+ toml: str,
629
+ ptr
630
+ });
631
+ }
632
+ dot = str.indexOf(".", eos);
633
+ let strEnd = str.slice(eos, dot < 0 || dot > endPtr ? endPtr : dot);
634
+ let newLine = indexOfNewline(strEnd);
635
+ if (newLine > -1) {
636
+ throw new TomlError("newlines are not allowed in keys", {
637
+ toml: str,
638
+ ptr: ptr + dot + newLine
639
+ });
640
+ }
641
+ if (strEnd.trimStart()) {
642
+ throw new TomlError("found extra tokens after the string part", {
643
+ toml: str,
644
+ ptr: eos
645
+ });
646
+ }
647
+ if (endPtr < eos) {
648
+ endPtr = str.indexOf(end, eos);
649
+ if (endPtr < 0) {
650
+ throw new TomlError("incomplete key-value: cannot find end of key", {
651
+ toml: str,
652
+ ptr
653
+ });
654
+ }
655
+ }
656
+ parsed.push(parseString(str, ptr, eos));
657
+ } else {
658
+ dot = str.indexOf(".", ptr);
659
+ let part = str.slice(ptr, dot < 0 || dot > endPtr ? endPtr : dot);
660
+ if (!KEY_PART_RE.test(part)) {
661
+ throw new TomlError("only letter, numbers, dashes and underscores are allowed in keys", {
662
+ toml: str,
663
+ ptr
664
+ });
665
+ }
666
+ parsed.push(part.trimEnd());
667
+ }
668
+ }
669
+ } while (dot + 1 && dot < endPtr);
670
+ return [parsed, skipVoid(str, endPtr + 1, true, true)];
671
+ }
672
+ function parseInlineTable(str, ptr, depth, integersAsBigInt) {
673
+ let res = {};
674
+ let seen = /* @__PURE__ */ new Set();
675
+ let c;
676
+ ptr++;
677
+ while ((c = str[ptr++]) !== "}" && c) {
678
+ if (c === ",") {
679
+ throw new TomlError("expected value, found comma", {
680
+ toml: str,
681
+ ptr: ptr - 1
682
+ });
683
+ } else if (c === "#")
684
+ ptr = skipComment(str, ptr);
685
+ else if (c !== " " && c !== " " && c !== "\n" && c !== "\r") {
686
+ let k;
687
+ let t = res;
688
+ let hasOwn = false;
689
+ let [key, keyEndPtr] = parseKey(str, ptr - 1);
690
+ for (let i = 0; i < key.length; i++) {
691
+ if (i)
692
+ t = hasOwn ? t[k] : t[k] = {};
693
+ k = key[i];
694
+ if ((hasOwn = Object.hasOwn(t, k)) && (typeof t[k] !== "object" || seen.has(t[k]))) {
695
+ throw new TomlError("trying to redefine an already defined value", {
696
+ toml: str,
697
+ ptr
698
+ });
699
+ }
700
+ if (!hasOwn && k === "__proto__") {
701
+ Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true });
702
+ }
703
+ }
704
+ if (hasOwn) {
705
+ throw new TomlError("trying to redefine an already defined value", {
706
+ toml: str,
707
+ ptr
708
+ });
709
+ }
710
+ let [value, valueEndPtr] = extractValue(str, keyEndPtr, "}", depth - 1, integersAsBigInt);
711
+ seen.add(value);
712
+ t[k] = value;
713
+ ptr = valueEndPtr;
714
+ }
715
+ }
716
+ if (!c) {
717
+ throw new TomlError("unfinished table encountered", {
718
+ toml: str,
719
+ ptr
720
+ });
721
+ }
722
+ return [res, ptr];
723
+ }
724
+ function parseArray(str, ptr, depth, integersAsBigInt) {
725
+ let res = [];
726
+ let c;
727
+ ptr++;
728
+ while ((c = str[ptr++]) !== "]" && c) {
729
+ if (c === ",") {
730
+ throw new TomlError("expected value, found comma", {
731
+ toml: str,
732
+ ptr: ptr - 1
733
+ });
734
+ } else if (c === "#")
735
+ ptr = skipComment(str, ptr);
736
+ else if (c !== " " && c !== " " && c !== "\n" && c !== "\r") {
737
+ let e = extractValue(str, ptr - 1, "]", depth - 1, integersAsBigInt);
738
+ res.push(e[0]);
739
+ ptr = e[1];
740
+ }
741
+ }
742
+ if (!c) {
743
+ throw new TomlError("unfinished array encountered", {
744
+ toml: str,
745
+ ptr
746
+ });
747
+ }
748
+ return [res, ptr];
749
+ }
750
+
751
+ // ../../../main/node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/parse.js
752
+ function peekTable(key, table, meta, type) {
753
+ let t = table;
754
+ let m = meta;
755
+ let k;
756
+ let hasOwn = false;
757
+ let state;
758
+ for (let i = 0; i < key.length; i++) {
759
+ if (i) {
760
+ t = hasOwn ? t[k] : t[k] = {};
761
+ m = (state = m[k]).c;
762
+ if (type === 0 && (state.t === 1 || state.t === 2)) {
763
+ return null;
764
+ }
765
+ if (state.t === 2) {
766
+ let l = t.length - 1;
767
+ t = t[l];
768
+ m = m[l].c;
769
+ }
770
+ }
771
+ k = key[i];
772
+ if ((hasOwn = Object.hasOwn(t, k)) && m[k]?.t === 0 && m[k]?.d) {
773
+ return null;
774
+ }
775
+ if (!hasOwn) {
776
+ if (k === "__proto__") {
777
+ Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true });
778
+ Object.defineProperty(m, k, { enumerable: true, configurable: true, writable: true });
779
+ }
780
+ m[k] = {
781
+ t: i < key.length - 1 && type === 2 ? 3 : type,
782
+ d: false,
783
+ i: 0,
784
+ c: {}
785
+ };
786
+ }
787
+ }
788
+ state = m[k];
789
+ if (state.t !== type && !(type === 1 && state.t === 3)) {
790
+ return null;
791
+ }
792
+ if (type === 2) {
793
+ if (!state.d) {
794
+ state.d = true;
795
+ t[k] = [];
796
+ }
797
+ t[k].push(t = {});
798
+ state.c[state.i++] = state = { t: 1, d: false, i: 0, c: {} };
799
+ }
800
+ if (state.d) {
801
+ return null;
802
+ }
803
+ state.d = true;
804
+ if (type === 1) {
805
+ t = hasOwn ? t[k] : t[k] = {};
806
+ } else if (type === 0 && hasOwn) {
807
+ return null;
808
+ }
809
+ return [k, t, state.c];
810
+ }
811
+ function parse(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
812
+ let res = {};
813
+ let meta = {};
814
+ let tbl = res;
815
+ let m = meta;
816
+ for (let ptr = skipVoid(toml, 0); ptr < toml.length; ) {
817
+ if (toml[ptr] === "[") {
818
+ let isTableArray = toml[++ptr] === "[";
819
+ let k = parseKey(toml, ptr += +isTableArray, "]");
820
+ if (isTableArray) {
821
+ if (toml[k[1] - 1] !== "]") {
822
+ throw new TomlError("expected end of table declaration", {
823
+ toml,
824
+ ptr: k[1] - 1
825
+ });
826
+ }
827
+ k[1]++;
828
+ }
829
+ let p = peekTable(
830
+ k[0],
831
+ res,
832
+ meta,
833
+ isTableArray ? 2 : 1
834
+ /* Type.EXPLICIT */
835
+ );
836
+ if (!p) {
837
+ throw new TomlError("trying to redefine an already defined table or value", {
838
+ toml,
839
+ ptr
840
+ });
841
+ }
842
+ m = p[2];
843
+ tbl = p[1];
844
+ ptr = k[1];
845
+ } else {
846
+ let k = parseKey(toml, ptr);
847
+ let p = peekTable(
848
+ k[0],
849
+ tbl,
850
+ m,
851
+ 0
852
+ /* Type.DOTTED */
853
+ );
854
+ if (!p) {
855
+ throw new TomlError("trying to redefine an already defined table or value", {
856
+ toml,
857
+ ptr
858
+ });
859
+ }
860
+ let v = extractValue(toml, k[1], void 0, maxDepth, integersAsBigInt);
861
+ p[1][p[0]] = v[0];
862
+ ptr = v[1];
863
+ }
864
+ ptr = skipVoid(toml, ptr, true);
865
+ if (toml[ptr] && toml[ptr] !== "\n" && toml[ptr] !== "\r") {
866
+ throw new TomlError("each key-value declaration must be followed by an end-of-line", {
867
+ toml,
868
+ ptr
869
+ });
870
+ }
871
+ ptr = skipVoid(toml, ptr);
872
+ }
873
+ return res;
874
+ }
875
+
876
+ // ../../../main/node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/stringify.js
877
+ var BARE_KEY = /^[a-z0-9-_]+$/i;
878
+ function extendedTypeOf(obj) {
879
+ let type = typeof obj;
880
+ if (type === "object") {
881
+ if (Array.isArray(obj))
882
+ return "array";
883
+ if (obj instanceof Date)
884
+ return "date";
885
+ }
886
+ return type;
887
+ }
888
+ function isArrayOfTables(obj) {
889
+ for (let i = 0; i < obj.length; i++) {
890
+ if (extendedTypeOf(obj[i]) !== "object")
891
+ return false;
892
+ }
893
+ return obj.length != 0;
894
+ }
895
+ function formatString(s) {
896
+ return JSON.stringify(s).replace(/\x7f/g, "\\u007f");
897
+ }
898
+ function stringifyValue(val, type, depth, numberAsFloat) {
899
+ if (depth === 0) {
900
+ throw new Error("Could not stringify the object: maximum object depth exceeded");
901
+ }
902
+ if (type === "number") {
903
+ if (isNaN(val))
904
+ return "nan";
905
+ if (val === Infinity)
906
+ return "inf";
907
+ if (val === -Infinity)
908
+ return "-inf";
909
+ if (numberAsFloat && Number.isInteger(val))
910
+ return val.toFixed(1);
911
+ return val.toString();
912
+ }
913
+ if (type === "bigint" || type === "boolean") {
914
+ return val.toString();
915
+ }
916
+ if (type === "string") {
917
+ return formatString(val);
918
+ }
919
+ if (type === "date") {
920
+ if (isNaN(val.getTime())) {
921
+ throw new TypeError("cannot serialize invalid date");
922
+ }
923
+ return val.toISOString();
924
+ }
925
+ if (type === "object") {
926
+ return stringifyInlineTable(val, depth, numberAsFloat);
927
+ }
928
+ if (type === "array") {
929
+ return stringifyArray(val, depth, numberAsFloat);
930
+ }
931
+ }
932
+ function stringifyInlineTable(obj, depth, numberAsFloat) {
933
+ let keys = Object.keys(obj);
934
+ if (keys.length === 0)
935
+ return "{}";
936
+ let res = "{ ";
937
+ for (let i = 0; i < keys.length; i++) {
938
+ let k = keys[i];
939
+ if (i)
940
+ res += ", ";
941
+ res += BARE_KEY.test(k) ? k : formatString(k);
942
+ res += " = ";
943
+ res += stringifyValue(obj[k], extendedTypeOf(obj[k]), depth - 1, numberAsFloat);
944
+ }
945
+ return res + " }";
946
+ }
947
+ function stringifyArray(array, depth, numberAsFloat) {
948
+ if (array.length === 0)
949
+ return "[]";
950
+ let res = "[ ";
951
+ for (let i = 0; i < array.length; i++) {
952
+ if (i)
953
+ res += ", ";
954
+ if (array[i] === null || array[i] === void 0) {
955
+ throw new TypeError("arrays cannot contain null or undefined values");
956
+ }
957
+ res += stringifyValue(array[i], extendedTypeOf(array[i]), depth - 1, numberAsFloat);
958
+ }
959
+ return res + " ]";
960
+ }
961
+ function stringifyArrayTable(array, key, depth, numberAsFloat) {
962
+ if (depth === 0) {
963
+ throw new Error("Could not stringify the object: maximum object depth exceeded");
964
+ }
965
+ let res = "";
966
+ for (let i = 0; i < array.length; i++) {
967
+ res += `${res && "\n"}[[${key}]]
968
+ `;
969
+ res += stringifyTable(0, array[i], key, depth, numberAsFloat);
970
+ }
971
+ return res;
972
+ }
973
+ function stringifyTable(tableKey, obj, prefix, depth, numberAsFloat) {
974
+ if (depth === 0) {
975
+ throw new Error("Could not stringify the object: maximum object depth exceeded");
976
+ }
977
+ let preamble = "";
978
+ let tables = "";
979
+ let keys = Object.keys(obj);
980
+ for (let i = 0; i < keys.length; i++) {
981
+ let k = keys[i];
982
+ if (obj[k] !== null && obj[k] !== void 0) {
983
+ let type = extendedTypeOf(obj[k]);
984
+ if (type === "symbol" || type === "function") {
985
+ throw new TypeError(`cannot serialize values of type '${type}'`);
986
+ }
987
+ let key = BARE_KEY.test(k) ? k : formatString(k);
988
+ if (type === "array" && isArrayOfTables(obj[k])) {
989
+ tables += (tables && "\n") + stringifyArrayTable(obj[k], prefix ? `${prefix}.${key}` : key, depth - 1, numberAsFloat);
990
+ } else if (type === "object") {
991
+ let tblKey = prefix ? `${prefix}.${key}` : key;
992
+ tables += (tables && "\n") + stringifyTable(tblKey, obj[k], tblKey, depth - 1, numberAsFloat);
993
+ } else {
994
+ preamble += key;
995
+ preamble += " = ";
996
+ preamble += stringifyValue(obj[k], type, depth, numberAsFloat);
997
+ preamble += "\n";
998
+ }
999
+ }
1000
+ }
1001
+ if (tableKey && (preamble || !tables))
1002
+ preamble = preamble ? `[${tableKey}]
1003
+ ${preamble}` : `[${tableKey}]`;
1004
+ return preamble && tables ? `${preamble}
1005
+ ${tables}` : preamble || tables;
1006
+ }
1007
+ function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) {
1008
+ if (extendedTypeOf(obj) !== "object") {
1009
+ throw new TypeError("stringify can only be called with an object");
1010
+ }
1011
+ let str = stringifyTable(0, obj, "", maxDepth, numbersAsFloat);
1012
+ if (str[str.length - 1] !== "\n")
1013
+ return str + "\n";
1014
+ return str;
1015
+ }
1016
+
1017
+ // ../../../main/packages/cli-core/dist/index.js
188
1018
  import { createHash, randomBytes } from "crypto";
189
1019
  import { createServer } from "http";
190
1020
  import { existsSync, mkdirSync as mkdirSync2, readFileSync } from "fs";
@@ -193,7 +1023,7 @@ import { homedir as homedir2 } from "os";
193
1023
  import { join as join2 } from "path";
194
1024
  import pc from "picocolors";
195
1025
 
196
- // ../../node_modules/.pnpm/open@10.2.0/node_modules/open/index.js
1026
+ // ../../../main/node_modules/.pnpm/open@10.2.0/node_modules/open/index.js
197
1027
  import process7 from "process";
198
1028
  import { Buffer as Buffer2 } from "buffer";
199
1029
  import path from "path";
@@ -202,19 +1032,19 @@ import { promisify as promisify5 } from "util";
202
1032
  import childProcess from "child_process";
203
1033
  import fs5, { constants as fsConstants2 } from "fs/promises";
204
1034
 
205
- // ../../node_modules/.pnpm/wsl-utils@0.1.0/node_modules/wsl-utils/index.js
1035
+ // ../../../main/node_modules/.pnpm/wsl-utils@0.1.0/node_modules/wsl-utils/index.js
206
1036
  import process3 from "process";
207
1037
  import fs4, { constants as fsConstants } from "fs/promises";
208
1038
 
209
- // ../../node_modules/.pnpm/is-wsl@3.1.1/node_modules/is-wsl/index.js
1039
+ // ../../../main/node_modules/.pnpm/is-wsl@3.1.0/node_modules/is-wsl/index.js
210
1040
  import process2 from "process";
211
1041
  import os from "os";
212
1042
  import fs3 from "fs";
213
1043
 
214
- // ../../node_modules/.pnpm/is-inside-container@1.0.0/node_modules/is-inside-container/index.js
1044
+ // ../../../main/node_modules/.pnpm/is-inside-container@1.0.0/node_modules/is-inside-container/index.js
215
1045
  import fs2 from "fs";
216
1046
 
217
- // ../../node_modules/.pnpm/is-docker@3.0.0/node_modules/is-docker/index.js
1047
+ // ../../../main/node_modules/.pnpm/is-docker@3.0.0/node_modules/is-docker/index.js
218
1048
  import fs from "fs";
219
1049
  var isDockerCached;
220
1050
  function hasDockerEnv() {
@@ -239,7 +1069,7 @@ function isDocker() {
239
1069
  return isDockerCached;
240
1070
  }
241
1071
 
242
- // ../../node_modules/.pnpm/is-inside-container@1.0.0/node_modules/is-inside-container/index.js
1072
+ // ../../../main/node_modules/.pnpm/is-inside-container@1.0.0/node_modules/is-inside-container/index.js
243
1073
  var cachedResult;
244
1074
  var hasContainerEnv = () => {
245
1075
  try {
@@ -256,7 +1086,7 @@ function isInsideContainer() {
256
1086
  return cachedResult;
257
1087
  }
258
1088
 
259
- // ../../node_modules/.pnpm/is-wsl@3.1.1/node_modules/is-wsl/index.js
1089
+ // ../../../main/node_modules/.pnpm/is-wsl@3.1.0/node_modules/is-wsl/index.js
260
1090
  var isWsl = () => {
261
1091
  if (process2.platform !== "linux") {
262
1092
  return false;
@@ -268,19 +1098,14 @@ var isWsl = () => {
268
1098
  return true;
269
1099
  }
270
1100
  try {
271
- if (fs3.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft")) {
272
- return !isInsideContainer();
273
- }
1101
+ return fs3.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft") ? !isInsideContainer() : false;
274
1102
  } catch {
1103
+ return false;
275
1104
  }
276
- if (fs3.existsSync("/proc/sys/fs/binfmt_misc/WSLInterop") || fs3.existsSync("/run/WSL")) {
277
- return !isInsideContainer();
278
- }
279
- return false;
280
1105
  };
281
1106
  var is_wsl_default = process2.env.__IS_WSL_TEST__ ? isWsl : isWsl();
282
1107
 
283
- // ../../node_modules/.pnpm/wsl-utils@0.1.0/node_modules/wsl-utils/index.js
1108
+ // ../../../main/node_modules/.pnpm/wsl-utils@0.1.0/node_modules/wsl-utils/index.js
284
1109
  var wslDrivesMountPoint = /* @__PURE__ */ (() => {
285
1110
  const defaultMountPoint = "/mnt/";
286
1111
  let mountPoint;
@@ -319,7 +1144,7 @@ var powerShellPath = async () => {
319
1144
  return `${process3.env.SYSTEMROOT || process3.env.windir || String.raw`C:\Windows`}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`;
320
1145
  };
321
1146
 
322
- // ../../node_modules/.pnpm/define-lazy-prop@3.0.0/node_modules/define-lazy-prop/index.js
1147
+ // ../../../main/node_modules/.pnpm/define-lazy-prop@3.0.0/node_modules/define-lazy-prop/index.js
323
1148
  function defineLazyProperty(object, propertyName, valueGetter) {
324
1149
  const define = (value) => Object.defineProperty(object, propertyName, { value, enumerable: true, writable: true });
325
1150
  Object.defineProperty(object, propertyName, {
@@ -337,12 +1162,12 @@ function defineLazyProperty(object, propertyName, valueGetter) {
337
1162
  return object;
338
1163
  }
339
1164
 
340
- // ../../node_modules/.pnpm/default-browser@5.5.0/node_modules/default-browser/index.js
1165
+ // ../../../main/node_modules/.pnpm/default-browser@5.4.0/node_modules/default-browser/index.js
341
1166
  import { promisify as promisify4 } from "util";
342
1167
  import process6 from "process";
343
1168
  import { execFile as execFile4 } from "child_process";
344
1169
 
345
- // ../../node_modules/.pnpm/default-browser-id@5.0.1/node_modules/default-browser-id/index.js
1170
+ // ../../../main/node_modules/.pnpm/default-browser-id@5.0.1/node_modules/default-browser-id/index.js
346
1171
  import { promisify } from "util";
347
1172
  import process4 from "process";
348
1173
  import { execFile } from "child_process";
@@ -360,7 +1185,7 @@ async function defaultBrowserId() {
360
1185
  return browserId;
361
1186
  }
362
1187
 
363
- // ../../node_modules/.pnpm/run-applescript@7.1.0/node_modules/run-applescript/index.js
1188
+ // ../../../main/node_modules/.pnpm/run-applescript@7.1.0/node_modules/run-applescript/index.js
364
1189
  import process5 from "process";
365
1190
  import { promisify as promisify2 } from "util";
366
1191
  import { execFile as execFile2, execFileSync } from "child_process";
@@ -378,13 +1203,13 @@ async function runAppleScript(script, { humanReadableOutput = true, signal } = {
378
1203
  return stdout.trim();
379
1204
  }
380
1205
 
381
- // ../../node_modules/.pnpm/bundle-name@4.1.0/node_modules/bundle-name/index.js
1206
+ // ../../../main/node_modules/.pnpm/bundle-name@4.1.0/node_modules/bundle-name/index.js
382
1207
  async function bundleName(bundleId) {
383
1208
  return runAppleScript(`tell application "Finder" to set app_path to application file id "${bundleId}" as string
384
1209
  tell application "System Events" to get value of property list item "CFBundleName" of property list file (app_path & ":Contents:Info.plist")`);
385
1210
  }
386
1211
 
387
- // ../../node_modules/.pnpm/default-browser@5.5.0/node_modules/default-browser/windows.js
1212
+ // ../../../main/node_modules/.pnpm/default-browser@5.4.0/node_modules/default-browser/windows.js
388
1213
  import { promisify as promisify3 } from "util";
389
1214
  import { execFile as execFile3 } from "child_process";
390
1215
  var execFileAsync3 = promisify3(execFile3);
@@ -422,14 +1247,14 @@ async function defaultBrowser(_execFileAsync = execFileAsync3) {
422
1247
  throw new UnknownBrowserError(`Cannot find Windows browser in stdout: ${JSON.stringify(stdout)}`);
423
1248
  }
424
1249
  const { id } = match.groups;
425
- const dotIndex = id.lastIndexOf(".");
426
- const hyphenIndex = id.lastIndexOf("-");
427
- const baseIdByDot = dotIndex === -1 ? void 0 : id.slice(0, dotIndex);
428
- const baseIdByHyphen = hyphenIndex === -1 ? void 0 : id.slice(0, hyphenIndex);
429
- return windowsBrowserProgIds[id] ?? windowsBrowserProgIds[baseIdByDot] ?? windowsBrowserProgIds[baseIdByHyphen] ?? { name: id, id };
1250
+ const browser = windowsBrowserProgIds[id];
1251
+ if (!browser) {
1252
+ throw new UnknownBrowserError(`Unknown browser ID: ${id}`);
1253
+ }
1254
+ return browser;
430
1255
  }
431
1256
 
432
- // ../../node_modules/.pnpm/default-browser@5.5.0/node_modules/default-browser/index.js
1257
+ // ../../../main/node_modules/.pnpm/default-browser@5.4.0/node_modules/default-browser/index.js
433
1258
  var execFileAsync4 = promisify4(execFile4);
434
1259
  var titleize = (string) => string.toLowerCase().replaceAll(/(?:^|\s|-)\S/g, (x) => x.toUpperCase());
435
1260
  async function defaultBrowser2() {
@@ -450,7 +1275,7 @@ async function defaultBrowser2() {
450
1275
  throw new Error("Only macOS, Linux, and Windows are supported");
451
1276
  }
452
1277
 
453
- // ../../node_modules/.pnpm/open@10.2.0/node_modules/open/index.js
1278
+ // ../../../main/node_modules/.pnpm/open@10.2.0/node_modules/open/index.js
454
1279
  var execFile5 = promisify5(childProcess.execFile);
455
1280
  var __dirname = path.dirname(fileURLToPath(import.meta.url));
456
1281
  var localXdgOpenPath = path.join(__dirname, "xdg-open");
@@ -707,7 +1532,7 @@ defineLazyProperty(apps, "browser", () => "browser");
707
1532
  defineLazyProperty(apps, "browserPrivate", () => "browserPrivate");
708
1533
  var open_default = open;
709
1534
 
710
- // ../../node_modules/.pnpm/@nuucognition+cli-core@0.0.1-beta.5/node_modules/@nuucognition/cli-core/dist/index.js
1535
+ // ../../../main/packages/cli-core/dist/index.js
711
1536
  import { Command } from "commander";
712
1537
  import cfonts from "cfonts";
713
1538
  import pc3 from "picocolors";
@@ -729,9 +1554,9 @@ function normalizeRuntimeMode(input) {
729
1554
  function authEnvForMode(mode) {
730
1555
  return mode === "dev" ? "dev" : "prod";
731
1556
  }
732
- async function readConfigFile(path4) {
1557
+ async function readConfigFile(path5) {
733
1558
  try {
734
- const content = await fsReadFile(path4, "utf-8");
1559
+ const content = await fsReadFile(path5, "utf-8");
735
1560
  return parse(content);
736
1561
  } catch (error22) {
737
1562
  if (error22.code === "ENOENT") {
@@ -740,9 +1565,9 @@ async function readConfigFile(path4) {
740
1565
  throw error22;
741
1566
  }
742
1567
  }
743
- function readConfigFileSync(path4) {
1568
+ function readConfigFileSync(path5) {
744
1569
  try {
745
- const content = fsReadFileSync(path4, "utf-8");
1570
+ const content = fsReadFileSync(path5, "utf-8");
746
1571
  return parse(content);
747
1572
  } catch (error22) {
748
1573
  if (error22.code === "ENOENT") {
@@ -751,25 +1576,25 @@ function readConfigFileSync(path4) {
751
1576
  throw error22;
752
1577
  }
753
1578
  }
754
- async function writeConfigFile(path4, data) {
755
- await mkdir(dirname(path4), { recursive: true });
756
- await fsWriteFile(path4, `${stringify(data)}
1579
+ async function writeConfigFile(path5, data) {
1580
+ await mkdir(dirname(path5), { recursive: true });
1581
+ await fsWriteFile(path5, `${stringify(data)}
757
1582
  `, "utf-8");
758
1583
  }
759
- async function setConfigField(path4, key, value) {
760
- const existing = await readConfigFile(path4) ?? {};
1584
+ async function setConfigField(path5, key, value) {
1585
+ const existing = await readConfigFile(path5) ?? {};
761
1586
  existing[key] = value;
762
- await writeConfigFile(path4, existing);
1587
+ await writeConfigFile(path5, existing);
763
1588
  }
764
- async function setFeatureOverride(path4, featureId, enabled) {
765
- const existing = await readConfigFile(path4) ?? {};
1589
+ async function setFeatureOverride(path5, featureId, enabled) {
1590
+ const existing = await readConfigFile(path5) ?? {};
766
1591
  const features = existing.features && typeof existing.features === "object" && !Array.isArray(existing.features) ? { ...existing.features } : {};
767
1592
  features[featureId] = enabled;
768
1593
  existing.features = features;
769
- await writeConfigFile(path4, existing);
1594
+ await writeConfigFile(path5, existing);
770
1595
  }
771
- async function removeFeatureOverride(path4, featureId) {
772
- const existing = await readConfigFile(path4);
1596
+ async function removeFeatureOverride(path5, featureId) {
1597
+ const existing = await readConfigFile(path5);
773
1598
  if (!existing) return;
774
1599
  const features = existing.features;
775
1600
  if (!features || typeof features !== "object" || Array.isArray(features)) {
@@ -782,7 +1607,7 @@ async function removeFeatureOverride(path4, featureId) {
782
1607
  } else {
783
1608
  existing.features = next;
784
1609
  }
785
- await writeConfigFile(path4, existing);
1610
+ await writeConfigFile(path5, existing);
786
1611
  }
787
1612
  var CONFIG_FILENAME = "config.toml";
788
1613
  function getConfigDir(cliname) {
@@ -991,9 +1816,9 @@ async function loadAuth(env = "prod") {
991
1816
  function loadAuthSync(env = "prod") {
992
1817
  try {
993
1818
  ensureNuuDirSync();
994
- const path4 = authPath(env);
995
- if (!existsSync(path4)) return null;
996
- return normalizeCredentials(JSON.parse(readFileSync(path4, "utf-8")));
1819
+ const path5 = authPath(env);
1820
+ if (!existsSync(path5)) return null;
1821
+ return normalizeCredentials(JSON.parse(readFileSync(path5, "utf-8")));
997
1822
  } catch {
998
1823
  return null;
999
1824
  }
@@ -1480,7 +2305,7 @@ var FEATURES = createFeatureRegistry([
1480
2305
  { id: "agent", tier: "prod", type: "command", description: "Headless agent management", requiresAuth: false },
1481
2306
  { id: "tinderbox", tier: "prod", type: "command", description: "Orchestrate operations across multiple Flints", requiresAuth: false },
1482
2307
  { id: "code", tier: "prod", type: "command", description: "Launch AI coding agents", requiresAuth: false },
1483
- { id: "orb", tier: "prod", type: "command", description: "OrbH meta-harness agent management", requiresAuth: false },
2308
+ { id: "orb", tier: "prod", type: "command", description: "Orbh meta-harness agent management", requiresAuth: false },
1484
2309
  { id: "server", tier: "prod", type: "command", description: "Flint runtime server", requiresAuth: false },
1485
2310
  { id: "runtime", tier: "dev", type: "command", description: "Flint runtime management", requiresAuth: false },
1486
2311
  { id: "obsidian.push", tier: "dev", type: "function", description: "Push obsidian config changes to remote", requiresAuth: false },
@@ -1558,25 +2383,25 @@ function createProgressDisplay(label, total) {
1558
2383
  import { homedir as homedir3 } from "os";
1559
2384
  import { access } from "fs/promises";
1560
2385
  import { createInterface } from "readline";
1561
- function abbreviatePath(path4) {
2386
+ function abbreviatePath(path5) {
1562
2387
  const home = homedir3();
1563
- if (path4.startsWith(home)) {
1564
- return path4.replace(home, "~");
2388
+ if (path5.startsWith(home)) {
2389
+ return path5.replace(home, "~");
1565
2390
  }
1566
- return path4;
2391
+ return path5;
1567
2392
  }
1568
- function expandPath(path4) {
1569
- if (path4.startsWith("~/")) {
1570
- return path4.replace("~", homedir3());
2393
+ function expandPath(path5) {
2394
+ if (path5.startsWith("~/")) {
2395
+ return path5.replace("~", homedir3());
1571
2396
  }
1572
- return path4;
2397
+ return path5;
1573
2398
  }
1574
2399
  function padEnd(str, length) {
1575
2400
  return str.padEnd(length);
1576
2401
  }
1577
- async function checkPathExists(path4) {
2402
+ async function checkPathExists(path5) {
1578
2403
  try {
1579
- await access(path4);
2404
+ await access(path5);
1580
2405
  return true;
1581
2406
  } catch {
1582
2407
  return false;
@@ -1827,12 +2652,12 @@ function resolvePath(flint, fullPath) {
1827
2652
  }
1828
2653
  function printFlint(flint, opts) {
1829
2654
  const { nameColWidth, showStatus, fullPath, indent = " " } = opts;
1830
- const path4 = resolvePath(flint, fullPath);
2655
+ const path5 = resolvePath(flint, fullPath);
1831
2656
  const isBroken = showStatus && !flint.valid;
1832
2657
  const tags = formatTags(flint.tags);
1833
2658
  const nameCell = tags ? `${pc7.bold(flint.name)} ${tags}` : pc7.bold(flint.name);
1834
2659
  const status = showStatus ? statusBadge(flint) + " " : "";
1835
- const pathColor = isBroken ? pc7.red(path4) : pc7.dim(path4);
2660
+ const pathColor = isBroken ? pc7.red(path5) : pc7.dim(path5);
1836
2661
  console.log(`${indent}${pad(nameCell, nameColWidth)}${status}${pathColor}`);
1837
2662
  if (flint.description) {
1838
2663
  console.log(`${indent} ${pc7.dim(truncate(flint.description, 65))}`);
@@ -1840,10 +2665,10 @@ function printFlint(flint, opts) {
1840
2665
  }
1841
2666
  function printGroupRow(flint, opts) {
1842
2667
  const { nameColWidth, showStatus, fullPath } = opts;
1843
- const path4 = resolvePath(flint, fullPath);
2668
+ const path5 = resolvePath(flint, fullPath);
1844
2669
  const isBroken = showStatus && !flint.valid;
1845
2670
  const status = showStatus ? statusBadge(flint) + " " : "";
1846
- const pathColor = isBroken ? pc7.red(path4) : pc7.dim(path4);
2671
+ const pathColor = isBroken ? pc7.red(path5) : pc7.dim(path5);
1847
2672
  console.log(` ${pad(flint.name, nameColWidth)}${status}${pathColor}`);
1848
2673
  }
1849
2674
  function measureNameCol(flints) {
@@ -3637,9 +4462,23 @@ var syncCommand = new Command6("sync").description("Sync shards from flint.toml"
3637
4462
  if (result.migrations.pending.length > 0) {
3638
4463
  console.log(pc9.bold("Migrations:"));
3639
4464
  console.log(pc9.yellow(` ${result.migrations.pending.length} migration(s) available:`));
4465
+ const migrationsByVersion = /* @__PURE__ */ new Map();
3640
4466
  for (const m of result.migrations.pending) {
3641
- console.log(` ${pc9.yellow("\u2192")} ${m.name} ${pc9.dim(`(${m.from} \u2192 ${m.to})`)}`);
3642
- console.log(` ${pc9.dim(m.description)}`);
4467
+ const existing = migrationsByVersion.get(m.to) || [];
4468
+ existing.push(m);
4469
+ migrationsByVersion.set(m.to, existing);
4470
+ }
4471
+ for (const [version, items] of migrationsByVersion) {
4472
+ const sealed = isVersionStepSealed(version);
4473
+ if (!sealed) {
4474
+ console.log(` ${pc9.yellow("\u2192")} ${pc9.bold(version)} ${pc9.yellow("(unsealed \u2014 version will not advance)")}`);
4475
+ } else {
4476
+ console.log(` ${pc9.yellow("\u2192")} ${pc9.bold(version)}`);
4477
+ }
4478
+ for (const m of items) {
4479
+ console.log(` ${m.name} ${pc9.dim(`(${m.from} \u2192 ${m.to})`)}`);
4480
+ console.log(` ${pc9.dim(m.description)}`);
4481
+ }
3643
4482
  }
3644
4483
  console.log(pc9.dim(`
3645
4484
  Run \`flint migrate\` to apply.
@@ -4120,9 +4959,9 @@ var REQUIRED_DIRS = [
4120
4959
  "Workspace/Bench",
4121
4960
  ".flint"
4122
4961
  ];
4123
- async function exists(path4) {
4962
+ async function exists(path5) {
4124
4963
  try {
4125
- await access2(path4);
4964
+ await access2(path5);
4126
4965
  return true;
4127
4966
  } catch {
4128
4967
  return false;
@@ -4347,9 +5186,9 @@ import pc12 from "picocolors";
4347
5186
  import { readFile as readFile4, stat } from "fs/promises";
4348
5187
  import { join as join7, basename as basename2 } from "path";
4349
5188
  import { createInterface as createInterface2 } from "readline";
4350
- async function exists2(path4) {
5189
+ async function exists2(path5) {
4351
5190
  try {
4352
- await stat(path4);
5191
+ await stat(path5);
4353
5192
  return true;
4354
5193
  } catch {
4355
5194
  return false;
@@ -4643,17 +5482,17 @@ import { resolve as resolve2 } from "path";
4643
5482
  import { platform as platform3 } from "os";
4644
5483
  import pc13 from "picocolors";
4645
5484
  var execAsync2 = promisify7(exec2);
4646
- async function openInObsidian(path4) {
5485
+ async function openInObsidian(path5) {
4647
5486
  const os2 = platform3();
4648
5487
  if (os2 === "darwin") {
4649
- await execAsync2(`open -a "Obsidian" "${path4}"`);
5488
+ await execAsync2(`open -a "Obsidian" "${path5}"`);
4650
5489
  } else if (os2 === "win32") {
4651
- await execAsync2(`start "" "Obsidian" "${path4}"`);
5490
+ await execAsync2(`start "" "Obsidian" "${path5}"`);
4652
5491
  } else {
4653
5492
  try {
4654
- await execAsync2(`obsidian "${path4}"`);
5493
+ await execAsync2(`obsidian "${path5}"`);
4655
5494
  } catch {
4656
- await execAsync2(`xdg-open "${path4}"`);
5495
+ await execAsync2(`xdg-open "${path5}"`);
4657
5496
  }
4658
5497
  }
4659
5498
  }
@@ -4745,7 +5584,7 @@ if (!configJson) {
4745
5584
  }
4746
5585
 
4747
5586
  const { sessionPath, flintPath, prompt, claudeArgs, sessionId, runId } = JSON.parse(configJson);
4748
- const dashboardUrl = 'http://localhost:7433/agent#session-' + sessionId;
5587
+ const dashboardUrl = 'http://localhost:13040/agent#session-' + sessionId;
4749
5588
 
4750
5589
  function readSession() {
4751
5590
  try {
@@ -6100,7 +6939,7 @@ plateCommand.command("create").description("Scaffold a new Plate").argument("<na
6100
6939
  const flintPath = await resolveFlintPath2(options.path);
6101
6940
  const plate = await createPlate(flintPath, name, { shard: options.shard });
6102
6941
  console.log(pc22.green(`
6103
- Created Plate ${pc22.bold(plate.manifest.display)}`));
6942
+ Created Plate ${pc22.bold(plate.manifest.title)}`));
6104
6943
  console.log(` Name: ${pc22.cyan(plate.manifest.name)}`);
6105
6944
  console.log(` Path: ${pc22.dim(plate.path)}`);
6106
6945
  if (plate.manifest.shard) {
@@ -6130,15 +6969,15 @@ plateCommand.command("list").description("List installed Plates").option("-p, --
6130
6969
  return;
6131
6970
  }
6132
6971
  const nameWidth = Math.max(4, ...plates.map((plate) => plate.manifest.name.length)) + 2;
6133
- const displayWidth = Math.max(7, ...plates.map((plate) => plate.manifest.display.length)) + 2;
6972
+ const titleWidth = Math.max(5, ...plates.map((plate) => plate.manifest.title.length)) + 2;
6134
6973
  const shardWidth = Math.max(5, ...plates.map((plate) => (plate.manifest.shard ?? "\u2014").length)) + 2;
6135
6974
  console.log();
6136
6975
  console.log(
6137
- ` ${pad2(pc22.bold("Name"), nameWidth)}${pad2(pc22.bold("Display"), displayWidth)}${pad2(pc22.bold("Shard"), shardWidth)}${pc22.bold("Built")}`
6976
+ ` ${pad2(pc22.bold("Name"), nameWidth)}${pad2(pc22.bold("Title"), titleWidth)}${pad2(pc22.bold("Shard"), shardWidth)}${pc22.bold("Built")}`
6138
6977
  );
6139
6978
  for (const plate of plates) {
6140
6979
  console.log(
6141
- ` ${pad2(plate.manifest.name, nameWidth)}${pad2(plate.manifest.display, displayWidth)}${pad2(plate.manifest.shard ?? "\u2014", shardWidth)}${plate.built ? pc22.green("yes") : pc22.yellow("no")}`
6980
+ ` ${pad2(plate.manifest.name, nameWidth)}${pad2(plate.manifest.title, titleWidth)}${pad2(plate.manifest.shard ?? "\u2014", shardWidth)}${plate.built ? pc22.green("yes") : pc22.yellow("no")}`
6142
6981
  );
6143
6982
  }
6144
6983
  console.log();
@@ -6158,7 +6997,7 @@ repoCommand.command("add").description("Add a plate from a git repo").argument("
6158
6997
  getPlateDeclaration,
6159
6998
  nameFormats,
6160
6999
  updateGitignore: updateGitignore2
6161
- } = await import("./dist-PKS3JY77.js");
7000
+ } = await import("./dist-RGQKIZQW.js");
6162
7001
  const { proper, slug } = nameFormats(name);
6163
7002
  const existing = await getPlateDeclaration(flintPath, slug);
6164
7003
  if (existing) {
@@ -6170,7 +7009,7 @@ repoCommand.command("add").description("Add a plate from a git repo").argument("
6170
7009
  Cloning ${url}...`));
6171
7010
  await clonePlateFromRepo(flintPath, slug, url, platePath);
6172
7011
  await addPlateDeclaration(flintPath, slug, platePath, { title: proper });
6173
- const { setPlateRepo } = await import("./dist-PKS3JY77.js");
7012
+ const { setPlateRepo } = await import("./dist-RGQKIZQW.js");
6174
7013
  await setPlateRepo(flintPath, slug, url);
6175
7014
  await updateGitignore2(flintPath);
6176
7015
  console.log(pc22.green(`
@@ -6188,8 +7027,8 @@ Added plate: ${pc22.bold(proper)}`));
6188
7027
  repoCommand.command("remove").description("Remove a repo-sourced plate").argument("<name>", "Plate declaration name or slug").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (name, options) => {
6189
7028
  try {
6190
7029
  const flintPath = await resolveFlintPath2(options.path);
6191
- const { removePlateDeclaration, updateGitignore: updateGitignore2 } = await import("./dist-PKS3JY77.js");
6192
- const { rm: rm5, stat: stat8 } = await import("fs/promises");
7030
+ const { removePlateDeclaration, updateGitignore: updateGitignore2 } = await import("./dist-RGQKIZQW.js");
7031
+ const { rm: rm5, stat: stat9 } = await import("fs/promises");
6193
7032
  const { join: join19 } = await import("path");
6194
7033
  const plate = await getPlate(flintPath, name);
6195
7034
  if (!plate) {
@@ -6197,14 +7036,14 @@ repoCommand.command("remove").description("Remove a repo-sourced plate").argumen
6197
7036
  process.exit(1);
6198
7037
  }
6199
7038
  try {
6200
- await stat8(plate.path);
7039
+ await stat9(plate.path);
6201
7040
  await rm5(plate.path, { recursive: true, force: true });
6202
7041
  } catch {
6203
7042
  }
6204
7043
  await removePlateDeclaration(flintPath, plate.declarationName);
6205
7044
  await updateGitignore2(flintPath);
6206
7045
  console.log(pc22.green(`
6207
- Removed plate: ${pc22.bold(plate.manifest.display)}
7046
+ Removed plate: ${pc22.bold(plate.manifest.title)}
6208
7047
  `));
6209
7048
  } catch (err) {
6210
7049
  const message = err instanceof Error ? err.message : String(err);
@@ -6213,10 +7052,65 @@ Removed plate: ${pc22.bold(plate.manifest.display)}
6213
7052
  }
6214
7053
  });
6215
7054
  plateCommand.addCommand(repoCommand);
7055
+ plateCommand.command("install").description("Install a Plate from a git repo URL").argument("<url>", "Git repo URL to clone").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (url, options) => {
7056
+ try {
7057
+ const flintPath = await resolveFlintPath2(options.path);
7058
+ const {
7059
+ addPlateDeclaration,
7060
+ clonePlateFromRepo,
7061
+ readPlateManifest,
7062
+ setPlateRepo,
7063
+ updateGitignore: updateGitignore2
7064
+ } = await import("./dist-RGQKIZQW.js");
7065
+ const { join: join19 } = await import("path");
7066
+ const { mkdtemp: mkdtemp2, rm: rm5, rename: rename2 } = await import("fs/promises");
7067
+ const { tmpdir: tmpdir2 } = await import("os");
7068
+ const tmpDir = await mkdtemp2(join19(tmpdir2(), "flint-plate-"));
7069
+ console.log(pc22.dim(`
7070
+ Cloning ${url}...`));
7071
+ try {
7072
+ await clonePlateFromRepo(flintPath, "temp", url, tmpDir);
7073
+ } catch {
7074
+ const { execSync: execSync6 } = await import("child_process");
7075
+ execSync6(`git clone --depth 1 "${url}" "${tmpDir}"`, { timeout: 6e4, stdio: "ignore" });
7076
+ await rm5(join19(tmpDir, ".git"), { recursive: true, force: true }).catch(() => {
7077
+ });
7078
+ }
7079
+ const manifest = await readPlateManifest(tmpDir);
7080
+ const slug = manifest.name;
7081
+ const title = manifest.title;
7082
+ const existing = await getPlate(flintPath, slug);
7083
+ if (existing) {
7084
+ await rm5(tmpDir, { recursive: true, force: true });
7085
+ console.error(pc22.red(`Error: Plate "${slug}" already exists.`));
7086
+ process.exit(1);
7087
+ }
7088
+ const { mkdir: mkdir8 } = await import("fs/promises");
7089
+ const platePath = `Plates/${title}`;
7090
+ const absolutePlatePath = join19(flintPath, platePath);
7091
+ await mkdir8(join19(flintPath, "Plates"), { recursive: true });
7092
+ await rename2(tmpDir, absolutePlatePath);
7093
+ await addPlateDeclaration(flintPath, slug, platePath, { title });
7094
+ await setPlateRepo(flintPath, slug, url);
7095
+ await updateGitignore2(flintPath);
7096
+ console.log(pc22.green(`
7097
+ Installed plate: ${pc22.bold(title)}`));
7098
+ console.log(` Slug: ${pc22.cyan(slug)}`);
7099
+ console.log(` Title: ${title}`);
7100
+ console.log(` Path: ${pc22.dim(platePath)}`);
7101
+ console.log(` URL: ${pc22.dim(url)}`);
7102
+ console.log(pc22.dim("\nThe server will auto-build this plate on next startup."));
7103
+ console.log();
7104
+ } catch (err) {
7105
+ const message = err instanceof Error ? err.message : String(err);
7106
+ console.error(pc22.red(`Error: ${message}`));
7107
+ process.exit(1);
7108
+ }
7109
+ });
6216
7110
  plateCommand.command("push").description("Initialize a plate as a git repo, set remote, and push").argument("<name>", "Plate name").argument("<url>", "Git remote URL").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (name, url, options) => {
6217
7111
  try {
6218
7112
  const flintPath = await resolveFlintPath2(options.path);
6219
- const { setPlateRepo } = await import("./dist-PKS3JY77.js");
7113
+ const { setPlateRepo } = await import("./dist-RGQKIZQW.js");
6220
7114
  console.log(pc22.dim(`
6221
7115
  Pushing plate "${name}"...`));
6222
7116
  const result = await initPlateRepo(flintPath, name, url);
@@ -6242,7 +7136,7 @@ Pushing plate "${name}"...`));
6242
7136
  plateCommand.command("sync").description("Sync plates that have a repo configured").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (options) => {
6243
7137
  try {
6244
7138
  const flintPath = await resolveFlintPath2(options.path);
6245
- const { getPlateDeclarations, syncPlateRepos } = await import("./dist-PKS3JY77.js");
7139
+ const { getPlateDeclarations, syncPlateRepos } = await import("./dist-RGQKIZQW.js");
6246
7140
  const declarations = await getPlateDeclarations(flintPath);
6247
7141
  const hasRepos = Object.values(declarations).some((d) => d.repo);
6248
7142
  if (!hasRepos) {
@@ -6261,6 +7155,8 @@ plateCommand.command("sync").description("Sync plates that have a repo configure
6261
7155
  console.log(` ${pc22.green("+")} ${pr.name} ${pc22.dim("(cloned)")}`);
6262
7156
  } else if (pr.status === "updated") {
6263
7157
  console.log(` ${pc22.green("\u2713")} ${pr.name} ${pc22.dim("(updated)")}`);
7158
+ } else if (pr.status === "skipped") {
7159
+ console.log(` ${pc22.dim("\u25CB")} ${pr.name} ${pc22.dim("(exists, skipped)")}`);
6264
7160
  } else if (pr.status === "error") {
6265
7161
  console.log(` ${pc22.red("\u2717")} ${pr.name} \u2014 ${pr.error}`);
6266
7162
  }
@@ -6281,7 +7177,7 @@ plateCommand.command("info").description("Show Plate details").argument("<name>"
6281
7177
  }
6282
7178
  console.log();
6283
7179
  console.log(`${pc22.bold("Name:")} ${pc22.cyan(plate.manifest.name)}`);
6284
- console.log(`${pc22.bold("Display:")} ${plate.manifest.display}`);
7180
+ console.log(`${pc22.bold("Title:")} ${plate.manifest.title}`);
6285
7181
  console.log(`${pc22.bold("Version:")} ${plate.manifest.version ?? "0.1.0"}`);
6286
7182
  console.log(`${pc22.bold("Shard:")} ${plate.manifest.shard ?? "\u2014"}`);
6287
7183
  console.log(`${pc22.bold("Entry:")} ${plate.manifest.entry}`);
@@ -6316,7 +7212,7 @@ plateCommand.command("dev").description("Start a Plate dev server").argument("<n
6316
7212
  if (!plate) {
6317
7213
  throw new Error(`Plate not found: ${name}`);
6318
7214
  }
6319
- console.log(pc22.dim(`Starting dev server for ${plate.manifest.display}...
7215
+ console.log(pc22.dim(`Starting dev server for ${plate.manifest.title}...
6320
7216
  `));
6321
7217
  const child = spawnPlateDevServer(flintPath, plate);
6322
7218
  child.on("exit", (code) => process.exit(code ?? 0));
@@ -6516,9 +7412,9 @@ repoCommand2.addCommand(
6516
7412
  }
6517
7413
  })
6518
7414
  );
6519
- async function fileExists(path4) {
7415
+ async function fileExists(path5) {
6520
7416
  try {
6521
- await stat3(path4);
7417
+ await stat3(path5);
6522
7418
  return true;
6523
7419
  } catch {
6524
7420
  return false;
@@ -7136,11 +8032,33 @@ var latticeCommand = new Command21("lattice").description("Manage lattice connec
7136
8032
 
7137
8033
  // src/commands/server.ts
7138
8034
  import { Command as Command22 } from "commander";
8035
+ import { createRequire } from "module";
8036
+ import path3 from "path";
8037
+ import { spawn as spawn4 } from "child_process";
8038
+ import { stat as stat4 } from "fs/promises";
7139
8039
  import pc25 from "picocolors";
8040
+ var SERVER_SHUTDOWN_TIMEOUT_MS = 5e3;
8041
+ var FLINT_SERVER_PACKAGE = "@nuucognition/flint-server";
8042
+ var SHUTDOWN_HEADER_NAME = "x-flint-shutdown";
8043
+ var SHUTDOWN_HEADER_VALUE = "true";
8044
+ async function importFlintServer() {
8045
+ const require2 = createRequire(import.meta.url);
8046
+ try {
8047
+ const resolved = require2.resolve(FLINT_SERVER_PACKAGE);
8048
+ return await import(resolved);
8049
+ } catch (error3) {
8050
+ if (error3 instanceof Error && (error3.code === "ERR_MODULE_NOT_FOUND" || error3.code === "MODULE_NOT_FOUND" || error3.message.includes(`Cannot find package '${FLINT_SERVER_PACKAGE}'`) || error3.message.includes(`Cannot find module '${FLINT_SERVER_PACKAGE}'`))) {
8051
+ console.error(pc25.red(`Error: ${FLINT_SERVER_PACKAGE} is not installed.`));
8052
+ console.log(pc25.dim("The server module is in development. Install it locally to use this command."));
8053
+ process.exit(1);
8054
+ }
8055
+ throw error3;
8056
+ }
8057
+ }
7140
8058
  var serverCommand = new Command22("server").description("Manage the local Flint server");
7141
- serverCommand.command("start").description("Start the Flint server").option("-p, --port <port>", "Port to bind").option("--path <dir>", "Path to flint (default: auto-detect)").action(async (options) => {
8059
+ serverCommand.command("start").description("Start the Flint server").option("-p, --port <port>", "Port to bind").option("--path <dir>", "Path to flint (default: auto-detect)").option("--steel-url <url>", "Paired Steel host URL for cascading shutdown").action(async (options) => {
7142
8060
  const flintPath = options.path || await findFlintRoot(process.cwd());
7143
- let configPort = 7433;
8061
+ let configPort = 13040;
7144
8062
  if (flintPath) {
7145
8063
  try {
7146
8064
  const config = await readFlintToml(flintPath);
@@ -7149,15 +8067,9 @@ serverCommand.command("start").description("Start the Flint server").option("-p,
7149
8067
  }
7150
8068
  }
7151
8069
  const port = options.port ? Number(options.port) : configPort;
7152
- let startFlintServer;
7153
- try {
7154
- ({ startFlintServer } = await import("@nuucognition/flint-server"));
7155
- } catch {
7156
- console.error(pc25.red("Error: @nuucognition/flint-server is not installed."));
7157
- console.log(pc25.dim("The server module is in development. Install it locally to use this command."));
7158
- process.exit(1);
7159
- }
7160
- const server = await startFlintServer({ port, flintPath });
8070
+ const steelUrl = typeof options.steelUrl === "string" ? options.steelUrl.trim() : void 0;
8071
+ const { startFlintServer } = await importFlintServer();
8072
+ const server = await startFlintServer({ port, flintPath, steelUrl });
7161
8073
  console.log(`
7162
8074
  ${pc25.bold(pc25.blue("Flint Server"))}`);
7163
8075
  console.log(` URL: ${pc25.cyan(server.address)}`);
@@ -7169,14 +8081,76 @@ ${pc25.bold(pc25.blue("Flint Server"))}`);
7169
8081
  console.log(`
7170
8082
  ${pc25.dim('Session endpoint: POST /sessions { "prompt": "..." }')}
7171
8083
  `);
7172
- const handleShutdown = async () => {
7173
- await server.close();
7174
- process.exit(0);
8084
+ let shutdownPromise = null;
8085
+ let shutdownTimer = null;
8086
+ const handleShutdown = (signal) => {
8087
+ if (shutdownPromise) {
8088
+ console.error(pc25.red(`Received ${signal} during shutdown. Forcing Flint server exit.`));
8089
+ process.exit(1);
8090
+ }
8091
+ console.log(pc25.dim(`Received ${signal}. Shutting down Flint server...`));
8092
+ shutdownTimer = setTimeout(() => {
8093
+ console.error(pc25.red(`Flint server did not shut down within ${SERVER_SHUTDOWN_TIMEOUT_MS}ms. Forcing exit.`));
8094
+ process.exit(1);
8095
+ }, SERVER_SHUTDOWN_TIMEOUT_MS);
8096
+ shutdownTimer.unref?.();
8097
+ shutdownPromise = (async () => {
8098
+ try {
8099
+ await server.close();
8100
+ process.exit(0);
8101
+ } catch (error3) {
8102
+ const message = error3 instanceof Error ? error3.message : String(error3);
8103
+ console.error(pc25.red(`Flint server shutdown failed: ${message}`));
8104
+ process.exit(1);
8105
+ } finally {
8106
+ if (shutdownTimer) {
8107
+ clearTimeout(shutdownTimer);
8108
+ shutdownTimer = null;
8109
+ }
8110
+ }
8111
+ })();
7175
8112
  };
7176
- process.on("SIGINT", handleShutdown);
7177
- process.on("SIGTERM", handleShutdown);
8113
+ process.on("SIGINT", () => handleShutdown("SIGINT"));
8114
+ process.on("SIGTERM", () => handleShutdown("SIGTERM"));
8115
+ });
8116
+ serverCommand.command("dev").description("Start the server in dev mode with auto-reload on source changes").option("-p, --port <port>", "Port to bind").option("--path <dir>", "Path to flint (default: auto-detect)").action(async (options) => {
8117
+ const require2 = createRequire(import.meta.url);
8118
+ let serverPkgDir;
8119
+ try {
8120
+ const serverPkgJson = require2.resolve(`${FLINT_SERVER_PACKAGE}/package.json`);
8121
+ serverPkgDir = path3.dirname(serverPkgJson);
8122
+ } catch {
8123
+ console.error(pc25.red("Error: flint-server package not found."));
8124
+ process.exit(1);
8125
+ }
8126
+ const devEntry = path3.join(serverPkgDir, "src", "dev.ts");
8127
+ try {
8128
+ await stat4(devEntry);
8129
+ } catch {
8130
+ console.error(pc25.red("Dev mode requires the server source directory."));
8131
+ console.log(pc25.dim("This command only works from the monorepo development environment."));
8132
+ process.exit(1);
8133
+ }
8134
+ const env = { ...process.env };
8135
+ if (options.port) env.FLINT_SERVER_PORT = String(options.port);
8136
+ if (options.path) {
8137
+ env.FLINT_PATH = options.path;
8138
+ } else {
8139
+ const detected = await findFlintRoot(process.cwd());
8140
+ if (detected) env.FLINT_PATH = detected;
8141
+ }
8142
+ console.log(`${pc25.bold(pc25.blue("Flint Server"))} ${pc25.dim("dev mode \u2014 watching for changes")}
8143
+ `);
8144
+ const child = spawn4("tsx", ["watch", devEntry], {
8145
+ env,
8146
+ stdio: "inherit",
8147
+ cwd: serverPkgDir
8148
+ });
8149
+ child.on("exit", (code) => process.exit(code ?? 0));
8150
+ process.on("SIGTERM", () => child.kill("SIGTERM"));
8151
+ process.on("SIGINT", () => child.kill("SIGINT"));
7178
8152
  });
7179
- serverCommand.command("status").description("Check server status").option("--server <url>", "Server URL", "http://127.0.0.1:7433").action(async (options) => {
8153
+ serverCommand.command("status").description("Check server status").option("--server <url>", "Server URL", "http://127.0.0.1:13040").action(async (options) => {
7180
8154
  const serverUrl = options.server;
7181
8155
  try {
7182
8156
  const response = await fetch(`${serverUrl}/health`);
@@ -7223,10 +8197,15 @@ ${pc25.bold("Sessions")}`);
7223
8197
  console.log(pc25.yellow("Server not running. Start with: flint server start"));
7224
8198
  }
7225
8199
  });
7226
- serverCommand.command("stop").description("Stop the Flint server").option("--server <url>", "Server URL", "http://127.0.0.1:7433").action(async (options) => {
8200
+ serverCommand.command("stop").description("Stop the Flint server").option("--server <url>", "Server URL", "http://127.0.0.1:13040").action(async (options) => {
7227
8201
  const serverUrl = options.server;
7228
8202
  try {
7229
- const response = await fetch(`${serverUrl}/shutdown`, { method: "POST" });
8203
+ const response = await fetch(`${serverUrl}/shutdown`, {
8204
+ method: "POST",
8205
+ headers: {
8206
+ [SHUTDOWN_HEADER_NAME]: SHUTDOWN_HEADER_VALUE
8207
+ }
8208
+ });
7230
8209
  if (!response.ok) {
7231
8210
  console.log(pc25.yellow("Server not running."));
7232
8211
  return;
@@ -7236,15 +8215,38 @@ serverCommand.command("stop").description("Stop the Flint server").option("--ser
7236
8215
  console.log(pc25.yellow("Server not running."));
7237
8216
  }
7238
8217
  });
8218
+ serverCommand.command("list").description("List all running Flint servers from the shared registry").action(async () => {
8219
+ const { readAndValidateRegistry, getServerRegistryPath } = await importFlintServer();
8220
+ const servers = await readAndValidateRegistry();
8221
+ console.log(pc25.dim(`Registry: ${getServerRegistryPath()}
8222
+ `));
8223
+ if (servers.length === 0) {
8224
+ console.log(pc25.yellow("No running Flint servers found."));
8225
+ return;
8226
+ }
8227
+ console.log(`${pc25.bold("Running Flint Servers")} (${servers.length})
8228
+ `);
8229
+ for (const server of servers) {
8230
+ console.log(` ${pc25.bold(pc25.blue(server.name))}`);
8231
+ console.log(` URL: ${pc25.cyan(server.url)}`);
8232
+ console.log(` Path: ${pc25.dim(server.flintPath)}`);
8233
+ console.log(` PID: ${server.pid}`);
8234
+ console.log(` Since: ${pc25.dim(server.started)}`);
8235
+ if (server.flintId) {
8236
+ console.log(` ID: ${pc25.dim(server.flintId)}`);
8237
+ }
8238
+ console.log();
8239
+ }
8240
+ });
7239
8241
 
7240
8242
  // src/commands/runtime.ts
7241
8243
  import { Command as Command23 } from "commander";
7242
8244
  import pc26 from "picocolors";
7243
- import path3 from "path";
8245
+ import path4 from "path";
7244
8246
  var runtimeCommand = new Command23("runtime").description("Manage Flint runtimes");
7245
- runtimeCommand.command("start [flintPath]").description("Start runtime for a Flint").option("--server <url>", "Server URL", "http://127.0.0.1:7433").action(async (flintPath, options) => {
8247
+ runtimeCommand.command("start [flintPath]").description("Start runtime for a Flint").option("--server <url>", "Server URL", "http://127.0.0.1:13040").action(async (flintPath, options) => {
7246
8248
  const serverUrl = options.server;
7247
- const resolvedPath = flintPath ? path3.resolve(flintPath) : await findFlintRoot(process.cwd());
8249
+ const resolvedPath = flintPath ? path4.resolve(flintPath) : await findFlintRoot(process.cwd());
7248
8250
  if (!resolvedPath) {
7249
8251
  console.error(pc26.red("Error: Not inside a Flint workspace. Provide a path or cd into one."));
7250
8252
  process.exit(1);
@@ -7271,12 +8273,12 @@ ${pc26.bold("Runtime Started")}`);
7271
8273
  process.exit(1);
7272
8274
  }
7273
8275
  });
7274
- runtimeCommand.command("stop [runtimeId]").description("Stop a running runtime").option("--path <dir>", "Path to Flint").option("--server <url>", "Server URL", "http://127.0.0.1:7433").action(async (runtimeId, options) => {
8276
+ runtimeCommand.command("stop [runtimeId]").description("Stop a running runtime").option("--path <dir>", "Path to Flint").option("--server <url>", "Server URL", "http://127.0.0.1:13040").action(async (runtimeId, options) => {
7275
8277
  const serverUrl = options.server;
7276
8278
  let id = runtimeId;
7277
8279
  try {
7278
8280
  if (!id) {
7279
- const lookupPath = options.path ? path3.resolve(options.path) : await findFlintRoot(process.cwd());
8281
+ const lookupPath = options.path ? path4.resolve(options.path) : await findFlintRoot(process.cwd());
7280
8282
  if (!lookupPath) {
7281
8283
  console.error(pc26.red("Error: Provide a runtime ID or Flint path."));
7282
8284
  process.exit(1);
@@ -7307,7 +8309,7 @@ runtimeCommand.command("stop [runtimeId]").description("Stop a running runtime")
7307
8309
  process.exit(1);
7308
8310
  }
7309
8311
  });
7310
- runtimeCommand.command("list").description("List active runtimes").option("--server <url>", "Server URL", "http://127.0.0.1:7433").action(async (options) => {
8312
+ runtimeCommand.command("list").description("List active runtimes").option("--server <url>", "Server URL", "http://127.0.0.1:13040").action(async (options) => {
7311
8313
  const serverUrl = options.server;
7312
8314
  try {
7313
8315
  const response = await fetch(`${serverUrl}/runtimes`);
@@ -7337,34 +8339,38 @@ ${pc26.bold("Active Runtimes")}
7337
8339
  // src/commands/code.ts
7338
8340
  import { Command as Command24 } from "commander";
7339
8341
  import pc29 from "picocolors";
7340
- import { spawn as spawn4, execSync as execSync3 } from "child_process";
8342
+ import { spawn as spawn5, execSync as execSync3 } from "child_process";
7341
8343
  import { createInterface as createInterface5 } from "readline";
7342
- import { existsSync as existsSync6 } from "fs";
8344
+ import { existsSync as existsSync9, mkdirSync as mkdirSync3, readFileSync as readFileSync7, writeFileSync as writeFileSync2 } from "fs";
7343
8345
  import { randomUUID as randomUUID3 } from "crypto";
7344
8346
  import { join as join13 } from "path";
7345
8347
 
7346
- // src/commands/export-session.ts
7347
- import { writeFile as writeFile3, mkdir as mkdir5, stat as stat4, readFile as readFile6 } from "fs/promises";
7348
- import { join as join11 } from "path";
7349
- import { homedir as homedir6 } from "os";
7350
- import pc27 from "picocolors";
7351
-
7352
8348
  // ../../packages/orbh/dist/index.js
7353
8349
  import { randomUUID } from "crypto";
7354
8350
  import { mkdirSync, readdirSync, readFileSync as readFileSync2, renameSync, writeFileSync } from "fs";
7355
8351
  import { existsSync as existsSync5 } from "fs";
7356
8352
  import { join as join10 } from "path";
7357
8353
  import { randomUUID as randomUUID2 } from "crypto";
7358
- import { closeSync, existsSync as existsSync22, openSync, readSync, statSync, unwatchFile, watch, watchFile } from "fs";
7359
- import { existsSync as existsSync32 } from "fs";
8354
+ import { existsSync as existsSync22, readFileSync as readFileSync22 } from "fs";
8355
+ import { closeSync, existsSync as existsSync32, openSync, readSync, statSync, unwatchFile, watch, watchFile } from "fs";
8356
+ import { existsSync as existsSync42, readFileSync as readFileSync3, unwatchFile as unwatchFile2, watch as watch2, watchFile as watchFile2 } from "fs";
8357
+ import { existsSync as existsSync52 } from "fs";
7360
8358
  import { join as join22 } from "path";
7361
8359
  import { homedir as homedir5 } from "os";
7362
8360
  import { spawnSync as spawnSync3 } from "child_process";
7363
- import { readdirSync as readdirSync2, readFileSync as readFileSync22 } from "fs";
7364
- import { existsSync as existsSync42 } from "fs";
8361
+ import { readdirSync as readdirSync2, readFileSync as readFileSync4 } from "fs";
8362
+ import { existsSync as existsSync6 } from "fs";
7365
8363
  import { join as join32 } from "path";
7366
8364
  import { homedir as homedir22 } from "os";
7367
8365
  import { spawnSync as spawnSync22 } from "child_process";
8366
+ import { existsSync as existsSync7, readdirSync as readdirSync3, readFileSync as readFileSync5, statSync as statSync2 } from "fs";
8367
+ import { spawnSync as spawnSync32 } from "child_process";
8368
+ import { basename as basename4, join as join42 } from "path";
8369
+ import { homedir as homedir32 } from "os";
8370
+ import { existsSync as existsSync8, readdirSync as readdirSync4, readFileSync as readFileSync6, statSync as statSync3 } from "fs";
8371
+ import { spawnSync as spawnSync4 } from "child_process";
8372
+ import { homedir as homedir42 } from "os";
8373
+ import { basename as basename22, join as join52 } from "path";
7368
8374
  var RUN_TRANSITIONS = {
7369
8375
  running: ["completed", "failed", "cancelled", "suspended"],
7370
8376
  completed: [],
@@ -7424,26 +8430,84 @@ function addRequest(session, request) {
7424
8430
  function answerRequest(session, requestId, response) {
7425
8431
  const terminalRunStatuses = ["completed", "failed", "cancelled"];
7426
8432
  const currentRun = getCurrentRun2(session);
7427
- if (!currentRun) {
7428
- return void 0;
7429
- }
7430
- const request = currentRun.requests.find((r) => r.id === requestId);
7431
- if (!request) {
7432
- return void 0;
7433
- }
7434
- if (request.type !== "deferred" && terminalRunStatuses.includes(currentRun.status)) {
7435
- return void 0;
8433
+ for (let i = session.runs.length - 1; i >= 0; i--) {
8434
+ const run = session.runs[i];
8435
+ if (!run) {
8436
+ continue;
8437
+ }
8438
+ const request = run.requests.find((entry) => entry.id === requestId);
8439
+ if (!request) {
8440
+ continue;
8441
+ }
8442
+ if (request.type !== "deferred") {
8443
+ if (run !== currentRun || terminalRunStatuses.includes(run.status)) {
8444
+ return void 0;
8445
+ }
8446
+ }
8447
+ request.response = response ?? null;
8448
+ request.answered = (/* @__PURE__ */ new Date()).toISOString();
8449
+ return request;
7436
8450
  }
7437
- request.response = response ?? null;
7438
- request.answered = (/* @__PURE__ */ new Date()).toISOString();
7439
- return request;
8451
+ return void 0;
7440
8452
  }
7441
8453
  function getPendingRequest(session) {
8454
+ for (let i = session.runs.length - 1; i >= 0; i--) {
8455
+ const run = session.runs[i];
8456
+ if (!run) {
8457
+ continue;
8458
+ }
8459
+ for (let j = run.requests.length - 1; j >= 0; j--) {
8460
+ const request = run.requests[j];
8461
+ if (request && request.answered === null) {
8462
+ return request;
8463
+ }
8464
+ }
8465
+ }
8466
+ return void 0;
8467
+ }
8468
+ var TERMINAL_SESSION_STATUSES = ["finished", "failed", "cancelled"];
8469
+ function isTerminalSessionStatus(status) {
8470
+ return TERMINAL_SESSION_STATUSES.includes(status);
8471
+ }
8472
+ function isProcessAlive(pid) {
8473
+ try {
8474
+ process.kill(pid, 0);
8475
+ return true;
8476
+ } catch {
8477
+ return false;
8478
+ }
8479
+ }
8480
+ function healSession(session) {
8481
+ if (isTerminalSessionStatus(session.status)) return false;
7442
8482
  const currentRun = getCurrentRun2(session);
7443
8483
  if (!currentRun) {
7444
- return void 0;
8484
+ session.status = "failed";
8485
+ return true;
8486
+ }
8487
+ if (currentRun.status !== "running") return false;
8488
+ const alive = currentRun.pid ? isProcessAlive(currentRun.pid) : false;
8489
+ if (alive) return false;
8490
+ const hasResult = currentRun.result !== null;
8491
+ updateCurrentRun2(session, {
8492
+ status: hasResult ? "completed" : "suspended",
8493
+ ended: currentRun.ended ?? (/* @__PURE__ */ new Date()).toISOString()
8494
+ });
8495
+ const pending = getPendingRequest(session);
8496
+ if (pending?.type === "deferred") {
8497
+ session.status = "deferred";
8498
+ } else {
8499
+ session.status = "finished";
7445
8500
  }
7446
- return currentRun.requests.find((r) => r.answered === null);
8501
+ return true;
8502
+ }
8503
+ function isRecord(value) {
8504
+ return typeof value === "object" && value !== null && !Array.isArray(value);
8505
+ }
8506
+ function normalizeSession(session) {
8507
+ return {
8508
+ ...session,
8509
+ metadata: isRecord(session.metadata) ? session.metadata : {}
8510
+ };
7447
8511
  }
7448
8512
  function ensureSessionsDir(sessionsDir) {
7449
8513
  if (!existsSync5(sessionsDir)) {
@@ -7463,6 +8527,7 @@ function createSession2(sessionsDir, runtime2, prompt6, options) {
7463
8527
  prompt: prompt6,
7464
8528
  title: options?.title ?? "",
7465
8529
  description: options?.description ?? "",
8530
+ metadata: options?.metadata ?? {},
7466
8531
  continues: options?.continues ?? null,
7467
8532
  started: timestamp,
7468
8533
  updated: timestamp,
@@ -7478,7 +8543,7 @@ function readSession2(sessionsDir, sessionId) {
7478
8543
  return null;
7479
8544
  }
7480
8545
  try {
7481
- return JSON.parse(readFileSync2(sessionPath, "utf-8"));
8546
+ return normalizeSession(JSON.parse(readFileSync2(sessionPath, "utf-8")));
7482
8547
  } catch {
7483
8548
  return null;
7484
8549
  }
@@ -7486,7 +8551,7 @@ function readSession2(sessionsDir, sessionId) {
7486
8551
  function writeSession(sessionsDir, session) {
7487
8552
  ensureSessionsDir(sessionsDir);
7488
8553
  const nextSession = {
7489
- ...session,
8554
+ ...normalizeSession(session),
7490
8555
  updated: (/* @__PURE__ */ new Date()).toISOString()
7491
8556
  };
7492
8557
  const sessionPath = getSessionPath2(sessionsDir, nextSession.id);
@@ -7501,12 +8566,12 @@ function updateSession2(sessionsDir, sessionId, update) {
7501
8566
  return null;
7502
8567
  }
7503
8568
  const { id: _ignoredId, started: _ignoredStarted, ...safeUpdate } = update;
7504
- const nextSession = {
8569
+ const nextSession = normalizeSession({
7505
8570
  ...session,
7506
8571
  ...safeUpdate,
7507
8572
  id: session.id,
7508
8573
  started: session.started
7509
- };
8574
+ });
7510
8575
  writeSession(sessionsDir, nextSession);
7511
8576
  return nextSession;
7512
8577
  }
@@ -7751,7 +8816,7 @@ function formatSubagent(agentId, agentType, prompt6, transcript, opts, depth) {
7751
8816
  function formatTurnContent(content, opts, depth) {
7752
8817
  switch (content.type) {
7753
8818
  case "text":
7754
- return [content.text, ""];
8819
+ return ["````", content.text, "````", ""];
7755
8820
  case "thinking": {
7756
8821
  if (!opts.includeThinking) return [];
7757
8822
  if (content.encrypted) {
@@ -7831,11 +8896,11 @@ function createClaudeMapperContext(toolIdMap = /* @__PURE__ */ new Map()) {
7831
8896
  activeSubagents: /* @__PURE__ */ new Map()
7832
8897
  };
7833
8898
  }
7834
- function isRecord(value) {
8899
+ function isRecord2(value) {
7835
8900
  return typeof value === "object" && value !== null && !Array.isArray(value);
7836
8901
  }
7837
8902
  function isClaudeContentBlockArray(value) {
7838
- return Array.isArray(value) && value.every((item) => isRecord(item));
8903
+ return Array.isArray(value) && value.every((item) => isRecord2(item));
7839
8904
  }
7840
8905
  function stringifyContent(value) {
7841
8906
  if (typeof value === "string") {
@@ -7844,7 +8909,7 @@ function stringifyContent(value) {
7844
8909
  if (Array.isArray(value)) {
7845
8910
  return value.map((item) => stringifyContent(item)).join("\n");
7846
8911
  }
7847
- if (isRecord(value)) {
8912
+ if (isRecord2(value)) {
7848
8913
  return JSON.stringify(value);
7849
8914
  }
7850
8915
  if (value === null || value === void 0) {
@@ -7856,7 +8921,7 @@ function toTimestamp(entry) {
7856
8921
  return typeof entry.timestamp === "string" ? entry.timestamp : (/* @__PURE__ */ new Date(0)).toISOString();
7857
8922
  }
7858
8923
  function mapUserEntry(entry, context) {
7859
- const message = isRecord(entry.message) ? entry.message : null;
8924
+ const message = isRecord2(entry.message) ? entry.message : null;
7860
8925
  if (!message) {
7861
8926
  return [];
7862
8927
  }
@@ -7917,7 +8982,7 @@ function mapUserEntry(entry, context) {
7917
8982
  return mappedEntries;
7918
8983
  }
7919
8984
  function mapAssistantEntry(entry, context) {
7920
- const message = isRecord(entry.message) ? entry.message : null;
8985
+ const message = isRecord2(entry.message) ? entry.message : null;
7921
8986
  if (!message || !isClaudeContentBlockArray(message.content)) {
7922
8987
  return [];
7923
8988
  }
@@ -7947,12 +9012,12 @@ function mapAssistantEntry(entry, context) {
7947
9012
  type: "tool-call",
7948
9013
  id: block.id,
7949
9014
  tool: block.name,
7950
- input: isRecord(block.input) ? block.input : {},
9015
+ input: isRecord2(block.input) ? block.input : {},
7951
9016
  timestamp
7952
9017
  });
7953
9018
  }
7954
9019
  }
7955
- const usage = isRecord(message.usage) ? message.usage : null;
9020
+ const usage = isRecord2(message.usage) ? message.usage : null;
7956
9021
  if (usage) {
7957
9022
  const usageEntry = {
7958
9023
  type: "usage",
@@ -7968,7 +9033,7 @@ function mapAssistantEntry(entry, context) {
7968
9033
  return mappedEntries;
7969
9034
  }
7970
9035
  function mapAgentProgressEntry(entry, context) {
7971
- const data = isRecord(entry.data) ? entry.data : null;
9036
+ const data = isRecord2(entry.data) ? entry.data : null;
7972
9037
  if (!data || typeof data.agentId !== "string") {
7973
9038
  return [];
7974
9039
  }
@@ -7977,7 +9042,7 @@ function mapAgentProgressEntry(entry, context) {
7977
9042
  const parentToolCallId = typeof entry.parentToolUseID === "string" ? entry.parentToolUseID : "";
7978
9043
  const prompt6 = typeof data.prompt === "string" ? data.prompt : void 0;
7979
9044
  const agentType = typeof data.agentType === "string" ? data.agentType : void 0;
7980
- const nestedMessage = isRecord(data.message) ? data.message : null;
9045
+ const nestedMessage = isRecord2(data.message) ? data.message : null;
7981
9046
  const mappedEntries = [];
7982
9047
  if (!context.activeSubagents.has(agentId)) {
7983
9048
  context.activeSubagents.set(agentId, {
@@ -8010,7 +9075,7 @@ function mapAgentProgressEntry(entry, context) {
8010
9075
  return mappedEntries;
8011
9076
  }
8012
9077
  function mapProgressEntry(entry, context) {
8013
- const data = isRecord(entry.data) ? entry.data : null;
9078
+ const data = isRecord2(entry.data) ? entry.data : null;
8014
9079
  if (!data || typeof data.type !== "string") {
8015
9080
  return [];
8016
9081
  }
@@ -8057,7 +9122,7 @@ function buildClaudeToolIdMap(entries) {
8057
9122
  if (entry.type !== "assistant") {
8058
9123
  continue;
8059
9124
  }
8060
- const message = isRecord(entry.message) ? entry.message : null;
9125
+ const message = isRecord2(entry.message) ? entry.message : null;
8061
9126
  if (!message || !isClaudeContentBlockArray(message.content)) {
8062
9127
  continue;
8063
9128
  }
@@ -8100,17 +9165,17 @@ function createCodexMapperContext(toolIdMap = /* @__PURE__ */ new Map()) {
8100
9165
  activeSubagents: /* @__PURE__ */ new Map()
8101
9166
  };
8102
9167
  }
8103
- function isRecord2(value) {
9168
+ function isRecord3(value) {
8104
9169
  return typeof value === "object" && value !== null && !Array.isArray(value);
8105
9170
  }
8106
- function stringifyValue(value) {
9171
+ function stringifyValue2(value) {
8107
9172
  if (typeof value === "string") {
8108
9173
  return value;
8109
9174
  }
8110
9175
  if (Array.isArray(value)) {
8111
- return value.map((item) => stringifyValue(item)).join("\n");
9176
+ return value.map((item) => stringifyValue2(item)).join("\n");
8112
9177
  }
8113
- if (isRecord2(value)) {
9178
+ if (isRecord3(value)) {
8114
9179
  return JSON.stringify(value);
8115
9180
  }
8116
9181
  if (value === null || value === void 0) {
@@ -8119,13 +9184,13 @@ function stringifyValue(value) {
8119
9184
  return String(value);
8120
9185
  }
8121
9186
  function parseObjectInput(value) {
8122
- if (isRecord2(value)) {
9187
+ if (isRecord3(value)) {
8123
9188
  return value;
8124
9189
  }
8125
9190
  if (typeof value === "string") {
8126
9191
  try {
8127
9192
  const parsed = JSON.parse(value);
8128
- return isRecord2(parsed) ? parsed : {};
9193
+ return isRecord3(parsed) ? parsed : {};
8129
9194
  } catch {
8130
9195
  return {};
8131
9196
  }
@@ -8137,7 +9202,7 @@ function extractTextContent(content) {
8137
9202
  return "";
8138
9203
  }
8139
9204
  return content.map((block) => {
8140
- if (!isRecord2(block)) {
9205
+ if (!isRecord3(block)) {
8141
9206
  return "";
8142
9207
  }
8143
9208
  const text = block.text;
@@ -8149,7 +9214,7 @@ function extractReasoningSummary(summary) {
8149
9214
  return "";
8150
9215
  }
8151
9216
  return summary.map((item) => {
8152
- if (!isRecord2(item)) {
9217
+ if (!isRecord3(item)) {
8153
9218
  return "";
8154
9219
  }
8155
9220
  const text = item.text;
@@ -8157,14 +9222,14 @@ function extractReasoningSummary(summary) {
8157
9222
  }).filter((text) => text.length > 0).join("\n");
8158
9223
  }
8159
9224
  function inferToolResultError(output) {
8160
- if (isRecord2(output)) {
8161
- const metadata = isRecord2(output.metadata) ? output.metadata : null;
9225
+ if (isRecord3(output)) {
9226
+ const metadata = isRecord3(output.metadata) ? output.metadata : null;
8162
9227
  return metadata?.exit_code !== void 0 && typeof metadata.exit_code === "number" && metadata.exit_code !== 0;
8163
9228
  }
8164
9229
  if (typeof output === "string") {
8165
9230
  try {
8166
9231
  const parsed = JSON.parse(output);
8167
- if (isRecord2(parsed)) {
9232
+ if (isRecord3(parsed)) {
8168
9233
  return inferToolResultError(parsed);
8169
9234
  }
8170
9235
  } catch {
@@ -8222,14 +9287,14 @@ function mapFunctionCallOutputPayload(payload, timestamp, context) {
8222
9287
  type: "tool-result",
8223
9288
  id: payload.call_id,
8224
9289
  tool: context.toolIdMap.get(payload.call_id) ?? "unknown",
8225
- output: stringifyValue(output),
9290
+ output: stringifyValue2(output),
8226
9291
  error: inferToolResultError(output),
8227
9292
  timestamp
8228
9293
  }
8229
9294
  ];
8230
9295
  }
8231
9296
  function mapWebSearchCallPayload(payload, timestamp) {
8232
- const action = isRecord2(payload.action) ? payload.action : null;
9297
+ const action = isRecord3(payload.action) ? payload.action : null;
8233
9298
  const query = typeof action?.query === "string" ? action.query : "web_search";
8234
9299
  return [
8235
9300
  {
@@ -8253,8 +9318,8 @@ function getSubagentId(payload) {
8253
9318
  }
8254
9319
  }
8255
9320
  const nestedIds = [
8256
- isRecord2(payload.new_thread_id) ? payload.new_thread_id.id : void 0,
8257
- isRecord2(payload.receiver_thread_id) ? payload.receiver_thread_id.id : void 0
9321
+ isRecord3(payload.new_thread_id) ? payload.new_thread_id.id : void 0,
9322
+ isRecord3(payload.receiver_thread_id) ? payload.receiver_thread_id.id : void 0
8258
9323
  ];
8259
9324
  for (const nestedId of nestedIds) {
8260
9325
  if (typeof nestedId === "string" && nestedId.length > 0) {
@@ -8266,8 +9331,8 @@ function getSubagentId(payload) {
8266
9331
  function mapEventPayload(payload, timestamp, context) {
8267
9332
  switch (payload.type) {
8268
9333
  case "token_count": {
8269
- const info = isRecord2(payload.info) ? payload.info : null;
8270
- const usage = isRecord2(info?.total_token_usage) ? info?.total_token_usage : isRecord2(info?.last_token_usage) ? info?.last_token_usage : null;
9334
+ const info = isRecord3(payload.info) ? payload.info : null;
9335
+ const usage = isRecord3(info?.total_token_usage) ? info?.total_token_usage : isRecord3(info?.last_token_usage) ? info?.last_token_usage : null;
8271
9336
  if (!usage) {
8272
9337
  return [];
8273
9338
  }
@@ -8309,7 +9374,7 @@ function mapEventPayload(payload, timestamp, context) {
8309
9374
  if (!agentId) {
8310
9375
  return [];
8311
9376
  }
8312
- const nestedText = typeof payload.prompt === "string" && payload.prompt.length > 0 ? payload.prompt : stringifyValue(payload.status);
9377
+ const nestedText = typeof payload.prompt === "string" && payload.prompt.length > 0 ? payload.prompt : stringifyValue2(payload.status);
8313
9378
  return [
8314
9379
  {
8315
9380
  type: "subagent-entry",
@@ -8367,7 +9432,7 @@ function buildCodexToolIdMap(entries) {
8367
9432
  if (entry.type !== "response_item") {
8368
9433
  continue;
8369
9434
  }
8370
- const payload = isRecord2(entry.payload) ? entry.payload : null;
9435
+ const payload = isRecord3(entry.payload) ? entry.payload : null;
8371
9436
  if (!payload) {
8372
9437
  continue;
8373
9438
  }
@@ -8380,7 +9445,7 @@ function buildCodexToolIdMap(entries) {
8380
9445
  function mapCodexEntry(entry, context) {
8381
9446
  const timestamp = typeof entry.timestamp === "string" ? entry.timestamp : (/* @__PURE__ */ new Date(0)).toISOString();
8382
9447
  if (entry.type === "turn_context") {
8383
- const payload2 = isRecord2(entry.payload) ? entry.payload : null;
9448
+ const payload2 = isRecord3(entry.payload) ? entry.payload : null;
8384
9449
  context.currentModel = typeof payload2?.model === "string" ? payload2.model : context.currentModel;
8385
9450
  return [];
8386
9451
  }
@@ -8388,7 +9453,7 @@ function mapCodexEntry(entry, context) {
8388
9453
  return [];
8389
9454
  }
8390
9455
  if (entry.type === "compacted") {
8391
- const payload2 = isRecord2(entry.payload) ? entry.payload : null;
9456
+ const payload2 = isRecord3(entry.payload) ? entry.payload : null;
8392
9457
  return [
8393
9458
  {
8394
9459
  type: "compaction",
@@ -8397,7 +9462,7 @@ function mapCodexEntry(entry, context) {
8397
9462
  }
8398
9463
  ];
8399
9464
  }
8400
- const payload = isRecord2(entry.payload) ? entry.payload : null;
9465
+ const payload = isRecord3(entry.payload) ? entry.payload : null;
8401
9466
  if (!payload || typeof payload.type !== "string") {
8402
9467
  return [];
8403
9468
  }
@@ -8437,129 +9502,750 @@ function parseCodexTranscript(content) {
8437
9502
  const context = createCodexMapperContext(buildCodexToolIdMap(rawEntries));
8438
9503
  return rawEntries.flatMap((entry) => mapCodexEntry(entry, context));
8439
9504
  }
8440
- var JsonlTranscriptWatcher = class {
8441
- constructor(transcriptPath, mapper, options) {
8442
- this.transcriptPath = transcriptPath;
8443
- this.mapper = mapper;
8444
- this.mapperState = mapper.createState();
8445
- this.options = {
8446
- debounceMs: options?.debounceMs ?? 100,
8447
- pollIntervalMs: options?.pollIntervalMs ?? 500
8448
- };
9505
+ function createDroidMapperContext(options) {
9506
+ return {
9507
+ toolIdMap: options?.toolIdMap ?? /* @__PURE__ */ new Map(),
9508
+ transcriptPath: options?.transcriptPath
9509
+ };
9510
+ }
9511
+ function isRecord4(value) {
9512
+ return typeof value === "object" && value !== null && !Array.isArray(value);
9513
+ }
9514
+ function isDroidContentBlockArray(value) {
9515
+ return Array.isArray(value) && value.every((item) => isRecord4(item));
9516
+ }
9517
+ function stringifyContent2(value) {
9518
+ if (typeof value === "string") {
9519
+ return value;
8449
9520
  }
8450
- handlers = /* @__PURE__ */ new Set();
8451
- entries = [];
8452
- mapperState;
8453
- options;
8454
- byteOffset = 0;
8455
- buffer = "";
8456
- watcher = null;
8457
- debounceTimer = null;
8458
- started = false;
8459
- usingPolling = false;
8460
- onEntries(handler) {
8461
- this.handlers.add(handler);
9521
+ if (Array.isArray(value)) {
9522
+ return value.map((item) => stringifyContent2(item)).join("\n");
8462
9523
  }
8463
- start() {
8464
- if (this.started) {
8465
- return;
8466
- }
8467
- this.started = true;
8468
- if (existsSync22(this.transcriptPath)) {
8469
- this.readNewContent();
8470
- }
8471
- this.installWatcher();
9524
+ if (isRecord4(value)) {
9525
+ return JSON.stringify(value);
8472
9526
  }
8473
- stop() {
8474
- this.started = false;
8475
- if (this.debounceTimer) {
8476
- clearTimeout(this.debounceTimer);
8477
- this.debounceTimer = null;
9527
+ if (value === null || value === void 0) {
9528
+ return "";
9529
+ }
9530
+ return String(value);
9531
+ }
9532
+ function toTimestamp2(entry) {
9533
+ return typeof entry.timestamp === "string" ? entry.timestamp : (/* @__PURE__ */ new Date(0)).toISOString();
9534
+ }
9535
+ function buildDroidToolIdMap(entries) {
9536
+ const toolIdMap = /* @__PURE__ */ new Map();
9537
+ for (const entry of entries) {
9538
+ if (entry.type !== "message") {
9539
+ continue;
8478
9540
  }
8479
- if (this.watcher) {
8480
- this.watcher.close();
8481
- this.watcher = null;
9541
+ const message = isRecord4(entry.message) ? entry.message : null;
9542
+ if (message?.role !== "assistant" || !isDroidContentBlockArray(message.content)) {
9543
+ continue;
8482
9544
  }
8483
- if (this.usingPolling) {
8484
- unwatchFile(this.transcriptPath);
8485
- this.usingPolling = false;
9545
+ for (const block of message.content) {
9546
+ if (block.type === "tool_use" && typeof block.id === "string" && typeof block.name === "string") {
9547
+ toolIdMap.set(block.id, block.name);
9548
+ }
8486
9549
  }
8487
9550
  }
8488
- getEntries() {
8489
- return [...this.entries];
9551
+ return toolIdMap;
9552
+ }
9553
+ function resolveUsageSettingsPath(transcriptPath) {
9554
+ if (!transcriptPath || !transcriptPath.endsWith(".jsonl")) {
9555
+ return null;
8490
9556
  }
8491
- installWatcher() {
8492
- try {
8493
- this.watcher = watch(this.transcriptPath, { persistent: false }, () => this.scheduleRead());
8494
- this.watcher.on("error", () => this.installPollingWatcher());
8495
- } catch {
8496
- this.installPollingWatcher();
8497
- }
9557
+ return transcriptPath.slice(0, -".jsonl".length) + ".settings.json";
9558
+ }
9559
+ function readUsageSnapshot(transcriptPath) {
9560
+ const settingsPath = resolveUsageSettingsPath(transcriptPath);
9561
+ if (!settingsPath || !existsSync22(settingsPath)) {
9562
+ return null;
8498
9563
  }
8499
- installPollingWatcher() {
8500
- if (this.usingPolling) {
8501
- return;
9564
+ try {
9565
+ const parsed = JSON.parse(readFileSync22(settingsPath, "utf-8"));
9566
+ if (!isRecord4(parsed)) {
9567
+ return null;
8502
9568
  }
8503
- this.usingPolling = true;
8504
- watchFile(this.transcriptPath, { interval: this.options.pollIntervalMs, persistent: false }, () => {
8505
- this.scheduleRead();
8506
- });
8507
- }
8508
- scheduleRead() {
8509
- if (!this.started) {
8510
- return;
9569
+ const tokenUsage = isRecord4(parsed.tokenUsage) ? parsed.tokenUsage : null;
9570
+ if (!tokenUsage) {
9571
+ return null;
8511
9572
  }
8512
- if (this.debounceTimer) {
8513
- clearTimeout(this.debounceTimer);
9573
+ return {
9574
+ inputTokens: typeof tokenUsage.inputTokens === "number" ? tokenUsage.inputTokens : 0,
9575
+ outputTokens: typeof tokenUsage.outputTokens === "number" ? tokenUsage.outputTokens : 0,
9576
+ cacheCreationTokens: typeof tokenUsage.cacheCreationTokens === "number" ? tokenUsage.cacheCreationTokens : 0,
9577
+ cacheReadTokens: typeof tokenUsage.cacheReadTokens === "number" ? tokenUsage.cacheReadTokens : 0,
9578
+ thinkingTokens: typeof tokenUsage.thinkingTokens === "number" ? tokenUsage.thinkingTokens : 0,
9579
+ model: typeof parsed.model === "string" ? parsed.model : void 0
9580
+ };
9581
+ } catch {
9582
+ return null;
9583
+ }
9584
+ }
9585
+ function diffUsageSnapshot(current, previous) {
9586
+ const inputTokens = Math.max(0, current.inputTokens - (previous?.inputTokens ?? 0));
9587
+ const outputTokens = Math.max(0, current.outputTokens - (previous?.outputTokens ?? 0));
9588
+ const cacheCreationTokens = Math.max(0, current.cacheCreationTokens - (previous?.cacheCreationTokens ?? 0));
9589
+ const cacheReadTokens = Math.max(0, current.cacheReadTokens - (previous?.cacheReadTokens ?? 0));
9590
+ const reasoningTokens = Math.max(0, current.thinkingTokens - (previous?.thinkingTokens ?? 0));
9591
+ if (inputTokens === 0 && outputTokens === 0 && cacheCreationTokens === 0 && cacheReadTokens === 0 && reasoningTokens === 0) {
9592
+ return null;
9593
+ }
9594
+ return {
9595
+ inputTokens,
9596
+ outputTokens,
9597
+ cacheCreationTokens: cacheCreationTokens || void 0,
9598
+ cacheReadTokens: cacheReadTokens || void 0,
9599
+ reasoningTokens: reasoningTokens || void 0
9600
+ };
9601
+ }
9602
+ function maybeEmitUsage(context, timestamp) {
9603
+ const snapshot = readUsageSnapshot(context.transcriptPath);
9604
+ if (!snapshot) {
9605
+ return [];
9606
+ }
9607
+ const usageDelta = diffUsageSnapshot(snapshot, context.lastUsageSnapshot);
9608
+ context.lastUsageSnapshot = snapshot;
9609
+ if (!usageDelta) {
9610
+ return [];
9611
+ }
9612
+ return [
9613
+ {
9614
+ type: "usage",
9615
+ model: snapshot.model,
9616
+ timestamp,
9617
+ ...usageDelta
8514
9618
  }
8515
- this.debounceTimer = setTimeout(() => {
8516
- this.readNewContent();
8517
- }, this.options.debounceMs);
9619
+ ];
9620
+ }
9621
+ function mapDroidUserMessage(entry, context) {
9622
+ const message = isRecord4(entry.message) ? entry.message : null;
9623
+ if (!message) {
9624
+ return [];
8518
9625
  }
8519
- readNewContent() {
8520
- if (!this.started || !existsSync22(this.transcriptPath)) {
8521
- return;
9626
+ const content = message.content;
9627
+ const timestamp = toTimestamp2(entry);
9628
+ if (typeof content === "string") {
9629
+ return [
9630
+ {
9631
+ type: "message",
9632
+ role: "human",
9633
+ text: content,
9634
+ timestamp
9635
+ },
9636
+ ...maybeEmitUsage(context, timestamp)
9637
+ ];
9638
+ }
9639
+ if (!isDroidContentBlockArray(content)) {
9640
+ return maybeEmitUsage(context, timestamp);
9641
+ }
9642
+ const mappedEntries = [];
9643
+ for (const block of content) {
9644
+ if (block.type === "text" && typeof block.text === "string") {
9645
+ mappedEntries.push({
9646
+ type: "message",
9647
+ role: "human",
9648
+ text: block.text,
9649
+ timestamp
9650
+ });
9651
+ continue;
8522
9652
  }
8523
- let fileSize = 0;
8524
- try {
8525
- fileSize = statSync(this.transcriptPath).size;
8526
- } catch {
8527
- return;
9653
+ if (block.type === "tool_result" && typeof block.tool_use_id === "string") {
9654
+ const toolId = block.tool_use_id;
9655
+ mappedEntries.push({
9656
+ type: "tool-result",
9657
+ id: toolId,
9658
+ tool: context.toolIdMap.get(toolId) ?? "unknown",
9659
+ output: stringifyContent2(block.content),
9660
+ error: block.is_error === true,
9661
+ timestamp
9662
+ });
8528
9663
  }
8529
- if (fileSize < this.byteOffset) {
8530
- this.byteOffset = 0;
8531
- this.buffer = "";
9664
+ }
9665
+ mappedEntries.push(...maybeEmitUsage(context, timestamp));
9666
+ return mappedEntries;
9667
+ }
9668
+ function mapDroidAssistantMessage(entry, context) {
9669
+ const message = isRecord4(entry.message) ? entry.message : null;
9670
+ if (!message || !isDroidContentBlockArray(message.content)) {
9671
+ return maybeEmitUsage(context, toTimestamp2(entry));
9672
+ }
9673
+ const mappedEntries = [];
9674
+ const timestamp = toTimestamp2(entry);
9675
+ for (const block of message.content) {
9676
+ if (block.type === "text" && typeof block.text === "string") {
9677
+ mappedEntries.push({
9678
+ type: "message",
9679
+ role: "agent",
9680
+ text: block.text,
9681
+ timestamp
9682
+ });
9683
+ continue;
8532
9684
  }
8533
- if (fileSize === this.byteOffset) {
8534
- return;
9685
+ if (block.type === "tool_use" && typeof block.id === "string" && typeof block.name === "string") {
9686
+ context.toolIdMap.set(block.id, block.name);
9687
+ mappedEntries.push({
9688
+ type: "tool-call",
9689
+ id: block.id,
9690
+ tool: block.name,
9691
+ input: isRecord4(block.input) ? block.input : {},
9692
+ timestamp
9693
+ });
8535
9694
  }
8536
- const bytesToRead = fileSize - this.byteOffset;
8537
- const buffer = Buffer.alloc(bytesToRead);
8538
- const fileDescriptor = openSync(this.transcriptPath, "r");
9695
+ }
9696
+ mappedEntries.push(...maybeEmitUsage(context, timestamp));
9697
+ return mappedEntries;
9698
+ }
9699
+ function mapDroidMessageEntry(entry, context) {
9700
+ const message = isRecord4(entry.message) ? entry.message : null;
9701
+ const role = typeof message?.role === "string" ? message.role : null;
9702
+ if (role === "assistant") {
9703
+ return mapDroidAssistantMessage(entry, context);
9704
+ }
9705
+ if (role === "user" || role === "developer") {
9706
+ return mapDroidUserMessage(entry, context);
9707
+ }
9708
+ return maybeEmitUsage(context, toTimestamp2(entry));
9709
+ }
9710
+ function mapSessionStart(entry, context) {
9711
+ context.session = {
9712
+ sessionId: typeof entry.id === "string" ? entry.id : void 0,
9713
+ title: typeof entry.title === "string" ? entry.title : void 0,
9714
+ sessionTitle: typeof entry.sessionTitle === "string" ? entry.sessionTitle : void 0,
9715
+ owner: typeof entry.owner === "string" ? entry.owner : void 0,
9716
+ cwd: typeof entry.cwd === "string" ? entry.cwd : void 0,
9717
+ version: typeof entry.version === "number" ? entry.version : void 0
9718
+ };
9719
+ return maybeEmitUsage(context, toTimestamp2(entry));
9720
+ }
9721
+ function mapCompactionState(entry, context) {
9722
+ const timestamp = toTimestamp2(entry);
9723
+ const anchorMessage = isRecord4(entry.anchorMessage) ? entry.anchorMessage : null;
9724
+ const compactionEntry = {
9725
+ type: "compaction",
9726
+ timestamp,
9727
+ summary: typeof entry.summaryText === "string" ? entry.summaryText : void 0,
9728
+ summaryTokens: typeof entry.summaryTokens === "number" ? entry.summaryTokens : void 0,
9729
+ summaryKind: typeof entry.summaryKind === "string" ? entry.summaryKind : void 0,
9730
+ anchorMessageId: typeof anchorMessage?.id === "string" ? anchorMessage.id : void 0,
9731
+ removedCount: typeof entry.removedCount === "number" ? entry.removedCount : void 0
9732
+ };
9733
+ return [compactionEntry, ...maybeEmitUsage(context, timestamp)];
9734
+ }
9735
+ function mapDroidEntry(entry, context) {
9736
+ switch (entry.type) {
9737
+ case "session_start":
9738
+ return mapSessionStart(entry, context);
9739
+ case "message":
9740
+ return mapDroidMessageEntry(entry, context);
9741
+ case "compaction_state":
9742
+ return mapCompactionState(entry, context);
9743
+ case "todo_state":
9744
+ return [];
9745
+ default:
9746
+ return [];
9747
+ }
9748
+ }
9749
+ function parseDroidTranscript(content, options) {
9750
+ const rawEntries = content.split("\n").map((line) => line.trim()).filter((line) => line.length > 0).map((line) => {
8539
9751
  try {
8540
- readSync(fileDescriptor, buffer, 0, bytesToRead, this.byteOffset);
8541
- } finally {
8542
- closeSync(fileDescriptor);
9752
+ return JSON.parse(line);
9753
+ } catch {
9754
+ return null;
8543
9755
  }
8544
- this.byteOffset = fileSize;
8545
- const pendingText = `${this.buffer}${buffer.toString("utf-8")}`;
8546
- const lines = pendingText.split("\n");
8547
- this.buffer = lines.pop() ?? "";
8548
- const newEntries = [];
8549
- for (const line of lines) {
8550
- const trimmed = line.trim();
8551
- if (trimmed.length === 0) {
9756
+ }).filter((entry) => entry !== null);
9757
+ const context = createDroidMapperContext({
9758
+ toolIdMap: buildDroidToolIdMap(rawEntries),
9759
+ transcriptPath: options?.transcriptPath
9760
+ });
9761
+ return rawEntries.flatMap((entry) => mapDroidEntry(entry, context));
9762
+ }
9763
+ function createGeminiMapperContext(toolIdMap = /* @__PURE__ */ new Map()) {
9764
+ return { toolIdMap };
9765
+ }
9766
+ function isRecord5(value) {
9767
+ return typeof value === "object" && value !== null && !Array.isArray(value);
9768
+ }
9769
+ function stringifyValue22(value) {
9770
+ if (typeof value === "string") {
9771
+ return value;
9772
+ }
9773
+ if (Array.isArray(value)) {
9774
+ return value.map((item) => stringifyValue22(item)).filter((item) => item.length > 0).join("\n");
9775
+ }
9776
+ if (isRecord5(value)) {
9777
+ return JSON.stringify(value);
9778
+ }
9779
+ if (value === null || value === void 0) {
9780
+ return "";
9781
+ }
9782
+ return String(value);
9783
+ }
9784
+ function normalizeTimestamp(value) {
9785
+ return typeof value === "string" ? value : (/* @__PURE__ */ new Date(0)).toISOString();
9786
+ }
9787
+ function extractUserText(content) {
9788
+ if (typeof content === "string") {
9789
+ return content;
9790
+ }
9791
+ if (!Array.isArray(content)) {
9792
+ return "";
9793
+ }
9794
+ return content.map((item) => {
9795
+ if (!isRecord5(item)) {
9796
+ return "";
9797
+ }
9798
+ if (typeof item.text === "string") {
9799
+ return item.text;
9800
+ }
9801
+ return stringifyValue22(item);
9802
+ }).filter((item) => item.length > 0).join("\n");
9803
+ }
9804
+ function mapUserMessage(message) {
9805
+ const text = extractUserText(message.content);
9806
+ if (text.length === 0) {
9807
+ return [];
9808
+ }
9809
+ return [
9810
+ {
9811
+ type: "message",
9812
+ role: "human",
9813
+ text,
9814
+ timestamp: normalizeTimestamp(message.timestamp)
9815
+ }
9816
+ ];
9817
+ }
9818
+ function mapGeminiThoughts(message) {
9819
+ if (!Array.isArray(message.thoughts)) {
9820
+ return [];
9821
+ }
9822
+ const entries = [];
9823
+ for (const thought of message.thoughts) {
9824
+ if (!isRecord5(thought)) {
9825
+ continue;
9826
+ }
9827
+ const parts = [
9828
+ typeof thought.subject === "string" && thought.subject.length > 0 ? thought.subject : "",
9829
+ typeof thought.description === "string" ? thought.description : ""
9830
+ ].filter((part) => part.length > 0);
9831
+ if (parts.length === 0) {
9832
+ continue;
9833
+ }
9834
+ entries.push({
9835
+ type: "thinking",
9836
+ text: parts.join("\n\n"),
9837
+ timestamp: normalizeTimestamp(thought.timestamp ?? message.timestamp)
9838
+ });
9839
+ }
9840
+ return entries;
9841
+ }
9842
+ function mapGeminiToolCalls(message, context) {
9843
+ if (!Array.isArray(message.toolCalls)) {
9844
+ return [];
9845
+ }
9846
+ const entries = [];
9847
+ for (const toolCall of message.toolCalls) {
9848
+ if (!isRecord5(toolCall) || typeof toolCall.id !== "string") {
9849
+ continue;
9850
+ }
9851
+ const toolName = typeof toolCall.name === "string" ? toolCall.name : "unknown";
9852
+ const timestamp = normalizeTimestamp(toolCall.timestamp ?? message.timestamp);
9853
+ context.toolIdMap.set(toolCall.id, toolName);
9854
+ entries.push({
9855
+ type: "tool-call",
9856
+ id: toolCall.id,
9857
+ tool: toolName,
9858
+ input: isRecord5(toolCall.args) ? toolCall.args : {},
9859
+ timestamp
9860
+ });
9861
+ if (!Array.isArray(toolCall.result)) {
9862
+ continue;
9863
+ }
9864
+ for (const result of toolCall.result) {
9865
+ if (!isRecord5(result)) {
9866
+ continue;
9867
+ }
9868
+ const functionResponse = isRecord5(result.functionResponse) ? result.functionResponse : null;
9869
+ const response = isRecord5(functionResponse?.response) ? functionResponse?.response : null;
9870
+ if (!response) {
9871
+ continue;
9872
+ }
9873
+ const output = typeof response.output === "string" ? response.output : typeof response.error === "string" ? response.error : stringifyValue22(response);
9874
+ entries.push({
9875
+ type: "tool-result",
9876
+ id: typeof functionResponse?.id === "string" ? functionResponse.id : toolCall.id,
9877
+ tool: typeof functionResponse?.name === "string" ? functionResponse.name : context.toolIdMap.get(toolCall.id) ?? toolName,
9878
+ output,
9879
+ error: toolCall.status === "error" || typeof response.error === "string",
9880
+ timestamp
9881
+ });
9882
+ }
9883
+ }
9884
+ return entries;
9885
+ }
9886
+ function mapGeminiUsage(message) {
9887
+ const tokens = isRecord5(message.tokens) ? message.tokens : null;
9888
+ if (!tokens) {
9889
+ return [];
9890
+ }
9891
+ const entry = {
9892
+ type: "usage",
9893
+ inputTokens: typeof tokens.input === "number" ? tokens.input : 0,
9894
+ outputTokens: typeof tokens.output === "number" ? tokens.output : 0,
9895
+ cacheReadTokens: typeof tokens.cached === "number" ? tokens.cached : void 0,
9896
+ reasoningTokens: typeof tokens.thoughts === "number" ? tokens.thoughts : void 0,
9897
+ model: typeof message.model === "string" ? message.model : void 0,
9898
+ timestamp: normalizeTimestamp(message.timestamp)
9899
+ };
9900
+ return [entry];
9901
+ }
9902
+ function mapGeminiMessage(message, context) {
9903
+ const timestamp = normalizeTimestamp(message.timestamp);
9904
+ const entries = [];
9905
+ entries.push(...mapGeminiThoughts(message));
9906
+ if (typeof message.content === "string" && message.content.length > 0) {
9907
+ entries.push({
9908
+ type: "message",
9909
+ role: "agent",
9910
+ text: message.content,
9911
+ timestamp
9912
+ });
9913
+ }
9914
+ entries.push(...mapGeminiToolCalls(message, context));
9915
+ entries.push(...mapGeminiUsage(message));
9916
+ return entries;
9917
+ }
9918
+ function mapInfoMessage(message) {
9919
+ if (typeof message.content !== "string" || message.content.length === 0) {
9920
+ return [];
9921
+ }
9922
+ return [
9923
+ {
9924
+ type: "message",
9925
+ role: "agent",
9926
+ text: message.content,
9927
+ timestamp: normalizeTimestamp(message.timestamp),
9928
+ isMeta: true
9929
+ }
9930
+ ];
9931
+ }
9932
+ function mapGeminiMessageEntry(message, context) {
9933
+ switch (message.type) {
9934
+ case "user":
9935
+ return mapUserMessage(message);
9936
+ case "gemini":
9937
+ return mapGeminiMessage(message, context);
9938
+ case "info":
9939
+ return mapInfoMessage(message);
9940
+ default:
9941
+ return [];
9942
+ }
9943
+ }
9944
+ function buildGeminiToolIdMap(messages) {
9945
+ const toolIdMap = /* @__PURE__ */ new Map();
9946
+ for (const message of messages) {
9947
+ if (message.type !== "gemini" || !Array.isArray(message.toolCalls)) {
9948
+ continue;
9949
+ }
9950
+ for (const toolCall of message.toolCalls) {
9951
+ if (!isRecord5(toolCall) || typeof toolCall.id !== "string" || typeof toolCall.name !== "string") {
9952
+ continue;
9953
+ }
9954
+ toolIdMap.set(toolCall.id, toolCall.name);
9955
+ }
9956
+ }
9957
+ return toolIdMap;
9958
+ }
9959
+ function parseGeminiTranscript(content) {
9960
+ let parsed;
9961
+ try {
9962
+ parsed = JSON.parse(content);
9963
+ } catch {
9964
+ return [];
9965
+ }
9966
+ const messages = Array.isArray(parsed.messages) ? parsed.messages.filter((message) => isRecord5(message)) : [];
9967
+ const context = createGeminiMapperContext(buildGeminiToolIdMap(messages));
9968
+ return messages.flatMap((message) => mapGeminiMessageEntry(message, context));
9969
+ }
9970
+ var JsonlTranscriptWatcher = class {
9971
+ constructor(transcriptPath, mapper, options) {
9972
+ this.transcriptPath = transcriptPath;
9973
+ this.mapper = mapper;
9974
+ this.mapperState = mapper.createState();
9975
+ this.options = {
9976
+ debounceMs: options?.debounceMs ?? 100,
9977
+ pollIntervalMs: options?.pollIntervalMs ?? 500
9978
+ };
9979
+ }
9980
+ handlers = /* @__PURE__ */ new Set();
9981
+ errorHandlers = /* @__PURE__ */ new Set();
9982
+ entries = [];
9983
+ mapperState;
9984
+ options;
9985
+ byteOffset = 0;
9986
+ buffer = "";
9987
+ watcher = null;
9988
+ debounceTimer = null;
9989
+ started = false;
9990
+ usingPolling = false;
9991
+ onEntries(handler) {
9992
+ this.handlers.add(handler);
9993
+ }
9994
+ onError(handler) {
9995
+ this.errorHandlers.add(handler);
9996
+ }
9997
+ start() {
9998
+ if (this.started) {
9999
+ return;
10000
+ }
10001
+ this.started = true;
10002
+ if (existsSync32(this.transcriptPath)) {
10003
+ this.readNewContent();
10004
+ }
10005
+ this.installWatcher();
10006
+ }
10007
+ stop() {
10008
+ this.started = false;
10009
+ if (this.debounceTimer) {
10010
+ clearTimeout(this.debounceTimer);
10011
+ this.debounceTimer = null;
10012
+ }
10013
+ if (this.watcher) {
10014
+ this.watcher.close();
10015
+ this.watcher = null;
10016
+ }
10017
+ if (this.usingPolling) {
10018
+ unwatchFile(this.transcriptPath);
10019
+ this.usingPolling = false;
10020
+ }
10021
+ }
10022
+ getEntries() {
10023
+ return [...this.entries];
10024
+ }
10025
+ installWatcher() {
10026
+ try {
10027
+ this.watcher = watch(this.transcriptPath, { persistent: false }, () => this.scheduleRead());
10028
+ this.watcher.on("error", (error3) => {
10029
+ this.reportError(error3, "fs.watch failed");
10030
+ this.watcher?.close();
10031
+ this.watcher = null;
10032
+ this.installPollingWatcher();
10033
+ });
10034
+ } catch (error3) {
10035
+ this.reportError(error3, "Failed to install fs.watch");
10036
+ this.installPollingWatcher();
10037
+ }
10038
+ }
10039
+ installPollingWatcher() {
10040
+ if (this.usingPolling) {
10041
+ return;
10042
+ }
10043
+ this.usingPolling = true;
10044
+ watchFile(this.transcriptPath, { interval: this.options.pollIntervalMs, persistent: false }, () => {
10045
+ this.scheduleRead();
10046
+ });
10047
+ }
10048
+ scheduleRead() {
10049
+ if (!this.started) {
10050
+ return;
10051
+ }
10052
+ if (this.debounceTimer) {
10053
+ clearTimeout(this.debounceTimer);
10054
+ }
10055
+ this.debounceTimer = setTimeout(() => {
10056
+ this.readNewContent();
10057
+ }, this.options.debounceMs);
10058
+ }
10059
+ readNewContent() {
10060
+ if (!this.started || !existsSync32(this.transcriptPath)) {
10061
+ return;
10062
+ }
10063
+ let fileSize = 0;
10064
+ try {
10065
+ fileSize = statSync(this.transcriptPath).size;
10066
+ } catch {
10067
+ return;
10068
+ }
10069
+ if (fileSize < this.byteOffset) {
10070
+ this.byteOffset = 0;
10071
+ this.buffer = "";
10072
+ }
10073
+ if (fileSize === this.byteOffset) {
10074
+ return;
10075
+ }
10076
+ const bytesToRead = fileSize - this.byteOffset;
10077
+ const buffer = Buffer.alloc(bytesToRead);
10078
+ const fileDescriptor = openSync(this.transcriptPath, "r");
10079
+ try {
10080
+ readSync(fileDescriptor, buffer, 0, bytesToRead, this.byteOffset);
10081
+ } finally {
10082
+ closeSync(fileDescriptor);
10083
+ }
10084
+ this.byteOffset = fileSize;
10085
+ const pendingText = `${this.buffer}${buffer.toString("utf-8")}`;
10086
+ const lines = pendingText.split("\n");
10087
+ this.buffer = lines.pop() ?? "";
10088
+ const newEntries = [];
10089
+ for (const line of lines) {
10090
+ const trimmed = line.trim();
10091
+ if (trimmed.length === 0) {
8552
10092
  continue;
8553
10093
  }
8554
10094
  try {
8555
- const parsed = JSON.parse(trimmed);
8556
- newEntries.push(...this.mapper.map(parsed, this.mapperState));
8557
- } catch {
8558
- this.buffer = `${trimmed}
8559
- ${this.buffer}`;
8560
- break;
10095
+ const parsed = JSON.parse(trimmed);
10096
+ newEntries.push(...this.mapper.map(parsed, this.mapperState));
10097
+ } catch {
10098
+ this.buffer = `${trimmed}
10099
+ ${this.buffer}`;
10100
+ break;
10101
+ }
10102
+ }
10103
+ if (newEntries.length === 0) {
10104
+ return;
10105
+ }
10106
+ this.entries.push(...newEntries);
10107
+ const allEntries = [...this.entries];
10108
+ for (const handler of this.handlers) {
10109
+ handler(newEntries, allEntries);
10110
+ }
10111
+ }
10112
+ reportError(error3, fallbackMessage) {
10113
+ const resolved = error3 instanceof Error ? error3 : new Error(typeof error3 === "string" ? error3 : fallbackMessage);
10114
+ for (const handler of this.errorHandlers) {
10115
+ handler(resolved);
10116
+ }
10117
+ }
10118
+ };
10119
+ function createJsonlTranscriptWatcher(transcriptPath, mapper, options) {
10120
+ return new JsonlTranscriptWatcher(transcriptPath, mapper, options);
10121
+ }
10122
+ var JsonSessionWatcher = class {
10123
+ constructor(transcriptPath, mapper, options) {
10124
+ this.transcriptPath = transcriptPath;
10125
+ this.mapper = mapper;
10126
+ this.mapperState = mapper.createState();
10127
+ this.options = {
10128
+ debounceMs: options?.debounceMs ?? 100,
10129
+ pollIntervalMs: options?.pollIntervalMs ?? 500
10130
+ };
10131
+ }
10132
+ handlers = /* @__PURE__ */ new Set();
10133
+ errorHandlers = /* @__PURE__ */ new Set();
10134
+ options;
10135
+ entries = [];
10136
+ mapperState;
10137
+ messageCount = 0;
10138
+ watcher = null;
10139
+ debounceTimer = null;
10140
+ started = false;
10141
+ usingPolling = false;
10142
+ onEntries(handler) {
10143
+ this.handlers.add(handler);
10144
+ }
10145
+ onError(handler) {
10146
+ this.errorHandlers.add(handler);
10147
+ }
10148
+ start() {
10149
+ if (this.started) {
10150
+ return;
10151
+ }
10152
+ this.started = true;
10153
+ if (existsSync42(this.transcriptPath)) {
10154
+ this.readSession();
10155
+ }
10156
+ this.installWatcher();
10157
+ }
10158
+ stop() {
10159
+ this.started = false;
10160
+ if (this.debounceTimer) {
10161
+ clearTimeout(this.debounceTimer);
10162
+ this.debounceTimer = null;
10163
+ }
10164
+ if (this.watcher) {
10165
+ this.watcher.close();
10166
+ this.watcher = null;
10167
+ }
10168
+ if (this.usingPolling) {
10169
+ unwatchFile2(this.transcriptPath);
10170
+ this.usingPolling = false;
10171
+ }
10172
+ }
10173
+ getEntries() {
10174
+ return [...this.entries];
10175
+ }
10176
+ installWatcher() {
10177
+ try {
10178
+ this.watcher = watch2(this.transcriptPath, { persistent: false }, () => this.scheduleRead());
10179
+ this.watcher.on("error", (error3) => {
10180
+ this.reportError(error3, "fs.watch failed");
10181
+ this.watcher?.close();
10182
+ this.watcher = null;
10183
+ this.installPollingWatcher();
10184
+ });
10185
+ } catch (error3) {
10186
+ this.reportError(error3, "Failed to install fs.watch");
10187
+ this.installPollingWatcher();
10188
+ }
10189
+ }
10190
+ installPollingWatcher() {
10191
+ if (this.usingPolling) {
10192
+ return;
10193
+ }
10194
+ this.usingPolling = true;
10195
+ watchFile2(this.transcriptPath, { interval: this.options.pollIntervalMs, persistent: false }, () => {
10196
+ this.scheduleRead();
10197
+ });
10198
+ }
10199
+ scheduleRead() {
10200
+ if (!this.started) {
10201
+ return;
10202
+ }
10203
+ if (this.debounceTimer) {
10204
+ clearTimeout(this.debounceTimer);
10205
+ }
10206
+ this.debounceTimer = setTimeout(() => {
10207
+ this.readSession();
10208
+ }, this.options.debounceMs);
10209
+ }
10210
+ resetState() {
10211
+ this.entries = [];
10212
+ this.mapperState = this.mapper.createState();
10213
+ this.messageCount = 0;
10214
+ }
10215
+ readSession() {
10216
+ if (!this.started || !existsSync42(this.transcriptPath)) {
10217
+ return;
10218
+ }
10219
+ let parsed;
10220
+ try {
10221
+ parsed = JSON.parse(readFileSync3(this.transcriptPath, "utf-8"));
10222
+ } catch (error3) {
10223
+ this.reportError(error3, "Failed to parse JSON session");
10224
+ return;
10225
+ }
10226
+ let messages;
10227
+ try {
10228
+ messages = this.mapper.getMessages(parsed);
10229
+ } catch (error3) {
10230
+ this.reportError(error3, "Failed to read session messages");
10231
+ return;
10232
+ }
10233
+ if (messages.length < this.messageCount) {
10234
+ this.resetState();
10235
+ }
10236
+ const newMessages = messages.slice(this.messageCount);
10237
+ if (newMessages.length === 0) {
10238
+ return;
10239
+ }
10240
+ const newEntries = [];
10241
+ for (const message of newMessages) {
10242
+ try {
10243
+ newEntries.push(...this.mapper.map(message, this.mapperState));
10244
+ } catch (error3) {
10245
+ this.reportError(error3, "Failed to map JSON session entry");
8561
10246
  }
8562
10247
  }
10248
+ this.messageCount = messages.length;
8563
10249
  if (newEntries.length === 0) {
8564
10250
  return;
8565
10251
  }
@@ -8569,9 +10255,15 @@ ${this.buffer}`;
8569
10255
  handler(newEntries, allEntries);
8570
10256
  }
8571
10257
  }
10258
+ reportError(error3, fallbackMessage) {
10259
+ const resolved = error3 instanceof Error ? error3 : new Error(typeof error3 === "string" ? error3 : fallbackMessage);
10260
+ for (const handler of this.errorHandlers) {
10261
+ handler(resolved);
10262
+ }
10263
+ }
8572
10264
  };
8573
- function createJsonlTranscriptWatcher(transcriptPath, mapper, options) {
8574
- return new JsonlTranscriptWatcher(transcriptPath, mapper, options);
10265
+ function createJsonSessionWatcher(transcriptPath, mapper, options) {
10266
+ return new JsonSessionWatcher(transcriptPath, mapper, options);
8575
10267
  }
8576
10268
  function buildTranscriptPath(cwd, nativeSessionId) {
8577
10269
  const sanitized = cwd.replace(/[^a-zA-Z0-9\-_]/g, "-");
@@ -8623,7 +10315,7 @@ function createClaudeHarness() {
8623
10315
  },
8624
10316
  resolveTranscriptPath(nativeSessionId, cwd) {
8625
10317
  const candidate = buildTranscriptPath(cwd, nativeSessionId);
8626
- if (existsSync32(candidate)) {
10318
+ if (existsSync52(candidate)) {
8627
10319
  return candidate;
8628
10320
  }
8629
10321
  return null;
@@ -8643,7 +10335,7 @@ function createClaudeHarness() {
8643
10335
  };
8644
10336
  }
8645
10337
  function listDateDirectories(root) {
8646
- if (!existsSync42(root)) {
10338
+ if (!existsSync6(root)) {
8647
10339
  return [];
8648
10340
  }
8649
10341
  const directories = [];
@@ -8668,10 +10360,10 @@ function listDateDirectories(root) {
8668
10360
  }
8669
10361
  function resolveCodexSessionIndex(root, nativeSessionId) {
8670
10362
  const indexPath = join32(root, "session_index.jsonl");
8671
- if (!existsSync42(indexPath)) {
10363
+ if (!existsSync6(indexPath)) {
8672
10364
  return null;
8673
10365
  }
8674
- const lines = readFileSync22(indexPath, "utf-8").split("\n");
10366
+ const lines = readFileSync4(indexPath, "utf-8").split("\n");
8675
10367
  for (const line of lines) {
8676
10368
  const trimmed = line.trim();
8677
10369
  if (trimmed.length === 0) {
@@ -8698,56 +10390,406 @@ function createCodexHarness() {
8698
10390
  maxTurns: false,
8699
10391
  budgetLimit: false,
8700
10392
  toolHooks: false,
8701
- subagentVisibility: true,
10393
+ subagentVisibility: true,
10394
+ structuredOutput: true,
10395
+ permissionBypass: true
10396
+ },
10397
+ buildSpawnArgs(config) {
10398
+ const args = ["exec", config.prompt, "--json", "--dangerously-bypass-approvals-and-sandbox"];
10399
+ if (config.model) {
10400
+ args.push("--model", config.model);
10401
+ }
10402
+ if (config.extraArgs) {
10403
+ args.push(...config.extraArgs);
10404
+ }
10405
+ return args;
10406
+ },
10407
+ buildResumeArgs(nativeSessionId, config) {
10408
+ const args = ["exec", "resume", nativeSessionId, "--json", "--dangerously-bypass-approvals-and-sandbox"];
10409
+ if (config.prompt) {
10410
+ args.push(config.prompt);
10411
+ }
10412
+ if (config.extraArgs) {
10413
+ args.push(...config.extraArgs);
10414
+ }
10415
+ return args;
10416
+ },
10417
+ resolveTranscriptPath(nativeSessionId) {
10418
+ const sessionsRoot = join32(homedir22(), ".codex", "sessions");
10419
+ const indexedPath = resolveCodexSessionIndex(sessionsRoot, nativeSessionId);
10420
+ if (indexedPath) {
10421
+ return indexedPath;
10422
+ }
10423
+ for (const directory of listDateDirectories(sessionsRoot)) {
10424
+ for (const entry of readdirSync2(directory)) {
10425
+ if (entry.includes(nativeSessionId) && entry.endsWith(".jsonl")) {
10426
+ return join32(directory, entry);
10427
+ }
10428
+ }
10429
+ }
10430
+ return null;
10431
+ },
10432
+ createWatcher(transcriptPath) {
10433
+ return createJsonlTranscriptWatcher(transcriptPath, {
10434
+ createState: () => createCodexMapperContext(),
10435
+ map: (entry, state) => mapCodexEntry(entry, state)
10436
+ });
10437
+ },
10438
+ parseTranscript(content) {
10439
+ return parseCodexTranscript(content);
10440
+ },
10441
+ async isAvailable() {
10442
+ return spawnSync22("which", ["codex"], { stdio: "ignore" }).status === 0;
10443
+ }
10444
+ };
10445
+ }
10446
+ var TRANSCRIPT_DISCOVERY_PADDING_MS = 5 * 6e4;
10447
+ var DEFAULT_MAX_DISCOVERY_CANDIDATES = 40;
10448
+ function sanitizeFactoryCwd(cwd) {
10449
+ return cwd.replace(/[\\/]/g, "-");
10450
+ }
10451
+ function buildScopedTranscriptPath(cwd, nativeSessionId) {
10452
+ return join42(homedir32(), ".factory", "sessions", sanitizeFactoryCwd(cwd), `${nativeSessionId}.jsonl`);
10453
+ }
10454
+ function buildLegacyTranscriptPath(nativeSessionId) {
10455
+ return join42(homedir32(), ".factory", "sessions", `${nativeSessionId}.jsonl`);
10456
+ }
10457
+ function getDroidSessionsRoot() {
10458
+ return join42(homedir32(), ".factory", "sessions");
10459
+ }
10460
+ function parseStartedAtMs(startedAt) {
10461
+ if (typeof startedAt === "number" && Number.isFinite(startedAt)) {
10462
+ return startedAt;
10463
+ }
10464
+ if (typeof startedAt === "string") {
10465
+ const parsed = new Date(startedAt).getTime();
10466
+ return Number.isFinite(parsed) ? parsed : null;
10467
+ }
10468
+ return null;
10469
+ }
10470
+ function isTranscriptRecentEnough(transcriptPath, startedAt) {
10471
+ const startedAtMs = parseStartedAtMs(startedAt);
10472
+ if (startedAtMs == null) {
10473
+ return true;
10474
+ }
10475
+ try {
10476
+ return statSync2(transcriptPath).mtimeMs >= startedAtMs - TRANSCRIPT_DISCOVERY_PADDING_MS;
10477
+ } catch {
10478
+ return true;
10479
+ }
10480
+ }
10481
+ function readDroidSessionId(transcriptPath) {
10482
+ try {
10483
+ const firstLine = readFileSync5(transcriptPath, "utf-8").split(/\r?\n/, 1)[0]?.trim();
10484
+ if (!firstLine) {
10485
+ return basename4(transcriptPath, ".jsonl");
10486
+ }
10487
+ const parsed = JSON.parse(firstLine);
10488
+ if (typeof parsed.id === "string" && parsed.id.length > 0) {
10489
+ return parsed.id;
10490
+ }
10491
+ } catch {
10492
+ }
10493
+ return basename4(transcriptPath, ".jsonl");
10494
+ }
10495
+ function listDroidTranscriptPaths(cwd) {
10496
+ const candidateDirs = [join42(getDroidSessionsRoot(), sanitizeFactoryCwd(cwd)), getDroidSessionsRoot()];
10497
+ const transcriptPaths = /* @__PURE__ */ new Map();
10498
+ for (const directory of candidateDirs) {
10499
+ if (!existsSync7(directory)) {
10500
+ continue;
10501
+ }
10502
+ try {
10503
+ for (const entry of readdirSync3(directory, { withFileTypes: true })) {
10504
+ if (!entry.isFile() || !entry.name.endsWith(".jsonl")) {
10505
+ continue;
10506
+ }
10507
+ const transcriptPath = join42(directory, entry.name);
10508
+ transcriptPaths.set(transcriptPath, statSync2(transcriptPath).mtimeMs);
10509
+ }
10510
+ } catch {
10511
+ continue;
10512
+ }
10513
+ }
10514
+ return Array.from(transcriptPaths.entries()).sort((left, right) => right[1] - left[1]).map(([transcriptPath]) => transcriptPath);
10515
+ }
10516
+ function discoverDroidNativeSessionByOrbhSessionId(cwd, orbhSessionId, options) {
10517
+ const transcriptPaths = listDroidTranscriptPaths(cwd).slice(0, options?.maxCandidates ?? DEFAULT_MAX_DISCOVERY_CANDIDATES);
10518
+ for (const transcriptPath of transcriptPaths) {
10519
+ if (!isTranscriptRecentEnough(transcriptPath, options?.startedAt)) {
10520
+ continue;
10521
+ }
10522
+ try {
10523
+ const content = readFileSync5(transcriptPath, "utf-8");
10524
+ if (!content.includes(orbhSessionId)) {
10525
+ continue;
10526
+ }
10527
+ const nativeSessionId = readDroidSessionId(transcriptPath);
10528
+ if (!nativeSessionId) {
10529
+ continue;
10530
+ }
10531
+ return {
10532
+ nativeSessionId,
10533
+ transcriptPath
10534
+ };
10535
+ } catch {
10536
+ continue;
10537
+ }
10538
+ }
10539
+ return null;
10540
+ }
10541
+ function createDroidHarness() {
10542
+ return {
10543
+ name: "droid",
10544
+ capabilities: {
10545
+ headless: true,
10546
+ interactive: true,
10547
+ preassignSessionId: true,
10548
+ maxTurns: false,
10549
+ budgetLimit: false,
10550
+ toolHooks: false,
10551
+ subagentVisibility: false,
10552
+ structuredOutput: true,
10553
+ permissionBypass: true
10554
+ },
10555
+ buildSpawnArgs(config) {
10556
+ const args = ["exec", config.prompt, "--output-format", "stream-json"];
10557
+ if (config.sessionId) {
10558
+ args.push("--session-id", config.sessionId);
10559
+ }
10560
+ args.push("--skip-permissions-unsafe", "--cwd", config.cwd);
10561
+ if (config.model) {
10562
+ args.push("--model", config.model);
10563
+ }
10564
+ if (config.extraArgs) {
10565
+ args.push(...config.extraArgs);
10566
+ }
10567
+ return args;
10568
+ },
10569
+ buildResumeArgs(nativeSessionId, config) {
10570
+ const args = [
10571
+ "exec",
10572
+ config.prompt ?? "Continue working",
10573
+ "--session-id",
10574
+ nativeSessionId,
10575
+ "--output-format",
10576
+ "stream-json",
10577
+ "--skip-permissions-unsafe"
10578
+ ];
10579
+ if (config.extraArgs) {
10580
+ args.push(...config.extraArgs);
10581
+ }
10582
+ return args;
10583
+ },
10584
+ resolveTranscriptPath(nativeSessionId, cwd) {
10585
+ const scopedPath = buildScopedTranscriptPath(cwd, nativeSessionId);
10586
+ if (existsSync7(scopedPath)) {
10587
+ return scopedPath;
10588
+ }
10589
+ const legacyPath = buildLegacyTranscriptPath(nativeSessionId);
10590
+ if (existsSync7(legacyPath)) {
10591
+ return legacyPath;
10592
+ }
10593
+ return scopedPath;
10594
+ },
10595
+ createWatcher(transcriptPath) {
10596
+ return createJsonlTranscriptWatcher(transcriptPath, {
10597
+ createState: () => createDroidMapperContext({ transcriptPath }),
10598
+ map: (entry, state) => mapDroidEntry(entry, state)
10599
+ });
10600
+ },
10601
+ parseTranscript(content, options) {
10602
+ return parseDroidTranscript(content, { transcriptPath: options?.transcriptPath });
10603
+ },
10604
+ async isAvailable() {
10605
+ return spawnSync32("which", ["droid"], { stdio: "ignore" }).status === 0;
10606
+ }
10607
+ };
10608
+ }
10609
+ var TRANSCRIPT_DISCOVERY_PADDING_MS2 = 5 * 6e4;
10610
+ var DEFAULT_MAX_DISCOVERY_CANDIDATES2 = 20;
10611
+ var DEFAULT_GEMINI_MODEL = "gemini-3.1-pro-preview";
10612
+ function slugifyProjectName(name) {
10613
+ return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
10614
+ }
10615
+ function getGeminiTmpRoot() {
10616
+ return join52(homedir42(), ".gemini", "tmp");
10617
+ }
10618
+ function getProjectSlug(cwd) {
10619
+ return slugifyProjectName(basename22(cwd));
10620
+ }
10621
+ function getGeminiChatsDir(cwd) {
10622
+ return join52(getGeminiTmpRoot(), getProjectSlug(cwd), "chats");
10623
+ }
10624
+ function listGeminiTranscriptPaths(cwd) {
10625
+ const chatsDir = getGeminiChatsDir(cwd);
10626
+ if (!existsSync8(chatsDir)) {
10627
+ return [];
10628
+ }
10629
+ return readdirSync4(chatsDir).filter((entry) => entry.startsWith("session-") && entry.endsWith(".json")).map((entry) => join52(chatsDir, entry)).sort((left, right) => right.localeCompare(left));
10630
+ }
10631
+ function readGeminiSessionId(transcriptPath) {
10632
+ try {
10633
+ const parsed = JSON.parse(readFileSync6(transcriptPath, "utf-8"));
10634
+ return typeof parsed.sessionId === "string" ? parsed.sessionId : null;
10635
+ } catch {
10636
+ return null;
10637
+ }
10638
+ }
10639
+ function parseGeminiSessionList(output) {
10640
+ const mapping = /* @__PURE__ */ new Map();
10641
+ for (const line of output.split("\n")) {
10642
+ const match = line.match(/^\s*(\d+)\.\s+.*\[(.+?)\]\s*$/);
10643
+ if (!match) {
10644
+ continue;
10645
+ }
10646
+ const index = match[1];
10647
+ const sessionId = match[2];
10648
+ if (index && sessionId) {
10649
+ mapping.set(sessionId, index);
10650
+ }
10651
+ }
10652
+ return mapping;
10653
+ }
10654
+ function parseStartedAtMs2(startedAt) {
10655
+ if (typeof startedAt === "number" && Number.isFinite(startedAt)) {
10656
+ return startedAt;
10657
+ }
10658
+ if (typeof startedAt === "string") {
10659
+ const parsed = new Date(startedAt).getTime();
10660
+ return Number.isFinite(parsed) ? parsed : null;
10661
+ }
10662
+ return null;
10663
+ }
10664
+ function isTranscriptRecentEnough2(transcriptPath, startedAt) {
10665
+ const startedAtMs = parseStartedAtMs2(startedAt);
10666
+ if (startedAtMs == null) {
10667
+ return true;
10668
+ }
10669
+ try {
10670
+ return statSync3(transcriptPath).mtimeMs >= startedAtMs - TRANSCRIPT_DISCOVERY_PADDING_MS2;
10671
+ } catch {
10672
+ return true;
10673
+ }
10674
+ }
10675
+ function resolveGeminiResumeTarget(nativeSessionId, cwd) {
10676
+ if (nativeSessionId === "latest" || /^\d+$/.test(nativeSessionId)) {
10677
+ return nativeSessionId;
10678
+ }
10679
+ const result = spawnSync4("gemini", ["--list-sessions"], {
10680
+ cwd,
10681
+ encoding: "utf-8",
10682
+ stdio: ["ignore", "pipe", "pipe"]
10683
+ });
10684
+ if (result.status !== 0) {
10685
+ return nativeSessionId;
10686
+ }
10687
+ const sessionIndex = parseGeminiSessionList(result.stdout).get(nativeSessionId);
10688
+ return sessionIndex ?? nativeSessionId;
10689
+ }
10690
+ function discoverGeminiNativeSession(cwd, options) {
10691
+ const excludedPaths = options?.excludeTranscriptPaths;
10692
+ for (const transcriptPath of listGeminiTranscriptPaths(cwd)) {
10693
+ if (excludedPaths?.has(transcriptPath)) {
10694
+ continue;
10695
+ }
10696
+ const nativeSessionId = readGeminiSessionId(transcriptPath);
10697
+ if (!nativeSessionId) {
10698
+ continue;
10699
+ }
10700
+ return { nativeSessionId, transcriptPath };
10701
+ }
10702
+ return null;
10703
+ }
10704
+ function discoverGeminiNativeSessionByOrbhSessionId(cwd, orbhSessionId, options) {
10705
+ const transcriptPaths = listGeminiTranscriptPaths(cwd).slice(0, options?.maxCandidates ?? DEFAULT_MAX_DISCOVERY_CANDIDATES2);
10706
+ for (const transcriptPath of transcriptPaths) {
10707
+ if (!isTranscriptRecentEnough2(transcriptPath, options?.startedAt)) {
10708
+ continue;
10709
+ }
10710
+ try {
10711
+ const content = readFileSync6(transcriptPath, "utf-8");
10712
+ if (!content.includes(orbhSessionId)) {
10713
+ continue;
10714
+ }
10715
+ const parsed = JSON.parse(content);
10716
+ if (typeof parsed.sessionId !== "string") {
10717
+ continue;
10718
+ }
10719
+ return {
10720
+ nativeSessionId: parsed.sessionId,
10721
+ transcriptPath
10722
+ };
10723
+ } catch {
10724
+ continue;
10725
+ }
10726
+ }
10727
+ return null;
10728
+ }
10729
+ async function waitForGeminiNativeSession(cwd, timeoutMs, pollMs, options) {
10730
+ const deadline = Date.now() + timeoutMs;
10731
+ while (Date.now() <= deadline) {
10732
+ const discovered = discoverGeminiNativeSession(cwd, options);
10733
+ if (discovered) {
10734
+ return discovered;
10735
+ }
10736
+ await new Promise((resolve11) => setTimeout(resolve11, pollMs));
10737
+ }
10738
+ return null;
10739
+ }
10740
+ function createGeminiHarness() {
10741
+ return {
10742
+ name: "gemini",
10743
+ capabilities: {
10744
+ headless: true,
10745
+ interactive: true,
10746
+ preassignSessionId: false,
10747
+ maxTurns: false,
10748
+ budgetLimit: false,
10749
+ toolHooks: false,
10750
+ subagentVisibility: false,
8702
10751
  structuredOutput: true,
8703
10752
  permissionBypass: true
8704
10753
  },
8705
10754
  buildSpawnArgs(config) {
8706
- const args = ["exec", config.prompt, "--json", "--dangerously-bypass-approvals-and-sandbox"];
8707
- if (config.model) {
8708
- args.push("--model", config.model);
8709
- }
10755
+ const args = ["-p", config.prompt, "--yolo", "-o", "stream-json"];
10756
+ args.push("--model", config.model || DEFAULT_GEMINI_MODEL);
8710
10757
  if (config.extraArgs) {
8711
10758
  args.push(...config.extraArgs);
8712
10759
  }
8713
10760
  return args;
8714
10761
  },
8715
10762
  buildResumeArgs(nativeSessionId, config) {
8716
- const args = ["exec", "resume", nativeSessionId];
8717
- if (config.prompt) {
8718
- args.push(config.prompt);
8719
- }
10763
+ const args = ["-p", config.prompt ?? "Continue working", "--yolo", "-o", "stream-json", "--model", DEFAULT_GEMINI_MODEL, "--resume", resolveGeminiResumeTarget(nativeSessionId, config.cwd)];
8720
10764
  if (config.extraArgs) {
8721
10765
  args.push(...config.extraArgs);
8722
10766
  }
8723
10767
  return args;
8724
10768
  },
8725
- resolveTranscriptPath(nativeSessionId) {
8726
- const sessionsRoot = join32(homedir22(), ".codex", "sessions");
8727
- const indexedPath = resolveCodexSessionIndex(sessionsRoot, nativeSessionId);
8728
- if (indexedPath) {
8729
- return indexedPath;
8730
- }
8731
- for (const directory of listDateDirectories(sessionsRoot)) {
8732
- for (const entry of readdirSync2(directory)) {
8733
- if (entry.includes(nativeSessionId) && entry.endsWith(".jsonl")) {
8734
- return join32(directory, entry);
8735
- }
10769
+ resolveTranscriptPath(nativeSessionId, cwd) {
10770
+ const prefix = nativeSessionId.slice(0, 8);
10771
+ for (const transcriptPath of listGeminiTranscriptPaths(cwd)) {
10772
+ if (basename22(transcriptPath).includes(prefix)) {
10773
+ return transcriptPath;
10774
+ }
10775
+ if (readGeminiSessionId(transcriptPath) === nativeSessionId) {
10776
+ return transcriptPath;
8736
10777
  }
8737
10778
  }
8738
10779
  return null;
8739
10780
  },
8740
10781
  createWatcher(transcriptPath) {
8741
- return createJsonlTranscriptWatcher(transcriptPath, {
8742
- createState: () => createCodexMapperContext(),
8743
- map: (entry, state) => mapCodexEntry(entry, state)
10782
+ return createJsonSessionWatcher(transcriptPath, {
10783
+ createState: () => createGeminiMapperContext(),
10784
+ getMessages: (payload) => Array.isArray(payload.messages) ? payload.messages.filter((message) => typeof message === "object" && message !== null && !Array.isArray(message)) : [],
10785
+ map: (message, state) => mapGeminiMessageEntry(message, state)
8744
10786
  });
8745
10787
  },
8746
10788
  parseTranscript(content) {
8747
- return parseCodexTranscript(content);
10789
+ return parseGeminiTranscript(content);
8748
10790
  },
8749
10791
  async isAvailable() {
8750
- return spawnSync22("which", ["codex"], { stdio: "ignore" }).status === 0;
10792
+ return spawnSync4("which", ["gemini"], { stdio: "ignore" }).status === 0;
8751
10793
  }
8752
10794
  };
8753
10795
  }
@@ -8763,8 +10805,14 @@ function listHarnesses() {
8763
10805
  }
8764
10806
  registerHarness(createClaudeHarness());
8765
10807
  registerHarness(createCodexHarness());
10808
+ registerHarness(createDroidHarness());
10809
+ registerHarness(createGeminiHarness());
8766
10810
 
8767
10811
  // src/commands/export-session.ts
10812
+ import { writeFile as writeFile3, mkdir as mkdir5, stat as stat5, readFile as readFile6 } from "fs/promises";
10813
+ import { join as join11 } from "path";
10814
+ import { homedir as homedir6 } from "os";
10815
+ import pc27 from "picocolors";
8768
10816
  function resolveProjectDir(cwd) {
8769
10817
  return join11(homedir6(), ".claude", "projects", cwd.replace(/[^a-zA-Z0-9\-_]/g, "-"));
8770
10818
  }
@@ -8785,12 +10833,22 @@ function buildFrontmatter(sessionId) {
8785
10833
  return lines.join("\n");
8786
10834
  }
8787
10835
  async function exportSession(flintPath, sessionId) {
10836
+ const existingPath = join11(flintPath, "Mesh", "Agents", "Claude Code", `${sessionId}.md`);
10837
+ try {
10838
+ const existingContent = await readFile6(existingPath, "utf-8");
10839
+ const frontmatterMatch = existingContent.match(/^---\n([\s\S]*?)\n---/);
10840
+ if (frontmatterMatch && !frontmatterMatch[1].includes("live: true")) {
10841
+ console.log(pc27.dim("Session already exported by server, skipping CLI export."));
10842
+ return;
10843
+ }
10844
+ } catch {
10845
+ }
8788
10846
  const projectDir = resolveProjectDir(flintPath);
8789
10847
  let transcriptPath = null;
8790
10848
  for (const name of [`${sessionId}.jsonl`, `transcript-${sessionId}.jsonl`]) {
8791
10849
  const filePath = join11(projectDir, name);
8792
10850
  try {
8793
- await stat4(filePath);
10851
+ await stat5(filePath);
8794
10852
  transcriptPath = filePath;
8795
10853
  break;
8796
10854
  } catch {
@@ -8817,7 +10875,7 @@ async function exportSession(flintPath, sessionId) {
8817
10875
  }
8818
10876
 
8819
10877
  // src/commands/export-codex-session.ts
8820
- import { writeFile as writeFile4, mkdir as mkdir6, readFile as readFile7, readdir as readdir2, stat as stat5 } from "fs/promises";
10878
+ import { writeFile as writeFile4, mkdir as mkdir6, readFile as readFile7, readdir as readdir2, stat as stat6 } from "fs/promises";
8821
10879
  import { join as join12 } from "path";
8822
10880
  import { homedir as homedir7 } from "os";
8823
10881
  import pc28 from "picocolors";
@@ -8838,7 +10896,7 @@ async function findCodexTranscript(sessionId, startedAfter) {
8838
10896
  if (!file.endsWith(".jsonl")) continue;
8839
10897
  if (file.includes(sessionId)) {
8840
10898
  const filePath = join12(dayDir, file);
8841
- const s = await stat5(filePath);
10899
+ const s = await stat6(filePath);
8842
10900
  if (s.mtimeMs >= startedAfter) {
8843
10901
  return filePath;
8844
10902
  }
@@ -8868,6 +10926,16 @@ function buildFrontmatter2(sessionId) {
8868
10926
  return lines.join("\n");
8869
10927
  }
8870
10928
  async function exportCodexSession(flintPath, sessionId, startedAt) {
10929
+ const existingPath = join12(flintPath, "Mesh", "Agents", "Codex", `${sessionId}.md`);
10930
+ try {
10931
+ const existingContent = await readFile7(existingPath, "utf-8");
10932
+ const frontmatterMatch = existingContent.match(/^---\n([\s\S]*?)\n---/);
10933
+ if (frontmatterMatch && !frontmatterMatch[1].includes("live: true")) {
10934
+ console.log(pc28.dim("Session already exported by server, skipping CLI export."));
10935
+ return;
10936
+ }
10937
+ } catch {
10938
+ }
8871
10939
  const transcriptPath = await findCodexTranscript(sessionId, startedAt);
8872
10940
  if (!transcriptPath) {
8873
10941
  console.log(pc28.dim("No Codex session transcript found to export."));
@@ -8907,6 +10975,62 @@ function askYesNo(question) {
8907
10975
  });
8908
10976
  });
8909
10977
  }
10978
+ function getSessionsDir(flintPath) {
10979
+ return join13(flintPath, ".flint", "sessions");
10980
+ }
10981
+ function buildSessionFrontmatter(sessionId, runtime2) {
10982
+ const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
10983
+ const runtimeTag = runtime2 === "claude" ? "claude-code" : runtime2;
10984
+ const runtimeTitle = runtime2 === "claude" ? "Claude Code" : runtime2.charAt(0).toUpperCase() + runtime2.slice(1);
10985
+ return [
10986
+ "---",
10987
+ `id: ${sessionId}`,
10988
+ "tags:",
10989
+ ' - "#agent/session"',
10990
+ ` - "#agent/${runtimeTag}"`,
10991
+ `date: ${now}`,
10992
+ "---",
10993
+ "",
10994
+ `# ${runtimeTitle} Session`,
10995
+ ""
10996
+ ].join("\n");
10997
+ }
10998
+ function exportOrbhSessionTranscript(session, flintPath) {
10999
+ const harness = getHarness(session.runtime);
11000
+ if (!harness) {
11001
+ return;
11002
+ }
11003
+ const run = getCurrentRun2(session);
11004
+ const nativeId = run?.nativeSessionId ?? session.id;
11005
+ const transcriptPath = harness.resolveTranscriptPath(nativeId, flintPath);
11006
+ if (!transcriptPath) {
11007
+ console.log(pc29.dim("No transcript found to export."));
11008
+ return;
11009
+ }
11010
+ let content;
11011
+ try {
11012
+ content = readFileSync7(transcriptPath, "utf-8");
11013
+ } catch {
11014
+ console.log(pc29.dim("Could not read transcript file."));
11015
+ return;
11016
+ }
11017
+ const entries = harness.parseTranscript(content);
11018
+ if (entries.length === 0) {
11019
+ console.log(pc29.dim("Transcript is empty, skipping export."));
11020
+ return;
11021
+ }
11022
+ const body = formatTranscriptMarkdown(entries);
11023
+ const markdown = buildSessionFrontmatter(nativeId, session.runtime) + body;
11024
+ const runtimeDir = session.runtime === "claude" ? "Claude Code" : session.runtime.charAt(0).toUpperCase() + session.runtime.slice(1);
11025
+ const outputDir = join13(flintPath, "Mesh", "Agents", runtimeDir);
11026
+ mkdirSync3(outputDir, { recursive: true });
11027
+ const outputPath = join13(outputDir, `${nativeId}.md`);
11028
+ writeFileSync2(outputPath, markdown, "utf-8");
11029
+ console.log(pc29.green(`Session exported \u2192 Mesh/Agents/${runtimeDir}/${nativeId}.md`));
11030
+ }
11031
+ function buildGeminiInitPrompt(sessionId) {
11032
+ return `init, you are a gemini session, your session id is ${sessionId}, please read init-f.md and (System) Flint Init.md`;
11033
+ }
8910
11034
  var CLIENT_INFO = {
8911
11035
  name: "flint_code",
8912
11036
  title: "Flint Code",
@@ -8914,7 +11038,7 @@ var CLIENT_INFO = {
8914
11038
  };
8915
11039
  async function bootstrapCodexSession(cwd, initPrompt) {
8916
11040
  return new Promise((resolve11, reject) => {
8917
- const proc = spawn4("codex", ["app-server"], {
11041
+ const proc = spawn5("codex", ["app-server"], {
8918
11042
  stdio: ["pipe", "pipe", "pipe"],
8919
11043
  cwd
8920
11044
  });
@@ -8934,7 +11058,7 @@ async function bootstrapCodexSession(cwd, initPrompt) {
8934
11058
  let pollInterval = null;
8935
11059
  const startPolling = () => {
8936
11060
  pollInterval = setInterval(() => {
8937
- if (sessionPath && existsSync6(sessionPath)) {
11061
+ if (sessionPath && existsSync9(sessionPath)) {
8938
11062
  if (pollInterval) clearInterval(pollInterval);
8939
11063
  send({ method: "turn/interrupt", id: 4, params: { threadId } });
8940
11064
  setTimeout(() => {
@@ -8999,7 +11123,7 @@ codeCommand.command("claude").description("Open Claude Code TUI").option("-p, --
8999
11123
  sessionId = randomUUID3();
9000
11124
  args.push("--session-id", sessionId, await buildClaudeInitPrompt(sessionId));
9001
11125
  }
9002
- const child = spawn4("claude", args, {
11126
+ const child = spawn5("claude", args, {
9003
11127
  cwd: flintPath,
9004
11128
  stdio: "inherit"
9005
11129
  });
@@ -9068,7 +11192,7 @@ codeCommand.command("codex").description("Open Codex TUI with session tracking")
9068
11192
  console.log(pc29.green(`Session ID: ${threadId}`));
9069
11193
  console.log("");
9070
11194
  const resumePrompt = options.continue ? `continuing session ${threadId}` : `your session id is ${threadId}`;
9071
- const child = spawn4("codex", [
11195
+ const child = spawn5("codex", [
9072
11196
  "resume",
9073
11197
  threadId,
9074
11198
  "--dangerously-bypass-approvals-and-sandbox",
@@ -9102,7 +11226,7 @@ codeCommand.command("codex").description("Open Codex TUI with session tracking")
9102
11226
  process.exit(1);
9103
11227
  }
9104
11228
  });
9105
- codeCommand.command("gemini").description("Open Gemini CLI with session tracking").option("-p, --path <dir>", "Path to flint (default: auto-detect)").option("-r, --resume <id>", "Resume a previous Gemini session").action(async (options) => {
11229
+ codeCommand.command("gemini").description("Open Gemini CLI with Orbh session tracking").option("-p, --path <dir>", "Path to flint (default: auto-detect)").option("-r, --resume <id>", "Resume a previous Gemini or Orbh session").action(async (options) => {
9106
11230
  try {
9107
11231
  const flintPath = options.path || await findFlintRoot(process.cwd());
9108
11232
  if (!flintPath) {
@@ -9111,15 +11235,75 @@ codeCommand.command("gemini").description("Open Gemini CLI with session tracking
9111
11235
  );
9112
11236
  process.exit(1);
9113
11237
  }
9114
- const args = ["--yolo"];
11238
+ const sessionsDir = getSessionsDir(flintPath);
11239
+ let session;
11240
+ let args;
11241
+ let nativeDiscovery = null;
9115
11242
  if (options.resume) {
9116
- args.push("--resume", options.resume);
11243
+ const existing = resolveSession2(sessionsDir, options.resume);
11244
+ if (existing) {
11245
+ if (existing.runtime !== "gemini") {
11246
+ console.error(pc29.red(`Error: Session ${options.resume} is a ${existing.runtime} session, not gemini.`));
11247
+ process.exit(1);
11248
+ }
11249
+ session = existing;
11250
+ const lastRun = getCurrentRun2(session);
11251
+ const nativeResumeTarget = resolveGeminiResumeTarget(lastRun?.nativeSessionId ?? "latest", flintPath);
11252
+ addRun2(session, {
11253
+ nativeSessionId: lastRun?.nativeSessionId ?? null,
11254
+ continuesRunId: lastRun?.id ?? null
11255
+ });
11256
+ session.status = "in-progress";
11257
+ writeSession(sessionsDir, session);
11258
+ args = ["--yolo", "--resume", nativeResumeTarget];
11259
+ } else {
11260
+ session = createSession2(sessionsDir, "gemini", "", {
11261
+ title: "(Interactive) Gemini Session",
11262
+ description: "Interactive Gemini CLI session from flint code gemini"
11263
+ });
11264
+ addRun2(session, { nativeSessionId: options.resume });
11265
+ session.status = "in-progress";
11266
+ writeSession(sessionsDir, session);
11267
+ args = ["--yolo", "--resume", options.resume];
11268
+ }
11269
+ } else {
11270
+ session = createSession2(sessionsDir, "gemini", "", {
11271
+ title: "(Interactive) Gemini Session",
11272
+ description: "Interactive Gemini CLI session from flint code gemini"
11273
+ });
11274
+ addRun2(session, { nativeSessionId: null });
11275
+ session.status = "in-progress";
11276
+ writeSession(sessionsDir, session);
11277
+ const knownTranscriptPaths = new Set(listGeminiTranscriptPaths(flintPath));
11278
+ args = ["--yolo", "--prompt-interactive", buildGeminiInitPrompt(session.id)];
11279
+ nativeDiscovery = waitForGeminiNativeSession(flintPath, 3e4, 250, {
11280
+ excludeTranscriptPaths: knownTranscriptPaths
11281
+ }).then((discovered) => {
11282
+ if (!discovered) {
11283
+ return;
11284
+ }
11285
+ const fresh = readSession2(sessionsDir, session.id);
11286
+ if (!fresh) {
11287
+ return;
11288
+ }
11289
+ updateCurrentRun2(fresh, { nativeSessionId: discovered.nativeSessionId });
11290
+ writeSession(sessionsDir, fresh);
11291
+ });
9117
11292
  }
9118
- const child = spawn4("gemini", args, {
11293
+ const child = spawn5("gemini", args, {
9119
11294
  cwd: flintPath,
9120
- stdio: "inherit"
11295
+ stdio: "inherit",
11296
+ env: { ...process.env, ORBH_SESSION_ID: session.id }
9121
11297
  });
11298
+ if (child.pid) {
11299
+ updateCurrentRun2(session, { pid: child.pid });
11300
+ session.status = "in-progress";
11301
+ writeSession(sessionsDir, session);
11302
+ }
9122
11303
  child.on("error", (err) => {
11304
+ updateCurrentRun2(session, { status: "failed", ended: (/* @__PURE__ */ new Date()).toISOString() });
11305
+ session.status = "failed";
11306
+ writeSession(sessionsDir, session);
9123
11307
  if (err.code === "ENOENT") {
9124
11308
  console.error(pc29.red("Error: Gemini CLI is not installed."));
9125
11309
  console.log("");
@@ -9130,7 +11314,34 @@ codeCommand.command("gemini").description("Open Gemini CLI with session tracking
9130
11314
  console.error(pc29.red(`Error: ${err.message}`));
9131
11315
  process.exit(1);
9132
11316
  });
9133
- child.on("exit", (code) => {
11317
+ child.on("exit", async (code) => {
11318
+ if (nativeDiscovery) {
11319
+ await Promise.race([
11320
+ nativeDiscovery,
11321
+ new Promise((resolve11) => setTimeout(resolve11, 500))
11322
+ ]);
11323
+ }
11324
+ const fresh = readSession2(sessionsDir, session.id) ?? session;
11325
+ updateCurrentRun2(fresh, {
11326
+ ended: (/* @__PURE__ */ new Date()).toISOString(),
11327
+ exitCode: code ?? null,
11328
+ status: code === 0 ? "completed" : "failed"
11329
+ });
11330
+ fresh.status = code === 0 ? "finished" : "failed";
11331
+ writeSession(sessionsDir, fresh);
11332
+ try {
11333
+ const nativeId = getCurrentRun2(fresh)?.nativeSessionId ?? fresh.id;
11334
+ if (sessionReferencedInMesh(flintPath, fresh.id) || sessionReferencedInMesh(flintPath, nativeId)) {
11335
+ exportOrbhSessionTranscript(fresh, flintPath);
11336
+ } else {
11337
+ const save = await askYesNo(pc29.dim("Save session transcript? (y/N) "));
11338
+ if (save) {
11339
+ exportOrbhSessionTranscript(fresh, flintPath);
11340
+ }
11341
+ }
11342
+ } catch (err) {
11343
+ console.error(pc29.dim(`Session export failed: ${err instanceof Error ? err.message : err}`));
11344
+ }
9134
11345
  process.exit(code || 0);
9135
11346
  });
9136
11347
  } catch (err) {
@@ -9143,8 +11354,8 @@ codeCommand.command("gemini").description("Open Gemini CLI with session tracking
9143
11354
  // src/commands/helper.ts
9144
11355
  import { Command as Command25 } from "commander";
9145
11356
  import pc30 from "picocolors";
9146
- import { readdirSync as readdirSync3, existsSync as existsSync7, statSync as statSync2 } from "fs";
9147
- import { join as join14, basename as basename4 } from "path";
11357
+ import { readdirSync as readdirSync5, existsSync as existsSync10, statSync as statSync4 } from "fs";
11358
+ import { join as join14, basename as basename5 } from "path";
9148
11359
  function extractNumberFromFile(filename, typeName) {
9149
11360
  const regex = new RegExp(`^\\(${typeName}\\)\\s+(\\d+)`, "i");
9150
11361
  const match = filename.match(regex);
@@ -9152,18 +11363,18 @@ function extractNumberFromFile(filename, typeName) {
9152
11363
  }
9153
11364
  function collectFilesRecursively(dirPath) {
9154
11365
  const files = [];
9155
- if (!existsSync7(dirPath)) {
11366
+ if (!existsSync10(dirPath)) {
9156
11367
  return files;
9157
11368
  }
9158
- const entries = readdirSync3(dirPath);
11369
+ const entries = readdirSync5(dirPath);
9159
11370
  for (const entry of entries) {
9160
11371
  const fullPath = join14(dirPath, entry);
9161
11372
  try {
9162
- const stat8 = statSync2(fullPath);
9163
- if (stat8.isDirectory()) {
11373
+ const stat9 = statSync4(fullPath);
11374
+ if (stat9.isDirectory()) {
9164
11375
  files.push(...collectFilesRecursively(fullPath));
9165
- } else if (stat8.isFile()) {
9166
- files.push(basename4(fullPath));
11376
+ } else if (stat9.isFile()) {
11377
+ files.push(basename5(fullPath));
9167
11378
  }
9168
11379
  } catch {
9169
11380
  continue;
@@ -9173,7 +11384,7 @@ function collectFilesRecursively(dirPath) {
9173
11384
  }
9174
11385
  function getNextNumber(flintPath, typeName) {
9175
11386
  const meshDir = join14(flintPath, "Mesh");
9176
- if (!existsSync7(meshDir)) {
11387
+ if (!existsSync10(meshDir)) {
9177
11388
  return 1;
9178
11389
  }
9179
11390
  const allFiles = collectFilesRecursively(meshDir);
@@ -9340,7 +11551,7 @@ var resolveCommand = new Command27("resolve").description("Resolve a reference t
9340
11551
  // src/commands/fulfill.ts
9341
11552
  import { Command as Command28 } from "commander";
9342
11553
  import pc33 from "picocolors";
9343
- import { stat as stat6 } from "fs/promises";
11554
+ import { stat as stat7 } from "fs/promises";
9344
11555
  import { resolve as resolve8 } from "path";
9345
11556
  import { homedir as homedir8 } from "os";
9346
11557
  function expandPath3(p) {
@@ -9349,7 +11560,7 @@ function expandPath3(p) {
9349
11560
  }
9350
11561
  async function pathExists(p) {
9351
11562
  try {
9352
- await stat6(p);
11563
+ await stat7(p);
9353
11564
  return true;
9354
11565
  } catch {
9355
11566
  return false;
@@ -9456,7 +11667,7 @@ function prompt5(message) {
9456
11667
  // src/commands/update.ts
9457
11668
  import { Command as Command29 } from "commander";
9458
11669
  import pc34 from "picocolors";
9459
- import { readFileSync as readFileSync3, existsSync as existsSync8 } from "fs";
11670
+ import { readFileSync as readFileSync8, existsSync as existsSync11 } from "fs";
9460
11671
  import { dirname as dirname3, join as join15 } from "path";
9461
11672
  import { fileURLToPath as fileURLToPath2 } from "url";
9462
11673
  import { execSync as execSync4 } from "child_process";
@@ -9465,8 +11676,8 @@ var __dirname2 = dirname3(fileURLToPath2(import.meta.url));
9465
11676
  function readPkgVersion() {
9466
11677
  for (const rel of ["../..", ".."]) {
9467
11678
  const p = join15(__dirname2, rel, "package.json");
9468
- if (existsSync8(p)) {
9469
- return JSON.parse(readFileSync3(p, "utf-8")).version;
11679
+ if (existsSync11(p)) {
11680
+ return JSON.parse(readFileSync8(p, "utf-8")).version;
9470
11681
  }
9471
11682
  }
9472
11683
  throw new Error("Could not determine current version");
@@ -9541,11 +11752,11 @@ var updateCommand = new Command29("update").description("Update flint-cli to the
9541
11752
  import { Command as Command30 } from "commander";
9542
11753
  import pc35 from "picocolors";
9543
11754
  import { randomUUID as randomUUID4 } from "crypto";
9544
- import { copyFile as copyFile2, mkdir as mkdir7, writeFile as writeFile5, unlink as unlink2, stat as stat7 } from "fs/promises";
9545
- import { join as join16, basename as basename5, resolve as resolve9 } from "path";
9546
- async function exists3(path4) {
11755
+ import { copyFile as copyFile2, mkdir as mkdir7, writeFile as writeFile5, unlink as unlink2, stat as stat8 } from "fs/promises";
11756
+ import { join as join16, basename as basename6, resolve as resolve9 } from "path";
11757
+ async function exists3(path5) {
9547
11758
  try {
9548
- await stat7(path4);
11759
+ await stat8(path5);
9549
11760
  return true;
9550
11761
  } catch {
9551
11762
  return false;
@@ -9574,7 +11785,7 @@ var sendCommand = new Command30("send").description("Send files to another Flint
9574
11785
  const copyFileNames = /* @__PURE__ */ new Set();
9575
11786
  if (options.copy) {
9576
11787
  for (const cf of options.copy) {
9577
- copyFileNames.add(basename5(resolve9(cf)));
11788
+ copyFileNames.add(basename6(resolve9(cf)));
9578
11789
  }
9579
11790
  }
9580
11791
  const moveFiles = [];
@@ -9585,7 +11796,7 @@ var sendCommand = new Command30("send").description("Send files to another Flint
9585
11796
  console.error(pc35.red(`Error: File not found: ${file}`));
9586
11797
  process.exit(1);
9587
11798
  }
9588
- const fileName = basename5(file);
11799
+ const fileName = basename6(file);
9589
11800
  const entry = { sourcePath, fileName };
9590
11801
  if (copyFileNames.has(fileName)) {
9591
11802
  copyFiles.push(entry);
@@ -9596,8 +11807,8 @@ var sendCommand = new Command30("send").description("Send files to another Flint
9596
11807
  if (options.copy) {
9597
11808
  for (const cf of options.copy) {
9598
11809
  const sourcePath = resolve9(cf);
9599
- const fileName = basename5(cf);
9600
- if (files.some((f) => basename5(resolve9(f)) === fileName)) continue;
11810
+ const fileName = basename6(cf);
11811
+ if (files.some((f) => basename6(resolve9(f)) === fileName)) continue;
9601
11812
  if (!await exists3(sourcePath)) {
9602
11813
  console.error(pc35.red(`Error: Copy file not found: ${cf}`));
9603
11814
  process.exit(1);
@@ -9622,7 +11833,7 @@ var sendCommand = new Command30("send").description("Send files to another Flint
9622
11833
  console.log();
9623
11834
  let sourceFlintName = "Unknown";
9624
11835
  try {
9625
- const { readFlintToml: readFlintToml3 } = await import("./dist-PKS3JY77.js");
11836
+ const { readFlintToml: readFlintToml3 } = await import("./dist-RGQKIZQW.js");
9626
11837
  const toml = await readFlintToml3(flintPath);
9627
11838
  if (toml?.flint?.name) {
9628
11839
  sourceFlintName = toml.flint.name;
@@ -9721,7 +11932,7 @@ var whoamiCommand = new Command31("whoami").description("Show the current person
9721
11932
  // src/commands/migrate.ts
9722
11933
  import { Command as Command32 } from "commander";
9723
11934
  import pc37 from "picocolors";
9724
- var migrateCommand = new Command32("migrate").description("Run pending workspace migrations").option("-p, --path <dir>", "Path to flint (default: auto-detect)").option("--dry-run", "Show pending migrations without running them").action(async (options) => {
11935
+ var migrateCommand = new Command32("migrate").description("Run pending workspace migrations").option("-p, --path <dir>", "Path to flint (default: auto-detect)").option("--dry-run", "Show pending migrations without running them").option("--only <id>", "Run a single migration by ID (no version bump)").option("--list", "List all available migrations from the current version onwards").action(async (options) => {
9725
11936
  try {
9726
11937
  const flintPath = options.path || await findFlintRoot(process.cwd());
9727
11938
  if (!flintPath) {
@@ -9730,6 +11941,75 @@ var migrateCommand = new Command32("migrate").description("Run pending workspace
9730
11941
  );
9731
11942
  process.exit(1);
9732
11943
  }
11944
+ if (options.list) {
11945
+ const check2 = await checkMigrations(flintPath);
11946
+ const steps = getVersionSteps();
11947
+ console.log(pc37.bold("\nAll migrations from current version onwards:\n"));
11948
+ let hasAny = false;
11949
+ for (const step2 of steps) {
11950
+ const stepMigrations = getMigrationsForVersion(step2);
11951
+ const sealed = isVersionStepSealed(step2);
11952
+ const hasPending = stepMigrations.some(
11953
+ (m) => check2.pending.some((p) => p.id === m.id)
11954
+ );
11955
+ const hasSkipped = stepMigrations.some(
11956
+ (m) => check2.skipped.some((s) => s.id === m.id)
11957
+ );
11958
+ if (!hasPending && !hasSkipped) continue;
11959
+ hasAny = true;
11960
+ const sealLabel = sealed ? pc37.green("sealed") : pc37.yellow("unsealed");
11961
+ console.log(pc37.bold(` \u2192 ${step2}`) + ` ${pc37.dim("(")}${sealLabel}${pc37.dim(")")}`);
11962
+ for (const m of stepMigrations) {
11963
+ const isPending = check2.pending.some((p) => p.id === m.id);
11964
+ const isSkipped = check2.skipped.some((s) => s.id === m.id);
11965
+ const status = isPending ? pc37.yellow("pending") : isSkipped ? pc37.dim("done") : pc37.dim("unknown");
11966
+ console.log(` ${isPending ? pc37.yellow("\u25CB") : pc37.dim("\u2713")} ${m.name} ${pc37.dim(`[${m.id}]`)} ${pc37.dim("\u2014")} ${status}`);
11967
+ console.log(` ${pc37.dim(m.description)}`);
11968
+ }
11969
+ }
11970
+ if (!hasAny) {
11971
+ console.log(pc37.green(" No migrations available \u2014 workspace is up to date."));
11972
+ }
11973
+ console.log("");
11974
+ return;
11975
+ }
11976
+ if (options.only) {
11977
+ console.log(pc37.bold(`
11978
+ Running single migration: ${options.only}
11979
+ `));
11980
+ const result2 = await runSingleMigration(flintPath, options.only, {
11981
+ log: (msg) => console.log(pc37.dim(` ${msg}`)),
11982
+ warn: (msg) => console.log(pc37.yellow(` ! ${msg}`)),
11983
+ error: (msg) => console.log(pc37.red(` \u2717 ${msg}`))
11984
+ });
11985
+ for (const m of result2.applied) {
11986
+ console.log(` ${pc37.green("\u2713")} ${m.name}`);
11987
+ for (const change of m.changes) {
11988
+ console.log(` ${pc37.dim("\u2192")} ${change}`);
11989
+ }
11990
+ if (m.warnings) {
11991
+ for (const warning of m.warnings) {
11992
+ console.log(` ${pc37.yellow("!")} ${warning}`);
11993
+ }
11994
+ }
11995
+ }
11996
+ for (const m of result2.skipped) {
11997
+ console.log(` ${pc37.dim("\u25CB")} ${m.name} ${pc37.dim("(already done)")}`);
11998
+ }
11999
+ for (const m of result2.failed) {
12000
+ console.log(` ${pc37.red("\u2717")} ${m.name}`);
12001
+ console.log(` ${pc37.red("\u2192")} ${m.error}`);
12002
+ }
12003
+ console.log("");
12004
+ if (result2.failed.length > 0) {
12005
+ console.log(pc37.red("Migration failed."));
12006
+ process.exit(1);
12007
+ }
12008
+ if (result2.applied.length > 0) {
12009
+ console.log(pc37.green("\u2713 Migration applied (no version bump)."));
12010
+ }
12011
+ return;
12012
+ }
9733
12013
  const check = await checkMigrations(flintPath);
9734
12014
  if (check.pending.length === 0) {
9735
12015
  console.log(pc37.green("\u2713 No pending migrations."));
@@ -9745,7 +12025,9 @@ var migrateCommand = new Command32("migrate").description("Run pending workspace
9745
12025
  ${check.pending.length} migration(s) pending:
9746
12026
  `));
9747
12027
  for (const [version, items] of groups) {
9748
- console.log(pc37.bold(` \u2192 ${version}`));
12028
+ const sealed = isVersionStepSealed(version);
12029
+ const sealLabel = sealed ? pc37.green("sealed") : pc37.yellow("unsealed");
12030
+ console.log(pc37.bold(` \u2192 ${version}`) + ` ${pc37.dim("(")}${sealLabel}${pc37.dim(")")}`);
9749
12031
  for (const m of items) {
9750
12032
  console.log(` ${pc37.dim("\u25CB")} ${m.name}`);
9751
12033
  console.log(` ${pc37.dim(m.description)}`);
@@ -9945,6 +12227,7 @@ async function requireTinderboxRoot() {
9945
12227
  function printSummary(result) {
9946
12228
  console.log(pc40.bold("\nSummary"));
9947
12229
  console.log(` Cloned: ${result.cloned.length}`);
12230
+ console.log(` Moved: ${result.moved.length}`);
9948
12231
  console.log(` Referenced: ${result.referenced.length}`);
9949
12232
  console.log(` Already present: ${result.present.length}`);
9950
12233
  console.log(` Registry updated: ${result.registryUpdated.length}`);
@@ -10120,6 +12403,12 @@ var tinderboxCommand = new Command35("tinderbox").description("Orchestrate opera
10120
12403
  console.log(` ${pc40.green("\u2713")} ${name}`);
10121
12404
  }
10122
12405
  }
12406
+ if (result.moved.length > 0) {
12407
+ console.log(pc40.bold("\nMoved"));
12408
+ for (const entry of result.moved) {
12409
+ console.log(` ${pc40.green("\u2713")} ${entry.name} ${pc40.dim(`${abbreviatePath(entry.from)} \u2192 ${abbreviatePath(entry.to)}`)}`);
12410
+ }
12411
+ }
10123
12412
  if (result.referenced.length > 0) {
10124
12413
  console.log(pc40.bold("\nReferenced From Registry"));
10125
12414
  for (const name of result.referenced) {
@@ -10263,11 +12552,12 @@ var tinderboxCommand = new Command35("tinderbox").description("Orchestrate opera
10263
12552
  // src/commands/orb.ts
10264
12553
  import { Command as Command36 } from "commander";
10265
12554
  import pc41 from "picocolors";
10266
- import { spawn as spawn5, spawnSync as spawnSync4, execSync as execSync5 } from "child_process";
10267
- import { existsSync as existsSync9, readFileSync as readFileSync4, writeFileSync as writeFileSync2, mkdirSync as mkdirSync3 } from "fs";
12555
+ import { spawn as spawn6, spawnSync as spawnSync5, execSync as execSync5 } from "child_process";
12556
+ import { existsSync as existsSync12, mkdirSync as mkdirSync4, readFileSync as readFileSync9, readdirSync as readdirSync6, statSync as statSync5, writeFileSync as writeFileSync3 } from "fs";
10268
12557
  import { join as join17 } from "path";
12558
+ import { homedir as homedir9 } from "os";
10269
12559
  import { createInterface as createInterface7 } from "readline";
10270
- function getSessionsDir(flintPath) {
12560
+ function getSessionsDir2(flintPath) {
10271
12561
  return join17(flintPath, ".flint", "sessions");
10272
12562
  }
10273
12563
  async function resolveFlintPath4(optionPath) {
@@ -10280,7 +12570,7 @@ async function resolveFlintPath4(optionPath) {
10280
12570
  }
10281
12571
  async function resolveCtx(optionPath) {
10282
12572
  const flintPath = await resolveFlintPath4(optionPath);
10283
- return { flintPath, sessionsDir: getSessionsDir(flintPath) };
12573
+ return { flintPath, sessionsDir: getSessionsDir2(flintPath) };
10284
12574
  }
10285
12575
  function sessionReferencedInMesh2(flintPath, sessionId) {
10286
12576
  try {
@@ -10307,8 +12597,8 @@ function readTranscriptEntries(session, flintPath) {
10307
12597
  const transcriptPath = harness.resolveTranscriptPath(nativeId, flintPath);
10308
12598
  if (!transcriptPath) return null;
10309
12599
  try {
10310
- const content = readFileSync4(transcriptPath, "utf-8");
10311
- return harness.parseTranscript(content);
12600
+ const content = readFileSync9(transcriptPath, "utf-8");
12601
+ return harness.parseTranscript(content, { transcriptPath });
10312
12602
  } catch {
10313
12603
  return null;
10314
12604
  }
@@ -10330,7 +12620,7 @@ function formatTokenSummary(usage) {
10330
12620
  var DETACHED_ORB_MONITOR = String.raw`
10331
12621
  const { spawn, spawnSync } = require('node:child_process');
10332
12622
  const { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, renameSync } = require('node:fs');
10333
- const { dirname, join } = require('node:path');
12623
+ const { basename, dirname, join } = require('node:path');
10334
12624
  const { homedir } = require('node:os');
10335
12625
 
10336
12626
  const configJson = process.env.ORBH_MONITOR_CONFIG;
@@ -10388,7 +12678,7 @@ child.on('error', () => {
10388
12678
  updateCurrentRun(s, { status: 'failed', ended: new Date().toISOString() });
10389
12679
  writeSessionFile(s);
10390
12680
  }
10391
- notify('OrbH Session Failed', (s?.title || s?.description || 'Unknown').slice(0, 100));
12681
+ notify('Orbh Session Failed', (s?.title || s?.description || 'Unknown').slice(0, 100));
10392
12682
  process.exit(1);
10393
12683
  });
10394
12684
 
@@ -10456,6 +12746,57 @@ if (command === 'codex') {
10456
12746
  }, 500);
10457
12747
  }
10458
12748
 
12749
+ // Gemini native session discovery — poll for a new session-*.json transcript
12750
+ if (command === 'gemini') {
12751
+ const slugify = (name) => name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
12752
+ const geminiChatsDir = join(homedir(), '.gemini', 'tmp', slugify(basename(cwd)), 'chats');
12753
+
12754
+ // Snapshot existing transcript paths before launch to exclude them
12755
+ const existingTranscripts = new Set();
12756
+ try {
12757
+ for (const f of readdirSync(geminiChatsDir)) {
12758
+ if (f.startsWith('session-') && f.endsWith('.json')) {
12759
+ existingTranscripts.add(join(geminiChatsDir, f));
12760
+ }
12761
+ }
12762
+ } catch {}
12763
+
12764
+ function discoverGeminiSession() {
12765
+ if (!existsSync(geminiChatsDir)) return null;
12766
+ const files = readdirSync(geminiChatsDir)
12767
+ .filter(f => f.startsWith('session-') && f.endsWith('.json'))
12768
+ .map(f => join(geminiChatsDir, f))
12769
+ .sort((a, b) => b.localeCompare(a));
12770
+ for (const fp of files) {
12771
+ if (existingTranscripts.has(fp)) continue;
12772
+ try {
12773
+ const parsed = JSON.parse(readFileSync(fp, 'utf-8'));
12774
+ if (typeof parsed.sessionId === 'string') {
12775
+ return { nativeSessionId: parsed.sessionId, transcriptPath: fp };
12776
+ }
12777
+ } catch { continue; }
12778
+ }
12779
+ return null;
12780
+ }
12781
+
12782
+ let geminiDiscoveryAttempts = 0;
12783
+ const geminiMaxAttempts = 60; // 30s at 500ms interval
12784
+ const geminiDiscoveryTimer = setInterval(() => {
12785
+ geminiDiscoveryAttempts++;
12786
+ const found = discoverGeminiSession();
12787
+ if (found) {
12788
+ clearInterval(geminiDiscoveryTimer);
12789
+ const s = readSession();
12790
+ if (s) {
12791
+ updateCurrentRun(s, { nativeSessionId: found.nativeSessionId });
12792
+ writeSessionFile(s);
12793
+ }
12794
+ } else if (geminiDiscoveryAttempts >= geminiMaxAttempts) {
12795
+ clearInterval(geminiDiscoveryTimer);
12796
+ }
12797
+ }, 500);
12798
+ }
12799
+
10459
12800
  child.on('exit', (code) => {
10460
12801
  const s = readSession();
10461
12802
  if (!s) { process.exit(typeof code === 'number' ? code : 1); return; }
@@ -10477,7 +12818,7 @@ child.on('exit', (code) => {
10477
12818
  s.status = 'finished';
10478
12819
  }
10479
12820
  writeSessionFile(s);
10480
- notify('OrbH Session Complete', desc);
12821
+ notify('Orbh Session Complete', desc);
10481
12822
  } else {
10482
12823
  if (!runIsTerminal) {
10483
12824
  updateCurrentRun(s, { status: 'failed' });
@@ -10487,7 +12828,7 @@ child.on('exit', (code) => {
10487
12828
  }
10488
12829
  writeSessionFile(s);
10489
12830
  const errLine = stderr.trim().split(/\r?\n/).find(Boolean);
10490
- notify('OrbH Session Failed', desc + (errLine ? ': ' + errLine.slice(0, 80) : ' (exit ' + code + ')'));
12831
+ notify('Orbh Session Failed', desc + (errLine ? ': ' + errLine.slice(0, 80) : ' (exit ' + code + ')'));
10491
12832
  }
10492
12833
 
10493
12834
  process.exit(typeof code === 'number' ? code : 1);
@@ -10555,9 +12896,9 @@ async function buildOrbInitPrompt(sessionId, runtime2, flintPath, options) {
10555
12896
  }
10556
12897
  return `init, you are a ${runtime2} session, please read init-f.md and (System) Flint Init.md${identityClause}
10557
12898
 
10558
- You are running in headless mode via OrbH. Your session ID is: ${sessionId}
12899
+ You are running in headless mode via Orbh. Your session ID is: ${sessionId}
10559
12900
 
10560
- After initialization, load the Flint OrbH shard by reading Shards/(Dev) Flint OrbH/init-foh.md.
12901
+ After initialization, load the Flint Orbh shard by reading Shards/(Dev) Flint Orbh/init-foh.md.
10561
12902
 
10562
12903
  IMPORTANT: Use flint orb commands, NOT flint agent session commands.
10563
12904
 
@@ -10582,11 +12923,12 @@ async function buildInteractiveInitPrompt(sessionId, runtime2, flintPath) {
10582
12923
  }
10583
12924
  } catch {
10584
12925
  }
10585
- return `init, you are a ${runtime2} session, please read init-f.md and (System) Flint Init.md. Your session ID is ${sessionId}${identityClause}
12926
+ const sessionIdClause = runtime2 === "codex" ? `Your Orbh session ID is ${sessionId}. If Codex later shows you a native Codex session ID or thread ID, that is different from the Orbh session ID and must not be used with flint orb commands.` : `Your session ID is ${sessionId}.`;
12927
+ return `init, you are a ${runtime2} session, please read init-f.md and (System) Flint Init.md. ${sessionIdClause}${identityClause}
10586
12928
 
10587
- You are running as an interactive OrbH session. Your session is tracked via the orbh system.
12929
+ You are running as an interactive Orbh session. Your session is tracked via the orbh system.
10588
12930
 
10589
- After initialization, load the Flint OrbH shard by reading Shards/(Dev) Flint OrbH/init-foh.md.
12931
+ After initialization, load the Flint Orbh shard by reading Shards/(Dev) Flint Orbh/init-foh.md.
10590
12932
 
10591
12933
  IMPORTANT: Use flint orb commands, NOT flint agent session commands.
10592
12934
 
@@ -10595,7 +12937,7 @@ This is an interactive session \u2014 the human is present and will guide the co
10595
12937
 
10596
12938
  Use flint orb commands to keep your status and interface updated while you work.`;
10597
12939
  }
10598
- function buildSessionFrontmatter(sessionId, runtime2) {
12940
+ function buildSessionFrontmatter2(sessionId, runtime2) {
10599
12941
  const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
10600
12942
  const runtimeTag = runtime2 === "claude" ? "claude-code" : runtime2;
10601
12943
  const runtimeTitle = runtime2 === "claude" ? "Claude Code" : runtime2.charAt(0).toUpperCase() + runtime2.slice(1);
@@ -10624,29 +12966,29 @@ function exportSessionTranscript(session, flintPath) {
10624
12966
  }
10625
12967
  let content;
10626
12968
  try {
10627
- content = readFileSync4(transcriptPath, "utf-8");
12969
+ content = readFileSync9(transcriptPath, "utf-8");
10628
12970
  } catch {
10629
12971
  console.log(pc41.dim("Could not read transcript file."));
10630
12972
  return;
10631
12973
  }
10632
- const entries = harness.parseTranscript(content);
12974
+ const entries = harness.parseTranscript(content, { transcriptPath });
10633
12975
  if (entries.length === 0) {
10634
12976
  console.log(pc41.dim("Transcript is empty, skipping export."));
10635
12977
  return;
10636
12978
  }
10637
12979
  const body = formatTranscriptMarkdown(entries);
10638
- const markdown = buildSessionFrontmatter(nativeId, session.runtime) + body;
12980
+ const markdown = buildSessionFrontmatter2(nativeId, session.runtime) + body;
10639
12981
  const runtimeDir = session.runtime === "claude" ? "Claude Code" : session.runtime.charAt(0).toUpperCase() + session.runtime.slice(1);
10640
12982
  const outputDir = join17(flintPath, "Mesh", "Agents", runtimeDir);
10641
- mkdirSync3(outputDir, { recursive: true });
12983
+ mkdirSync4(outputDir, { recursive: true });
10642
12984
  const outputPath = join17(outputDir, `${nativeId}.md`);
10643
- writeFileSync2(outputPath, markdown, "utf-8");
12985
+ writeFileSync3(outputPath, markdown, "utf-8");
10644
12986
  console.log(pc41.green(`Session exported \u2192 Mesh/Agents/${runtimeDir}/${nativeId}.md`));
10645
12987
  }
10646
12988
  function startDetachedMonitor(sessionsDir, sessionId, cwd, command, args) {
10647
12989
  const sessionPath = getSessionPath2(sessionsDir, sessionId);
10648
12990
  const config = JSON.stringify({ sessionPath, cwd, command, args });
10649
- const monitor = spawn5(process.execPath, ["-e", DETACHED_ORB_MONITOR], {
12991
+ const monitor = spawn6(process.execPath, ["-e", DETACHED_ORB_MONITOR], {
10650
12992
  cwd,
10651
12993
  detached: true,
10652
12994
  stdio: "ignore",
@@ -10742,51 +13084,24 @@ function formatEntry2(entry, maxLen, depth = 0, agentCalls) {
10742
13084
  return null;
10743
13085
  }
10744
13086
  }
10745
- var orbCommand = new Command36("orb").description("OrbH meta-harness agent management").enablePositionalOptions();
10746
- function isProcessAlive(pid) {
10747
- try {
10748
- process.kill(pid, 0);
10749
- return true;
10750
- } catch {
10751
- return false;
10752
- }
10753
- }
13087
+ var orbCommand = new Command36("orb").description("Orbh meta-harness agent management").enablePositionalOptions();
10754
13088
  orbCommand.command("heal").description("Fix sessions stuck in non-terminal states (stale PIDs, orphaned runs)").option("-p, --path <dir>", "Path to flint (default: auto-detect)").option("--dry-run", "Show what would be healed without making changes").action(async (options) => {
10755
13089
  const { sessionsDir } = await resolveCtx(options.path);
10756
13090
  const sessions = listSessions2(sessionsDir);
10757
13091
  let healed = 0;
10758
13092
  for (const session of sessions) {
10759
- if (isTerminalStatus2(session.status)) continue;
10760
13093
  const currentRun = getCurrentRun2(session);
10761
- if (!currentRun) {
13094
+ const prevStatus = session.status;
13095
+ const prevRunStatus = currentRun?.status;
13096
+ if (healSession(session)) {
13097
+ const runDesc = currentRun ? `run ${shortId2(currentRun.id)} PID ${currentRun.pid ?? "none"} ${prevRunStatus} \u2192 ${currentRun.status}` : `no runs, ${prevStatus} \u2192 ${session.status}`;
10762
13098
  if (options.dryRun) {
10763
- console.log(`${pc41.yellow("would heal")} ${shortId2(session.id)} \u2014 no runs, status: ${session.status}`);
13099
+ console.log(`${pc41.yellow("would heal")} ${shortId2(session.id)} \u2014 ${runDesc}`);
10764
13100
  } else {
10765
- session.status = "failed";
10766
13101
  writeSession(sessionsDir, session);
10767
- console.log(`${pc41.green("healed")} ${shortId2(session.id)} \u2014 no runs \u2192 failed`);
13102
+ console.log(`${pc41.green("healed")} ${shortId2(session.id)} \u2014 ${runDesc}`);
10768
13103
  }
10769
13104
  healed++;
10770
- continue;
10771
- }
10772
- if (currentRun.status === "running") {
10773
- const pid = currentRun.pid;
10774
- const alive = pid ? isProcessAlive(pid) : false;
10775
- if (!alive) {
10776
- if (options.dryRun) {
10777
- console.log(`${pc41.yellow("would heal")} ${shortId2(session.id)} \u2014 run ${shortId2(currentRun.id)} PID ${pid ?? "none"} is dead, status: ${session.status}`);
10778
- } else {
10779
- updateCurrentRun2(session, {
10780
- status: "failed",
10781
- ended: (/* @__PURE__ */ new Date()).toISOString(),
10782
- exitCode: currentRun.exitCode ?? -1
10783
- });
10784
- session.status = "failed";
10785
- writeSession(sessionsDir, session);
10786
- console.log(`${pc41.green("healed")} ${shortId2(session.id)} \u2014 dead PID ${pid ?? "none"} \u2192 failed`);
10787
- }
10788
- healed++;
10789
- }
10790
13105
  }
10791
13106
  }
10792
13107
  if (healed === 0) {
@@ -10827,7 +13142,7 @@ orbCommand.command("launch").description("Launch a new headless agent session").
10827
13142
  const run = addRun2(session, { nativeSessionId });
10828
13143
  writeSession(sessionsDir, session);
10829
13144
  startDetachedMonitor(sessionsDir, session.id, flintPath, harness.name, args);
10830
- console.log(`${pc41.bold("OrbH Agent Session")}`);
13145
+ console.log(`${pc41.bold("Orbh Agent Session")}`);
10831
13146
  console.log(` ID: ${pc41.cyan(session.id)}`);
10832
13147
  console.log(` Runtime: ${pc41.cyan(runtime2)}`);
10833
13148
  console.log(` Run: ${pc41.dim(shortId2(run.id))}`);
@@ -10863,7 +13178,7 @@ orbCommand.command("resume").description("Resume an existing session (adds a new
10863
13178
  session.status = "queued";
10864
13179
  writeSession(sessionsDir, session);
10865
13180
  startDetachedMonitor(sessionsDir, session.id, flintPath, harness.name, args);
10866
- console.log(`${pc41.bold("OrbH Session Resumed")}`);
13181
+ console.log(`${pc41.bold("Orbh Session Resumed")}`);
10867
13182
  console.log(` ID: ${pc41.cyan(session.id)}`);
10868
13183
  console.log(` Run: ${pc41.dim(shortId2(run.id))} (run #${session.runs.length})`);
10869
13184
  console.log("");
@@ -10894,6 +13209,24 @@ function buildCodexResumeArgs(threadId, prompt6, options) {
10894
13209
  if (prompt6) args.push(prompt6);
10895
13210
  return args;
10896
13211
  }
13212
+ function buildInteractiveDroidArgs(prompt6) {
13213
+ return prompt6 ? [prompt6] : [];
13214
+ }
13215
+ function buildInteractiveDroidResumeArgs(nativeSessionId, prompt6) {
13216
+ const args = ["--resume", nativeSessionId];
13217
+ if (prompt6) args.push(prompt6);
13218
+ return args;
13219
+ }
13220
+ function buildInteractiveGeminiArgs(prompt6, options) {
13221
+ const args = ["--yolo", "--model", options.model || DEFAULT_GEMINI_MODEL];
13222
+ if (prompt6) args.push(prompt6);
13223
+ return args;
13224
+ }
13225
+ function buildInteractiveGeminiResumeArgs(nativeSessionId, prompt6, options) {
13226
+ const args = ["--yolo", "--model", options.model || DEFAULT_GEMINI_MODEL, "--resume", nativeSessionId];
13227
+ if (prompt6) args.push(prompt6);
13228
+ return args;
13229
+ }
10897
13230
  orbCommand.command("i").alias("interactive").description("Launch an interactive agent TUI with orbh session tracking").argument("<runtime>", `Harness runtime (${listHarnesses().join(", ")})`).argument("[prompt]", "Optional initial prompt").option("-p, --path <dir>", "Path to flint (default: auto-detect)").option("-c, --continue <sessionId>", "Continue a previous orbh session").option("--continues <sessionId>", "Link as continuation of another session (new session)").option("--model <model>", "Model override").option("--dev-channels", "Load development MCP channels (e.g. orbh)").option("--no-export", "Skip transcript export on exit").action(async (runtime2, userPrompt, options) => {
10898
13231
  try {
10899
13232
  const { flintPath, sessionsDir } = await resolveCtx(options.path);
@@ -10918,7 +13251,17 @@ orbCommand.command("i").alias("interactive").description("Launch an interactive
10918
13251
  }
10919
13252
  session = existing;
10920
13253
  const lastRun = getCurrentRun2(session);
10921
- const nativeId = lastRun?.nativeSessionId ?? session.id;
13254
+ let nativeId = lastRun?.nativeSessionId ?? session.id;
13255
+ if (!lastRun?.nativeSessionId && runtime2 === "droid") {
13256
+ nativeId = discoverDroidNativeSessionByOrbhSessionId(flintPath, session.id, {
13257
+ startedAt: lastRun?.started ?? session.started
13258
+ })?.nativeSessionId ?? nativeId;
13259
+ }
13260
+ if (!lastRun?.nativeSessionId && runtime2 === "gemini") {
13261
+ nativeId = discoverGeminiNativeSessionByOrbhSessionId(flintPath, session.id, {
13262
+ startedAt: lastRun?.started ?? session.started
13263
+ })?.nativeSessionId ?? nativeId;
13264
+ }
10922
13265
  const resumePrompt = userPrompt || `continuing session ${session.id}`;
10923
13266
  if (runtime2 === "claude") {
10924
13267
  spawnCommand = "claude";
@@ -10929,6 +13272,12 @@ orbCommand.command("i").alias("interactive").description("Launch an interactive
10929
13272
  } else if (runtime2 === "codex") {
10930
13273
  spawnCommand = "codex";
10931
13274
  spawnArgs = buildCodexResumeArgs(nativeId, resumePrompt, { model: options.model });
13275
+ } else if (runtime2 === "droid") {
13276
+ spawnCommand = "droid";
13277
+ spawnArgs = buildInteractiveDroidResumeArgs(nativeId, resumePrompt);
13278
+ } else if (runtime2 === "gemini") {
13279
+ spawnCommand = "gemini";
13280
+ spawnArgs = buildInteractiveGeminiResumeArgs(nativeId, resumePrompt, { model: options.model });
10932
13281
  } else {
10933
13282
  spawnCommand = harness.name;
10934
13283
  spawnArgs = resumePrompt ? [resumePrompt] : [];
@@ -10936,7 +13285,7 @@ orbCommand.command("i").alias("interactive").description("Launch an interactive
10936
13285
  addRun2(session, { nativeSessionId: nativeId, continuesRunId: lastRun?.id ?? null });
10937
13286
  session.status = "in-progress";
10938
13287
  writeSession(sessionsDir, session);
10939
- console.log(`${pc41.bold("OrbH Interactive Session (resumed)")}`);
13288
+ console.log(`${pc41.bold("Orbh Interactive Session (resumed)")}`);
10940
13289
  console.log(` ID: ${pc41.cyan(session.id)}`);
10941
13290
  console.log(` Run: ${pc41.dim(shortId2(session.runs[session.runs.length - 1].id))} (run #${session.runs.length})`);
10942
13291
  console.log("");
@@ -10975,11 +13324,23 @@ ${prompt6}` : initPrompt;
10975
13324
  process.exit(1);
10976
13325
  }
10977
13326
  spawnCommand = "codex";
10978
- const codexResumePrompt = `your session id is ${threadId}. Please initialize now.`;
13327
+ const codexResumePrompt = `Your native Codex session ID is ${threadId}. Your Orbh session ID remains ${session.id}. Use the Orbh session ID with flint orb commands, not the native Codex session ID. Please initialize now.`;
10979
13328
  spawnArgs = buildCodexResumeArgs(threadId, codexResumePrompt, { model: options.model });
10980
13329
  addRun2(session, { nativeSessionId: threadId });
10981
13330
  session.status = "in-progress";
10982
13331
  writeSession(sessionsDir, session);
13332
+ } else if (runtime2 === "droid") {
13333
+ spawnCommand = "droid";
13334
+ spawnArgs = buildInteractiveDroidArgs(fullPrompt);
13335
+ addRun2(session, { nativeSessionId: null });
13336
+ session.status = "in-progress";
13337
+ writeSession(sessionsDir, session);
13338
+ } else if (runtime2 === "gemini") {
13339
+ spawnCommand = "gemini";
13340
+ spawnArgs = buildInteractiveGeminiArgs(fullPrompt, { model: options.model });
13341
+ addRun2(session, { nativeSessionId: null });
13342
+ session.status = "in-progress";
13343
+ writeSession(sessionsDir, session);
10983
13344
  } else {
10984
13345
  spawnCommand = harness.name;
10985
13346
  spawnArgs = [fullPrompt];
@@ -10987,17 +13348,48 @@ ${prompt6}` : initPrompt;
10987
13348
  session.status = "in-progress";
10988
13349
  writeSession(sessionsDir, session);
10989
13350
  }
10990
- console.log(`${pc41.bold("OrbH Interactive Session")}`);
13351
+ console.log(`${pc41.bold("Orbh Interactive Session")}`);
10991
13352
  console.log(` ID: ${pc41.cyan(session.id)}`);
10992
13353
  console.log(` Runtime: ${pc41.cyan(runtime2)}`);
10993
13354
  if (options.continues) console.log(` Continues: ${pc41.dim(options.continues)}`);
10994
13355
  console.log("");
10995
13356
  }
10996
- const child = spawn5(spawnCommand, spawnArgs, {
13357
+ const child = spawn6(spawnCommand, spawnArgs, {
10997
13358
  cwd: flintPath,
10998
13359
  stdio: "inherit",
10999
13360
  env: { ...process.env, ORBH_SESSION_ID: session.id }
11000
13361
  });
13362
+ if (child.pid) {
13363
+ updateCurrentRun2(session, { pid: child.pid });
13364
+ session.status = "in-progress";
13365
+ writeSession(sessionsDir, session);
13366
+ }
13367
+ let nativeDiscoveryTimer = null;
13368
+ if ((runtime2 === "droid" || runtime2 === "gemini") && !getCurrentRun2(session)?.nativeSessionId) {
13369
+ const startedAt = getCurrentRun2(session)?.started ?? session.started;
13370
+ nativeDiscoveryTimer = setInterval(() => {
13371
+ const fresh = readSession2(sessionsDir, session.id) ?? session;
13372
+ const currentRun = getCurrentRun2(fresh);
13373
+ if (!currentRun || currentRun.nativeSessionId) {
13374
+ if (nativeDiscoveryTimer) {
13375
+ clearInterval(nativeDiscoveryTimer);
13376
+ nativeDiscoveryTimer = null;
13377
+ }
13378
+ return;
13379
+ }
13380
+ const discovered = runtime2 === "droid" ? discoverDroidNativeSessionByOrbhSessionId(flintPath, session.id, { startedAt }) : discoverGeminiNativeSessionByOrbhSessionId(flintPath, session.id, { startedAt });
13381
+ if (!discovered) {
13382
+ return;
13383
+ }
13384
+ updateCurrentRun2(fresh, { nativeSessionId: discovered.nativeSessionId });
13385
+ writeSession(sessionsDir, fresh);
13386
+ session = fresh;
13387
+ if (nativeDiscoveryTimer) {
13388
+ clearInterval(nativeDiscoveryTimer);
13389
+ nativeDiscoveryTimer = null;
13390
+ }
13391
+ }, 500);
13392
+ }
11001
13393
  child.on("error", (err) => {
11002
13394
  if (err.code === "ENOENT") {
11003
13395
  console.error(pc41.red(`Error: ${runtime2} is not installed.`));
@@ -11010,35 +13402,40 @@ ${prompt6}` : initPrompt;
11010
13402
  process.exit(1);
11011
13403
  });
11012
13404
  child.on("exit", async (code) => {
11013
- const run = getCurrentRun2(session);
13405
+ if (nativeDiscoveryTimer) {
13406
+ clearInterval(nativeDiscoveryTimer);
13407
+ nativeDiscoveryTimer = null;
13408
+ }
13409
+ const fresh = readSession2(sessionsDir, session.id) ?? session;
13410
+ const run = getCurrentRun2(fresh);
11014
13411
  const runIsTerminal = run && (run.status === "completed" || run.status === "failed" || run.status === "cancelled" || run.status === "suspended");
11015
- updateCurrentRun2(session, { ended: (/* @__PURE__ */ new Date()).toISOString(), exitCode: code });
13412
+ updateCurrentRun2(fresh, { ended: (/* @__PURE__ */ new Date()).toISOString(), exitCode: code });
11016
13413
  if (code === 0) {
11017
13414
  if (!runIsTerminal) {
11018
13415
  const agentReturned = run && run.result;
11019
- updateCurrentRun2(session, { status: agentReturned ? "completed" : "suspended" });
13416
+ updateCurrentRun2(fresh, { status: agentReturned ? "completed" : "suspended" });
11020
13417
  }
11021
- if (!isTerminalStatus2(session.status) && session.status !== "deferred") {
11022
- session.status = "finished";
13418
+ if (!isTerminalStatus2(fresh.status) && fresh.status !== "deferred") {
13419
+ fresh.status = "finished";
11023
13420
  }
11024
13421
  } else {
11025
13422
  if (!runIsTerminal) {
11026
- updateCurrentRun2(session, { status: "failed" });
13423
+ updateCurrentRun2(fresh, { status: "failed" });
11027
13424
  }
11028
- if (!isTerminalStatus2(session.status) && session.status !== "deferred") {
11029
- session.status = "failed";
13425
+ if (!isTerminalStatus2(fresh.status) && fresh.status !== "deferred") {
13426
+ fresh.status = "failed";
11030
13427
  }
11031
13428
  }
11032
- writeSession(sessionsDir, session);
13429
+ writeSession(sessionsDir, fresh);
11033
13430
  if (options.export !== false) {
11034
13431
  try {
11035
- const nativeId = run?.nativeSessionId ?? session.id;
11036
- if (sessionReferencedInMesh2(flintPath, session.id) || sessionReferencedInMesh2(flintPath, nativeId)) {
11037
- exportSessionTranscript(session, flintPath);
13432
+ const nativeId = run?.nativeSessionId ?? fresh.id;
13433
+ if (sessionReferencedInMesh2(flintPath, fresh.id) || sessionReferencedInMesh2(flintPath, nativeId)) {
13434
+ exportSessionTranscript(fresh, flintPath);
11038
13435
  } else {
11039
13436
  const save = await askYesNo2(pc41.dim("Save session transcript? (y/N) "));
11040
13437
  if (save) {
11041
- exportSessionTranscript(session, flintPath);
13438
+ exportSessionTranscript(fresh, flintPath);
11042
13439
  }
11043
13440
  }
11044
13441
  } catch (err) {
@@ -11057,6 +13454,11 @@ orbCommand.command("list").description("List all agent sessions").option("-p, --
11057
13454
  const { flintPath, sessionsDir } = await resolveCtx(options.path);
11058
13455
  const renderTable = (interactive) => {
11059
13456
  let sessions = listSessions2(sessionsDir);
13457
+ for (const s of sessions) {
13458
+ if (healSession(s)) {
13459
+ writeSession(sessionsDir, s);
13460
+ }
13461
+ }
11060
13462
  if (options.status) {
11061
13463
  sessions = sessions.filter((s) => s.status === options.status);
11062
13464
  }
@@ -11070,7 +13472,7 @@ orbCommand.command("list").description("List all agent sessions").option("-p, --
11070
13472
  );
11071
13473
  }
11072
13474
  if (!options.all) sessions = sessions.slice(0, 30);
11073
- const lines = ["", pc41.bold("OrbH Sessions"), ""];
13475
+ const lines = ["", pc41.bold("Orbh Sessions"), ""];
11074
13476
  if (sessions.length === 0) {
11075
13477
  lines.push(pc41.dim("No sessions found."));
11076
13478
  } else {
@@ -11097,7 +13499,8 @@ orbCommand.command("list").description("List all agent sessions").option("-p, --
11097
13499
  statsCol = `${pc41.dim("-").padEnd(6)} ${pc41.dim("-").padEnd(12)} `;
11098
13500
  }
11099
13501
  }
11100
- lines.push(` ${icon} ${s.status.padEnd(13)} ${pc41.cyan(sid)} ${rt} ${runs} ${dur} ${statsCol}${desc}${cont}`);
13502
+ const metaHint = s.metadata && Object.keys(s.metadata).length > 0 ? pc41.dim(` [meta: ${typeof s.metadata.plate === "string" ? s.metadata.plate : Object.keys(s.metadata).length + "k"}]`) : "";
13503
+ lines.push(` ${icon} ${s.status.padEnd(13)} ${pc41.cyan(sid)} ${rt} ${runs} ${dur} ${statsCol}${desc}${cont}${metaHint}`);
11101
13504
  }
11102
13505
  }
11103
13506
  if (interactive) {
@@ -11129,15 +13532,34 @@ orbCommand.command("list").description("List all agent sessions").option("-p, --
11129
13532
  }
11130
13533
  process.stdout.write(renderTable());
11131
13534
  });
11132
- orbCommand.command("inspect").description("Inspect a specific session in detail").argument("<id>", "Session ID (full or partial)").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (id, options) => {
13535
+ orbCommand.command("inspect").description("Inspect a specific session in detail").argument("<id>", "Session ID (full or partial)").option("-p, --path <dir>", "Path to flint (default: auto-detect)").option("-r, --results", "Show run results").action(async (id, options) => {
11133
13536
  const { flintPath, sessionsDir } = await resolveCtx(options.path);
11134
13537
  const session = resolveSession2(sessionsDir, id);
11135
13538
  if (!session) {
11136
13539
  console.error(pc41.red(`Error: Session not found: ${id}`));
11137
13540
  process.exit(1);
11138
13541
  }
13542
+ if (healSession(session)) {
13543
+ writeSession(sessionsDir, session);
13544
+ }
13545
+ if (options.results) {
13546
+ const runsWithResults = session.runs.filter((r) => r.result);
13547
+ if (runsWithResults.length === 0) {
13548
+ console.log(pc41.dim("No results for this session."));
13549
+ return;
13550
+ }
13551
+ console.log(`
13552
+ ${pc41.bold("Results")} ${pc41.dim(`\u2014 session ${shortId2(session.id)}`)}
13553
+ `);
13554
+ for (const run of runsWithResults) {
13555
+ console.log(` ${pc41.dim(`run ${shortId2(run.id)}`)} ${pc41.dim(formatLocalTime2(run.started))}`);
13556
+ console.log(` ${run.result}`);
13557
+ console.log("");
13558
+ }
13559
+ return;
13560
+ }
11139
13561
  console.log(`
11140
- ${pc41.bold("OrbH Session")}
13562
+ ${pc41.bold("Orbh Session")}
11141
13563
  `);
11142
13564
  console.log(` ${pc41.dim("ID:")} ${session.id}`);
11143
13565
  console.log(` ${pc41.dim("Runtime:")} ${session.runtime}`);
@@ -11149,12 +13571,6 @@ ${pc41.bold("OrbH Session")}
11149
13571
  console.log(` ${pc41.dim("Updated:")} ${formatLocalTime2(session.updated)}`);
11150
13572
  console.log(` ${pc41.dim("Duration:")} ${formatDuration2(session.started, isTerminalStatus2(session.status) ? session.updated : void 0)}`);
11151
13573
  if (session.continues) console.log(` ${pc41.dim("Continues:")} ${session.continues}`);
11152
- const latestRun = getCurrentRun2(session);
11153
- if (latestRun?.result) {
11154
- console.log(`
11155
- ${pc41.bold("Result:")} ${pc41.dim(`(run ${shortId2(latestRun.id)})`)}`);
11156
- console.log(` ${latestRun.result}`);
11157
- }
11158
13574
  const entries = readTranscriptEntries(session, flintPath);
11159
13575
  if (entries && entries.length > 0) {
11160
13576
  const turns = groupIntoTurns(entries);
@@ -11214,8 +13630,26 @@ ${pc41.bold("OrbH Session")}
11214
13630
  console.log(` ${pc41.cyan(key)}: ${val}`);
11215
13631
  }
11216
13632
  }
13633
+ const meta = session.metadata;
13634
+ if (meta && Object.keys(meta).length > 0) {
13635
+ console.log(`
13636
+ ${pc41.bold("Metadata:")}`);
13637
+ for (const [key, val] of Object.entries(meta)) {
13638
+ const display = typeof val === "string" ? val : JSON.stringify(val);
13639
+ console.log(` ${pc41.cyan(key)}: ${display}`);
13640
+ }
13641
+ }
11217
13642
  console.log("");
11218
13643
  });
13644
+ orbCommand.command("export").description("Export a session transcript to Mesh/Agents/<Runtime>/").argument("<id>", "Session ID (full or partial)").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (id, options) => {
13645
+ const { flintPath, sessionsDir } = await resolveCtx(options.path);
13646
+ const session = resolveSession2(sessionsDir, id);
13647
+ if (!session) {
13648
+ console.error(pc41.red(`Error: Session not found: ${id}`));
13649
+ process.exit(1);
13650
+ }
13651
+ exportSessionTranscript(session, flintPath);
13652
+ });
11219
13653
  orbCommand.command("requests").description("View request/response pairs for a session").argument("<id>", "Session ID (full or partial)").option("-p, --path <dir>", "Path to flint (default: auto-detect)").option("--pending", "Show only unanswered requests").action(async (id, options) => {
11220
13654
  const { sessionsDir } = await resolveCtx(options.path);
11221
13655
  const session = resolveSession2(sessionsDir, id);
@@ -11293,7 +13727,7 @@ orbCommand.command("stats").description("Show detailed session statistics \u2014
11293
13727
  }
11294
13728
  }
11295
13729
  console.log(`
11296
- ${pc41.bold("OrbH Session Stats")} ${pc41.dim("\xB7")} ${pc41.cyan(shortId2(session.id))} ${pc41.dim("\xB7")} ${session.runtime}
13730
+ ${pc41.bold("Orbh Session Stats")} ${pc41.dim("\xB7")} ${pc41.cyan(shortId2(session.id))} ${pc41.dim("\xB7")} ${session.runtime}
11297
13731
  `);
11298
13732
  console.log(` ${pc41.bold("Overview")}`);
11299
13733
  console.log(` Status: ${statusIcon2(session.status)} ${session.status}`);
@@ -11405,22 +13839,40 @@ orbCommand.command("watch").description("Stream a live session transcript to the
11405
13839
  process.exit(1);
11406
13840
  }
11407
13841
  const run = getCurrentRun2(session);
11408
- const nativeId = run?.nativeSessionId ?? session.id;
11409
- const transcriptPath = harness.resolveTranscriptPath(nativeId, flintPath);
13842
+ let nativeId = run?.nativeSessionId ?? session.id;
13843
+ let transcriptPath = harness.resolveTranscriptPath(nativeId, flintPath);
11410
13844
  const maxLen = options.verbose ? Infinity : 200;
13845
+ if (!transcriptPath && !isTerminalStatus2(session.status)) {
13846
+ const deadline = Date.now() + 3e4;
13847
+ process.stdout.write(pc41.dim("Waiting for transcript path resolution..."));
13848
+ while (Date.now() <= deadline) {
13849
+ await new Promise((resolve11) => setTimeout(resolve11, 500));
13850
+ const fresh = resolveSession2(sessionsDir, id);
13851
+ if (!fresh) break;
13852
+ const freshRun = getCurrentRun2(fresh);
13853
+ const freshNativeId = freshRun?.nativeSessionId ?? fresh.id;
13854
+ transcriptPath = harness.resolveTranscriptPath(freshNativeId, flintPath);
13855
+ if (transcriptPath) {
13856
+ nativeId = freshNativeId;
13857
+ break;
13858
+ }
13859
+ }
13860
+ process.stdout.write("\r\x1B[2K");
13861
+ }
11411
13862
  if (!transcriptPath) {
11412
13863
  console.error(pc41.red(`Error: Could not resolve transcript path for session ${shortId2(session.id)}`));
11413
13864
  process.exit(1);
11414
13865
  }
11415
13866
  const watchTitle = session.title ? ` ${pc41.dim("\xB7")} ${session.title}` : "";
11416
- console.log(`${pc41.bold("Watching")} ${pc41.cyan(shortId2(session.id))} ${pc41.dim("\xB7")} ${session.runtime}${watchTitle} ${pc41.dim("\xB7")} ${statusIcon2(session.status)} ${session.status}`);
13867
+ const watchMeta = session.metadata && Object.keys(session.metadata).length > 0 ? ` ${pc41.dim("\xB7")} ${pc41.dim(`meta: ${typeof session.metadata.plate === "string" ? session.metadata.plate : Object.keys(session.metadata).length + " keys"}`)}` : "";
13868
+ console.log(`${pc41.bold("Watching")} ${pc41.cyan(shortId2(session.id))} ${pc41.dim("\xB7")} ${session.runtime}${watchTitle} ${pc41.dim("\xB7")} ${statusIcon2(session.status)} ${session.status}${watchMeta}`);
11417
13869
  console.log(pc41.dim(transcriptPath));
11418
13870
  console.log("");
11419
- if (!existsSync9(transcriptPath)) {
13871
+ if (!existsSync12(transcriptPath)) {
11420
13872
  process.stdout.write(pc41.dim("Waiting for transcript..."));
11421
13873
  await new Promise((resolve11, reject) => {
11422
13874
  const poll = setInterval(() => {
11423
- if (existsSync9(transcriptPath)) {
13875
+ if (existsSync12(transcriptPath)) {
11424
13876
  clearInterval(poll);
11425
13877
  process.stdout.write("\r\x1B[2K");
11426
13878
  resolve11();
@@ -11630,7 +14082,7 @@ orbCommand.command("ask").description("Ask a blocking question and wait for a re
11630
14082
  session.status = "blocked";
11631
14083
  writeSession(sessionsDir, session);
11632
14084
  try {
11633
- spawnSync4("osascript", ["-e", `display notification "${question.slice(0, 100)}" with title "OrbH Agent Needs Input"`], { stdio: "ignore" });
14085
+ spawnSync5("osascript", ["-e", `display notification "${question.slice(0, 100)}" with title "Orbh Agent Needs Input"`], { stdio: "ignore" });
11634
14086
  } catch {
11635
14087
  }
11636
14088
  const startTime = Date.now();
@@ -11664,7 +14116,7 @@ orbCommand.command("request").description("Post a deferred question and exit imm
11664
14116
  session.status = "deferred";
11665
14117
  writeSession(sessionsDir, session);
11666
14118
  try {
11667
- spawnSync4("osascript", ["-e", `display notification "${question.slice(0, 100)}" with title "OrbH Agent Needs Input"`], { stdio: "ignore" });
14119
+ spawnSync5("osascript", ["-e", `display notification "${question.slice(0, 100)}" with title "Orbh Agent Needs Input"`], { stdio: "ignore" });
11668
14120
  } catch {
11669
14121
  }
11670
14122
  console.log(`Question posted. Session ${shortId2(session.id)} is now deferred.`);
@@ -11700,7 +14152,7 @@ orbCommand.command("respond").description("Answer a pending question on a sessio
11700
14152
  console.log(`Response sent to session ${shortId2(session.id)}`);
11701
14153
  console.log(pc41.dim("Deferred question answered \u2014 auto-resuming session..."));
11702
14154
  const resumePrompt = `Your deferred question has been answered. Run \`flint orb requests ${session.id}\` to see the response, then continue working.`;
11703
- spawnSync4("flint", ["orb", "resume", session.id, resumePrompt], {
14155
+ spawnSync5("flint", ["orb", "resume", session.id, resumePrompt], {
11704
14156
  cwd: process.cwd(),
11705
14157
  stdio: "inherit"
11706
14158
  });
@@ -11713,24 +14165,24 @@ orbCommand.command("respond").description("Answer a pending question on a sessio
11713
14165
 
11714
14166
  // src/index.ts
11715
14167
  var __dirname3 = dirname4(fileURLToPath3(import.meta.url));
11716
- var pkg = JSON.parse(readFileSync5(join18(__dirname3, "..", "package.json"), "utf-8"));
14168
+ var pkg = JSON.parse(readFileSync10(join18(__dirname3, "..", "package.json"), "utf-8"));
11717
14169
  var runtime = resolveRuntimeSync({ cliname: "flint" });
11718
14170
  var devAvailable = runtime.mode === "dev";
11719
14171
  var newDir = getConfigDir("flint");
11720
- var oldDir = join18(homedir9(), ".flint");
11721
- var intermediateDir = join18(homedir9(), ".nuucognition", ".flint");
14172
+ var oldDir = join18(homedir10(), ".flint");
14173
+ var intermediateDir = join18(homedir10(), ".nuucognition", ".flint");
11722
14174
  function migrateDir(sourceDir, label) {
11723
- if (!existsSync10(sourceDir)) return false;
14175
+ if (!existsSync13(sourceDir)) return false;
11724
14176
  try {
11725
- const entries = readdirSync4(sourceDir);
14177
+ const entries = readdirSync7(sourceDir);
11726
14178
  const filesToMigrate = entries.filter((e) => !e.startsWith(".DS_Store"));
11727
14179
  if (filesToMigrate.length === 0) return false;
11728
- mkdirSync4(newDir, { recursive: true });
14180
+ mkdirSync5(newDir, { recursive: true });
11729
14181
  let migrated = 0;
11730
14182
  for (const entry of filesToMigrate) {
11731
14183
  const src = join18(sourceDir, entry);
11732
14184
  const dest = join18(newDir, entry);
11733
- if (!existsSync10(dest)) {
14185
+ if (!existsSync13(dest)) {
11734
14186
  cpSync(src, dest, { recursive: true });
11735
14187
  migrated++;
11736
14188
  }
@@ -11834,3 +14286,42 @@ program.on("command:*", (operands) => {
11834
14286
  process.exit(1);
11835
14287
  });
11836
14288
  await program.parseAsync(process.argv);
14289
+ /*! Bundled license information:
14290
+
14291
+ smol-toml/dist/error.js:
14292
+ smol-toml/dist/util.js:
14293
+ smol-toml/dist/date.js:
14294
+ smol-toml/dist/primitive.js:
14295
+ smol-toml/dist/extract.js:
14296
+ smol-toml/dist/struct.js:
14297
+ smol-toml/dist/parse.js:
14298
+ smol-toml/dist/stringify.js:
14299
+ smol-toml/dist/index.js:
14300
+ (*!
14301
+ * Copyright (c) Squirrel Chat et al., All rights reserved.
14302
+ * SPDX-License-Identifier: BSD-3-Clause
14303
+ *
14304
+ * Redistribution and use in source and binary forms, with or without
14305
+ * modification, are permitted provided that the following conditions are met:
14306
+ *
14307
+ * 1. Redistributions of source code must retain the above copyright notice, this
14308
+ * list of conditions and the following disclaimer.
14309
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
14310
+ * this list of conditions and the following disclaimer in the
14311
+ * documentation and/or other materials provided with the distribution.
14312
+ * 3. Neither the name of the copyright holder nor the names of its contributors
14313
+ * may be used to endorse or promote products derived from this software without
14314
+ * specific prior written permission.
14315
+ *
14316
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14317
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14318
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
14319
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
14320
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
14321
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
14322
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
14323
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
14324
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
14325
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14326
+ *)
14327
+ */