@kmmao/happy-agent 0.5.4 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  import { Command } from 'commander';
2
+ import { randomBytes, createCipheriv, createHash, createDecipheriv, createHmac, randomUUID as randomUUID$1 } from 'node:crypto';
2
3
  import { homedir, hostname } from 'node:os';
3
4
  import { join, dirname } from 'node:path';
4
5
  import { mkdirSync, writeFileSync, unlinkSync, readFileSync, appendFileSync } from 'node:fs';
5
- import { randomBytes, createCipheriv, createHash, createDecipheriv, createHmac } from 'node:crypto';
6
6
  import tweetnacl from 'tweetnacl';
7
7
  import axios, { AxiosError } from 'axios';
8
8
  import qrcode from 'qrcode-terminal';
@@ -16,8 +16,10 @@ import { join as join$1, resolve, dirname as dirname$1 } from 'path';
16
16
  import { realpathSync, readFileSync as readFileSync$1, mkdirSync as mkdirSync$1, writeFileSync as writeFileSync$1 } from 'fs';
17
17
  import { tmpdir } from 'os';
18
18
  import { createServer } from 'http';
19
+ import * as z from 'zod';
20
+ import { z as z$1 } from 'zod';
19
21
 
20
- var version = "0.5.4";
22
+ var version = "0.7.0";
21
23
 
22
24
  function loadConfig() {
23
25
  const serverUrl = (process.env.HAPPY_SERVER_URL ?? "https://s.sangreal.code.xycloud.info:2443").replace(/\/+$/, "");
@@ -226,7 +228,7 @@ async function authLogin(config, opts) {
226
228
  }
227
229
  const startTime = Date.now();
228
230
  while (Date.now() - startTime < AUTH_TIMEOUT_MS) {
229
- await sleep(POLL_INTERVAL_MS);
231
+ await sleep$1(POLL_INTERVAL_MS);
230
232
  let result;
231
233
  try {
232
234
  const resp = await axios.post(`${config.serverUrl}/v1/auth/account/request`, {
@@ -270,7 +272,7 @@ async function authStatus(config) {
270
272
  console.log("- Action: Run `happy-agent auth login` to authenticate.");
271
273
  }
272
274
  }
273
- function sleep(ms) {
275
+ function sleep$1(ms) {
274
276
  return new Promise((resolve) => setTimeout(resolve, ms));
275
277
  }
276
278
 
@@ -306,6 +308,7 @@ function decryptSession(raw, creds) {
306
308
  active: raw.active,
307
309
  activeAt: raw.activeAt,
308
310
  metadata: decryptField(raw.metadata, encryption),
311
+ metadataVersion: raw.metadataVersion,
309
312
  agentState: decryptField(raw.agentState, encryption),
310
313
  dataEncryptionKey: raw.dataEncryptionKey,
311
314
  encryption
@@ -1428,6 +1431,12 @@ class SessionClient extends EventEmitter {
1428
1431
  this.sessionId = opts.sessionId;
1429
1432
  this.encryptionKey = opts.encryptionKey;
1430
1433
  this.encryptionVariant = opts.encryptionVariant;
1434
+ if (opts.initialMetadata !== void 0) {
1435
+ this.metadata = opts.initialMetadata;
1436
+ }
1437
+ if (opts.initialMetadataVersion !== void 0) {
1438
+ this.metadataVersion = opts.initialMetadataVersion;
1439
+ }
1431
1440
  if (opts.initialAgentState !== void 0) {
1432
1441
  this.agentState = opts.initialAgentState;
1433
1442
  }
@@ -1480,6 +1489,9 @@ class SessionClient extends EventEmitter {
1480
1489
  getMetadata() {
1481
1490
  return this.metadata;
1482
1491
  }
1492
+ getMetadataVersion() {
1493
+ return this.metadataVersion;
1494
+ }
1483
1495
  getAgentState() {
1484
1496
  return this.agentState;
1485
1497
  }
@@ -1580,42 +1592,51 @@ class SessionClient extends EventEmitter {
1580
1592
  // -----------------------------------------------------------------------
1581
1593
  // New: OCC metadata/state updates
1582
1594
  // -----------------------------------------------------------------------
1583
- async updateMetadata(newMetadata) {
1595
+ async updateMetadataOnce(newMetadata) {
1584
1596
  const encrypted = encodeBase64(
1585
1597
  encrypt(this.encryptionKey, this.encryptionVariant, newMetadata)
1586
1598
  );
1587
- await withBackoff(
1588
- () => new Promise((resolve, reject) => {
1589
- this.socket.emit(
1590
- "update-metadata",
1591
- {
1592
- sid: this.sessionId,
1593
- expectedVersion: this.metadataVersion,
1594
- metadata: encrypted
1595
- },
1596
- (answer) => {
1597
- if (answer.result === "success" && answer.version !== void 0) {
1598
- this.metadataVersion = answer.version;
1599
- this.metadata = newMetadata;
1600
- resolve();
1601
- } else if (answer.result === "version-mismatch" && answer.version !== void 0) {
1602
- this.metadataVersion = answer.version;
1603
- if (answer.metadata) {
1604
- this.metadata = decrypt(
1605
- this.encryptionKey,
1606
- this.encryptionVariant,
1607
- decodeBase64(answer.metadata)
1608
- );
1609
- }
1610
- reject(new Error("version-mismatch"));
1611
- } else {
1612
- reject(new Error(`update-metadata failed: ${answer.result}`));
1599
+ await new Promise((resolve, reject) => {
1600
+ this.socket.emit(
1601
+ "update-metadata",
1602
+ {
1603
+ sid: this.sessionId,
1604
+ expectedVersion: this.metadataVersion,
1605
+ metadata: encrypted
1606
+ },
1607
+ (answer) => {
1608
+ if (answer.result === "success" && answer.version !== void 0) {
1609
+ this.metadataVersion = answer.version;
1610
+ this.metadata = newMetadata;
1611
+ resolve();
1612
+ } else if (answer.result === "version-mismatch" && answer.version !== void 0) {
1613
+ this.metadataVersion = answer.version;
1614
+ if (answer.metadata) {
1615
+ this.metadata = decrypt(
1616
+ this.encryptionKey,
1617
+ this.encryptionVariant,
1618
+ decodeBase64(answer.metadata)
1619
+ );
1613
1620
  }
1621
+ reject(new Error("version-mismatch"));
1622
+ } else {
1623
+ reject(new Error(`update-metadata failed: ${answer.result}`));
1614
1624
  }
1615
- );
1616
- }),
1617
- { maxRetries: 3, label: "updateMetadata" }
1618
- );
1625
+ }
1626
+ );
1627
+ });
1628
+ }
1629
+ async updateMetadata(newMetadata) {
1630
+ await withBackoff(() => this.updateMetadataOnce(newMetadata), {
1631
+ maxRetries: 3,
1632
+ label: "updateMetadata"
1633
+ });
1634
+ }
1635
+ async updateMetadataWith(handler) {
1636
+ await withBackoff(async () => {
1637
+ const updated = handler(this.metadata);
1638
+ await this.updateMetadataOnce(updated);
1639
+ }, { maxRetries: 3, label: "updateMetadataWith" });
1619
1640
  }
1620
1641
  async updateAgentState(newState) {
1621
1642
  const encrypted = newState !== null ? encodeBase64(encrypt(this.encryptionKey, this.encryptionVariant, newState)) : null;
@@ -2220,6 +2241,8 @@ function handleTaskTrigger(data, serverUrl, _authToken, scheduler) {
2220
2241
  approvedNewDirectoryCreation: true,
2221
2242
  automationContext: { kind: "task", trigger: "task-dispatch", projectId: data.projectId },
2222
2243
  environmentVariables: {
2244
+ // Profile-resolved env applied first so task-specific overrides win.
2245
+ ...data.runtimeProfile?.environmentVariables ?? {},
2223
2246
  HAPPY_INITIAL_PROMPT_FILE: promptFile,
2224
2247
  HAPPY_TASK_ID: data.taskId,
2225
2248
  HAPPY_TASK_PRIORITY: data.priority,
@@ -3428,9 +3451,2324 @@ function daemonStatus() {
3428
3451
  }
3429
3452
  }
3430
3453
 
3454
+ var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
3455
+
3456
+ var cuid2 = {};
3457
+
3458
+ var src = {};
3459
+
3460
+ var sha3 = {};
3461
+
3462
+ var _u64 = {};
3463
+
3464
+ var hasRequired_u64;
3465
+
3466
+ function require_u64 () {
3467
+ if (hasRequired_u64) return _u64;
3468
+ hasRequired_u64 = 1;
3469
+ Object.defineProperty(_u64, "__esModule", { value: true });
3470
+ _u64.toBig = _u64.shrSL = _u64.shrSH = _u64.rotrSL = _u64.rotrSH = _u64.rotrBL = _u64.rotrBH = _u64.rotr32L = _u64.rotr32H = _u64.rotlSL = _u64.rotlSH = _u64.rotlBL = _u64.rotlBH = _u64.add5L = _u64.add5H = _u64.add4L = _u64.add4H = _u64.add3L = _u64.add3H = void 0;
3471
+ _u64.add = add;
3472
+ _u64.fromBig = fromBig;
3473
+ _u64.split = split;
3474
+ const U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1);
3475
+ const _32n = /* @__PURE__ */ BigInt(32);
3476
+ function fromBig(n, le = false) {
3477
+ if (le)
3478
+ return { h: Number(n & U32_MASK64), l: Number(n >> _32n & U32_MASK64) };
3479
+ return { h: Number(n >> _32n & U32_MASK64) | 0, l: Number(n & U32_MASK64) | 0 };
3480
+ }
3481
+ function split(lst, le = false) {
3482
+ const len = lst.length;
3483
+ let Ah = new Uint32Array(len);
3484
+ let Al = new Uint32Array(len);
3485
+ for (let i = 0; i < len; i++) {
3486
+ const { h, l } = fromBig(lst[i], le);
3487
+ [Ah[i], Al[i]] = [h, l];
3488
+ }
3489
+ return [Ah, Al];
3490
+ }
3491
+ const toBig = (h, l) => BigInt(h >>> 0) << _32n | BigInt(l >>> 0);
3492
+ _u64.toBig = toBig;
3493
+ const shrSH = (h, _l, s) => h >>> s;
3494
+ _u64.shrSH = shrSH;
3495
+ const shrSL = (h, l, s) => h << 32 - s | l >>> s;
3496
+ _u64.shrSL = shrSL;
3497
+ const rotrSH = (h, l, s) => h >>> s | l << 32 - s;
3498
+ _u64.rotrSH = rotrSH;
3499
+ const rotrSL = (h, l, s) => h << 32 - s | l >>> s;
3500
+ _u64.rotrSL = rotrSL;
3501
+ const rotrBH = (h, l, s) => h << 64 - s | l >>> s - 32;
3502
+ _u64.rotrBH = rotrBH;
3503
+ const rotrBL = (h, l, s) => h >>> s - 32 | l << 64 - s;
3504
+ _u64.rotrBL = rotrBL;
3505
+ const rotr32H = (_h, l) => l;
3506
+ _u64.rotr32H = rotr32H;
3507
+ const rotr32L = (h, _l) => h;
3508
+ _u64.rotr32L = rotr32L;
3509
+ const rotlSH = (h, l, s) => h << s | l >>> 32 - s;
3510
+ _u64.rotlSH = rotlSH;
3511
+ const rotlSL = (h, l, s) => l << s | h >>> 32 - s;
3512
+ _u64.rotlSL = rotlSL;
3513
+ const rotlBH = (h, l, s) => l << s - 32 | h >>> 64 - s;
3514
+ _u64.rotlBH = rotlBH;
3515
+ const rotlBL = (h, l, s) => h << s - 32 | l >>> 64 - s;
3516
+ _u64.rotlBL = rotlBL;
3517
+ function add(Ah, Al, Bh, Bl) {
3518
+ const l = (Al >>> 0) + (Bl >>> 0);
3519
+ return { h: Ah + Bh + (l / 2 ** 32 | 0) | 0, l: l | 0 };
3520
+ }
3521
+ const add3L = (Al, Bl, Cl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0);
3522
+ _u64.add3L = add3L;
3523
+ const add3H = (low, Ah, Bh, Ch) => Ah + Bh + Ch + (low / 2 ** 32 | 0) | 0;
3524
+ _u64.add3H = add3H;
3525
+ const add4L = (Al, Bl, Cl, Dl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0);
3526
+ _u64.add4L = add4L;
3527
+ const add4H = (low, Ah, Bh, Ch, Dh) => Ah + Bh + Ch + Dh + (low / 2 ** 32 | 0) | 0;
3528
+ _u64.add4H = add4H;
3529
+ const add5L = (Al, Bl, Cl, Dl, El) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0) + (El >>> 0);
3530
+ _u64.add5L = add5L;
3531
+ const add5H = (low, Ah, Bh, Ch, Dh, Eh) => Ah + Bh + Ch + Dh + Eh + (low / 2 ** 32 | 0) | 0;
3532
+ _u64.add5H = add5H;
3533
+ const u64 = {
3534
+ fromBig,
3535
+ split,
3536
+ toBig,
3537
+ shrSH,
3538
+ shrSL,
3539
+ rotrSH,
3540
+ rotrSL,
3541
+ rotrBH,
3542
+ rotrBL,
3543
+ rotr32H,
3544
+ rotr32L,
3545
+ rotlSH,
3546
+ rotlSL,
3547
+ rotlBH,
3548
+ rotlBL,
3549
+ add,
3550
+ add3L,
3551
+ add3H,
3552
+ add4L,
3553
+ add4H,
3554
+ add5H,
3555
+ add5L
3556
+ };
3557
+ _u64.default = u64;
3558
+ return _u64;
3559
+ }
3560
+
3561
+ var utils = {};
3562
+
3563
+ var crypto = {};
3564
+
3565
+ var hasRequiredCrypto;
3566
+
3567
+ function requireCrypto () {
3568
+ if (hasRequiredCrypto) return crypto;
3569
+ hasRequiredCrypto = 1;
3570
+ Object.defineProperty(crypto, "__esModule", { value: true });
3571
+ crypto.crypto = void 0;
3572
+ crypto.crypto = typeof globalThis === "object" && "crypto" in globalThis ? globalThis.crypto : void 0;
3573
+ return crypto;
3574
+ }
3575
+
3576
+ var hasRequiredUtils;
3577
+
3578
+ function requireUtils () {
3579
+ if (hasRequiredUtils) return utils;
3580
+ hasRequiredUtils = 1;
3581
+ (function (exports$1) {
3582
+ /*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */
3583
+ Object.defineProperty(exports$1, "__esModule", { value: true });
3584
+ exports$1.wrapXOFConstructorWithOpts = exports$1.wrapConstructorWithOpts = exports$1.wrapConstructor = exports$1.Hash = exports$1.nextTick = exports$1.swap32IfBE = exports$1.byteSwapIfBE = exports$1.swap8IfBE = exports$1.isLE = void 0;
3585
+ exports$1.isBytes = isBytes;
3586
+ exports$1.anumber = anumber;
3587
+ exports$1.abytes = abytes;
3588
+ exports$1.ahash = ahash;
3589
+ exports$1.aexists = aexists;
3590
+ exports$1.aoutput = aoutput;
3591
+ exports$1.u8 = u8;
3592
+ exports$1.u32 = u32;
3593
+ exports$1.clean = clean;
3594
+ exports$1.createView = createView;
3595
+ exports$1.rotr = rotr;
3596
+ exports$1.rotl = rotl;
3597
+ exports$1.byteSwap = byteSwap;
3598
+ exports$1.byteSwap32 = byteSwap32;
3599
+ exports$1.bytesToHex = bytesToHex;
3600
+ exports$1.hexToBytes = hexToBytes;
3601
+ exports$1.asyncLoop = asyncLoop;
3602
+ exports$1.utf8ToBytes = utf8ToBytes;
3603
+ exports$1.bytesToUtf8 = bytesToUtf8;
3604
+ exports$1.toBytes = toBytes;
3605
+ exports$1.kdfInputToBytes = kdfInputToBytes;
3606
+ exports$1.concatBytes = concatBytes;
3607
+ exports$1.checkOpts = checkOpts;
3608
+ exports$1.createHasher = createHasher;
3609
+ exports$1.createOptHasher = createOptHasher;
3610
+ exports$1.createXOFer = createXOFer;
3611
+ exports$1.randomBytes = randomBytes;
3612
+ const crypto_1 = requireCrypto();
3613
+ function isBytes(a) {
3614
+ return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
3615
+ }
3616
+ function anumber(n) {
3617
+ if (!Number.isSafeInteger(n) || n < 0)
3618
+ throw new Error("positive integer expected, got " + n);
3619
+ }
3620
+ function abytes(b, ...lengths) {
3621
+ if (!isBytes(b))
3622
+ throw new Error("Uint8Array expected");
3623
+ if (lengths.length > 0 && !lengths.includes(b.length))
3624
+ throw new Error("Uint8Array expected of length " + lengths + ", got length=" + b.length);
3625
+ }
3626
+ function ahash(h) {
3627
+ if (typeof h !== "function" || typeof h.create !== "function")
3628
+ throw new Error("Hash should be wrapped by utils.createHasher");
3629
+ anumber(h.outputLen);
3630
+ anumber(h.blockLen);
3631
+ }
3632
+ function aexists(instance, checkFinished = true) {
3633
+ if (instance.destroyed)
3634
+ throw new Error("Hash instance has been destroyed");
3635
+ if (checkFinished && instance.finished)
3636
+ throw new Error("Hash#digest() has already been called");
3637
+ }
3638
+ function aoutput(out, instance) {
3639
+ abytes(out);
3640
+ const min = instance.outputLen;
3641
+ if (out.length < min) {
3642
+ throw new Error("digestInto() expects output buffer of length at least " + min);
3643
+ }
3644
+ }
3645
+ function u8(arr) {
3646
+ return new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);
3647
+ }
3648
+ function u32(arr) {
3649
+ return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));
3650
+ }
3651
+ function clean(...arrays) {
3652
+ for (let i = 0; i < arrays.length; i++) {
3653
+ arrays[i].fill(0);
3654
+ }
3655
+ }
3656
+ function createView(arr) {
3657
+ return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
3658
+ }
3659
+ function rotr(word, shift) {
3660
+ return word << 32 - shift | word >>> shift;
3661
+ }
3662
+ function rotl(word, shift) {
3663
+ return word << shift | word >>> 32 - shift >>> 0;
3664
+ }
3665
+ exports$1.isLE = (() => new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68)();
3666
+ function byteSwap(word) {
3667
+ return word << 24 & 4278190080 | word << 8 & 16711680 | word >>> 8 & 65280 | word >>> 24 & 255;
3668
+ }
3669
+ exports$1.swap8IfBE = exports$1.isLE ? (n) => n : (n) => byteSwap(n);
3670
+ exports$1.byteSwapIfBE = exports$1.swap8IfBE;
3671
+ function byteSwap32(arr) {
3672
+ for (let i = 0; i < arr.length; i++) {
3673
+ arr[i] = byteSwap(arr[i]);
3674
+ }
3675
+ return arr;
3676
+ }
3677
+ exports$1.swap32IfBE = exports$1.isLE ? (u) => u : byteSwap32;
3678
+ const hasHexBuiltin = /* @__PURE__ */ (() => (
3679
+ // @ts-ignore
3680
+ typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function"
3681
+ ))();
3682
+ const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
3683
+ function bytesToHex(bytes) {
3684
+ abytes(bytes);
3685
+ if (hasHexBuiltin)
3686
+ return bytes.toHex();
3687
+ let hex = "";
3688
+ for (let i = 0; i < bytes.length; i++) {
3689
+ hex += hexes[bytes[i]];
3690
+ }
3691
+ return hex;
3692
+ }
3693
+ const asciis = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 };
3694
+ function asciiToBase16(ch) {
3695
+ if (ch >= asciis._0 && ch <= asciis._9)
3696
+ return ch - asciis._0;
3697
+ if (ch >= asciis.A && ch <= asciis.F)
3698
+ return ch - (asciis.A - 10);
3699
+ if (ch >= asciis.a && ch <= asciis.f)
3700
+ return ch - (asciis.a - 10);
3701
+ return;
3702
+ }
3703
+ function hexToBytes(hex) {
3704
+ if (typeof hex !== "string")
3705
+ throw new Error("hex string expected, got " + typeof hex);
3706
+ if (hasHexBuiltin)
3707
+ return Uint8Array.fromHex(hex);
3708
+ const hl = hex.length;
3709
+ const al = hl / 2;
3710
+ if (hl % 2)
3711
+ throw new Error("hex string expected, got unpadded hex of length " + hl);
3712
+ const array = new Uint8Array(al);
3713
+ for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {
3714
+ const n1 = asciiToBase16(hex.charCodeAt(hi));
3715
+ const n2 = asciiToBase16(hex.charCodeAt(hi + 1));
3716
+ if (n1 === void 0 || n2 === void 0) {
3717
+ const char = hex[hi] + hex[hi + 1];
3718
+ throw new Error('hex string expected, got non-hex character "' + char + '" at index ' + hi);
3719
+ }
3720
+ array[ai] = n1 * 16 + n2;
3721
+ }
3722
+ return array;
3723
+ }
3724
+ const nextTick = async () => {
3725
+ };
3726
+ exports$1.nextTick = nextTick;
3727
+ async function asyncLoop(iters, tick, cb) {
3728
+ let ts = Date.now();
3729
+ for (let i = 0; i < iters; i++) {
3730
+ cb(i);
3731
+ const diff = Date.now() - ts;
3732
+ if (diff >= 0 && diff < tick)
3733
+ continue;
3734
+ await (0, exports$1.nextTick)();
3735
+ ts += diff;
3736
+ }
3737
+ }
3738
+ function utf8ToBytes(str) {
3739
+ if (typeof str !== "string")
3740
+ throw new Error("string expected");
3741
+ return new Uint8Array(new TextEncoder().encode(str));
3742
+ }
3743
+ function bytesToUtf8(bytes) {
3744
+ return new TextDecoder().decode(bytes);
3745
+ }
3746
+ function toBytes(data) {
3747
+ if (typeof data === "string")
3748
+ data = utf8ToBytes(data);
3749
+ abytes(data);
3750
+ return data;
3751
+ }
3752
+ function kdfInputToBytes(data) {
3753
+ if (typeof data === "string")
3754
+ data = utf8ToBytes(data);
3755
+ abytes(data);
3756
+ return data;
3757
+ }
3758
+ function concatBytes(...arrays) {
3759
+ let sum = 0;
3760
+ for (let i = 0; i < arrays.length; i++) {
3761
+ const a = arrays[i];
3762
+ abytes(a);
3763
+ sum += a.length;
3764
+ }
3765
+ const res = new Uint8Array(sum);
3766
+ for (let i = 0, pad = 0; i < arrays.length; i++) {
3767
+ const a = arrays[i];
3768
+ res.set(a, pad);
3769
+ pad += a.length;
3770
+ }
3771
+ return res;
3772
+ }
3773
+ function checkOpts(defaults, opts) {
3774
+ if (opts !== void 0 && {}.toString.call(opts) !== "[object Object]")
3775
+ throw new Error("options should be object or undefined");
3776
+ const merged = Object.assign(defaults, opts);
3777
+ return merged;
3778
+ }
3779
+ class Hash {
3780
+ }
3781
+ exports$1.Hash = Hash;
3782
+ function createHasher(hashCons) {
3783
+ const hashC = (msg) => hashCons().update(toBytes(msg)).digest();
3784
+ const tmp = hashCons();
3785
+ hashC.outputLen = tmp.outputLen;
3786
+ hashC.blockLen = tmp.blockLen;
3787
+ hashC.create = () => hashCons();
3788
+ return hashC;
3789
+ }
3790
+ function createOptHasher(hashCons) {
3791
+ const hashC = (msg, opts) => hashCons(opts).update(toBytes(msg)).digest();
3792
+ const tmp = hashCons({});
3793
+ hashC.outputLen = tmp.outputLen;
3794
+ hashC.blockLen = tmp.blockLen;
3795
+ hashC.create = (opts) => hashCons(opts);
3796
+ return hashC;
3797
+ }
3798
+ function createXOFer(hashCons) {
3799
+ const hashC = (msg, opts) => hashCons(opts).update(toBytes(msg)).digest();
3800
+ const tmp = hashCons({});
3801
+ hashC.outputLen = tmp.outputLen;
3802
+ hashC.blockLen = tmp.blockLen;
3803
+ hashC.create = (opts) => hashCons(opts);
3804
+ return hashC;
3805
+ }
3806
+ exports$1.wrapConstructor = createHasher;
3807
+ exports$1.wrapConstructorWithOpts = createOptHasher;
3808
+ exports$1.wrapXOFConstructorWithOpts = createXOFer;
3809
+ function randomBytes(bytesLength = 32) {
3810
+ if (crypto_1.crypto && typeof crypto_1.crypto.getRandomValues === "function") {
3811
+ return crypto_1.crypto.getRandomValues(new Uint8Array(bytesLength));
3812
+ }
3813
+ if (crypto_1.crypto && typeof crypto_1.crypto.randomBytes === "function") {
3814
+ return Uint8Array.from(crypto_1.crypto.randomBytes(bytesLength));
3815
+ }
3816
+ throw new Error("crypto.getRandomValues must be defined");
3817
+ }
3818
+ } (utils));
3819
+ return utils;
3820
+ }
3821
+
3822
+ var hasRequiredSha3;
3823
+
3824
+ function requireSha3 () {
3825
+ if (hasRequiredSha3) return sha3;
3826
+ hasRequiredSha3 = 1;
3827
+ Object.defineProperty(sha3, "__esModule", { value: true });
3828
+ sha3.shake256 = sha3.shake128 = sha3.keccak_512 = sha3.keccak_384 = sha3.keccak_256 = sha3.keccak_224 = sha3.sha3_512 = sha3.sha3_384 = sha3.sha3_256 = sha3.sha3_224 = sha3.Keccak = void 0;
3829
+ sha3.keccakP = keccakP;
3830
+ const _u64_ts_1 = /*@__PURE__*/ require_u64();
3831
+ const utils_ts_1 = /*@__PURE__*/ requireUtils();
3832
+ const _0n = BigInt(0);
3833
+ const _1n = BigInt(1);
3834
+ const _2n = BigInt(2);
3835
+ const _7n = BigInt(7);
3836
+ const _256n = BigInt(256);
3837
+ const _0x71n = BigInt(113);
3838
+ const SHA3_PI = [];
3839
+ const SHA3_ROTL = [];
3840
+ const _SHA3_IOTA = [];
3841
+ for (let round = 0, R = _1n, x = 1, y = 0; round < 24; round++) {
3842
+ [x, y] = [y, (2 * x + 3 * y) % 5];
3843
+ SHA3_PI.push(2 * (5 * y + x));
3844
+ SHA3_ROTL.push((round + 1) * (round + 2) / 2 % 64);
3845
+ let t = _0n;
3846
+ for (let j = 0; j < 7; j++) {
3847
+ R = (R << _1n ^ (R >> _7n) * _0x71n) % _256n;
3848
+ if (R & _2n)
3849
+ t ^= _1n << (_1n << /* @__PURE__ */ BigInt(j)) - _1n;
3850
+ }
3851
+ _SHA3_IOTA.push(t);
3852
+ }
3853
+ const IOTAS = (0, _u64_ts_1.split)(_SHA3_IOTA, true);
3854
+ const SHA3_IOTA_H = IOTAS[0];
3855
+ const SHA3_IOTA_L = IOTAS[1];
3856
+ const rotlH = (h, l, s) => s > 32 ? (0, _u64_ts_1.rotlBH)(h, l, s) : (0, _u64_ts_1.rotlSH)(h, l, s);
3857
+ const rotlL = (h, l, s) => s > 32 ? (0, _u64_ts_1.rotlBL)(h, l, s) : (0, _u64_ts_1.rotlSL)(h, l, s);
3858
+ function keccakP(s, rounds = 24) {
3859
+ const B = new Uint32Array(5 * 2);
3860
+ for (let round = 24 - rounds; round < 24; round++) {
3861
+ for (let x = 0; x < 10; x++)
3862
+ B[x] = s[x] ^ s[x + 10] ^ s[x + 20] ^ s[x + 30] ^ s[x + 40];
3863
+ for (let x = 0; x < 10; x += 2) {
3864
+ const idx1 = (x + 8) % 10;
3865
+ const idx0 = (x + 2) % 10;
3866
+ const B0 = B[idx0];
3867
+ const B1 = B[idx0 + 1];
3868
+ const Th = rotlH(B0, B1, 1) ^ B[idx1];
3869
+ const Tl = rotlL(B0, B1, 1) ^ B[idx1 + 1];
3870
+ for (let y = 0; y < 50; y += 10) {
3871
+ s[x + y] ^= Th;
3872
+ s[x + y + 1] ^= Tl;
3873
+ }
3874
+ }
3875
+ let curH = s[2];
3876
+ let curL = s[3];
3877
+ for (let t = 0; t < 24; t++) {
3878
+ const shift = SHA3_ROTL[t];
3879
+ const Th = rotlH(curH, curL, shift);
3880
+ const Tl = rotlL(curH, curL, shift);
3881
+ const PI = SHA3_PI[t];
3882
+ curH = s[PI];
3883
+ curL = s[PI + 1];
3884
+ s[PI] = Th;
3885
+ s[PI + 1] = Tl;
3886
+ }
3887
+ for (let y = 0; y < 50; y += 10) {
3888
+ for (let x = 0; x < 10; x++)
3889
+ B[x] = s[y + x];
3890
+ for (let x = 0; x < 10; x++)
3891
+ s[y + x] ^= ~B[(x + 2) % 10] & B[(x + 4) % 10];
3892
+ }
3893
+ s[0] ^= SHA3_IOTA_H[round];
3894
+ s[1] ^= SHA3_IOTA_L[round];
3895
+ }
3896
+ (0, utils_ts_1.clean)(B);
3897
+ }
3898
+ class Keccak extends utils_ts_1.Hash {
3899
+ // NOTE: we accept arguments in bytes instead of bits here.
3900
+ constructor(blockLen, suffix, outputLen, enableXOF = false, rounds = 24) {
3901
+ super();
3902
+ this.pos = 0;
3903
+ this.posOut = 0;
3904
+ this.finished = false;
3905
+ this.destroyed = false;
3906
+ this.enableXOF = false;
3907
+ this.blockLen = blockLen;
3908
+ this.suffix = suffix;
3909
+ this.outputLen = outputLen;
3910
+ this.enableXOF = enableXOF;
3911
+ this.rounds = rounds;
3912
+ (0, utils_ts_1.anumber)(outputLen);
3913
+ if (!(0 < blockLen && blockLen < 200))
3914
+ throw new Error("only keccak-f1600 function is supported");
3915
+ this.state = new Uint8Array(200);
3916
+ this.state32 = (0, utils_ts_1.u32)(this.state);
3917
+ }
3918
+ clone() {
3919
+ return this._cloneInto();
3920
+ }
3921
+ keccak() {
3922
+ (0, utils_ts_1.swap32IfBE)(this.state32);
3923
+ keccakP(this.state32, this.rounds);
3924
+ (0, utils_ts_1.swap32IfBE)(this.state32);
3925
+ this.posOut = 0;
3926
+ this.pos = 0;
3927
+ }
3928
+ update(data) {
3929
+ (0, utils_ts_1.aexists)(this);
3930
+ data = (0, utils_ts_1.toBytes)(data);
3931
+ (0, utils_ts_1.abytes)(data);
3932
+ const { blockLen, state } = this;
3933
+ const len = data.length;
3934
+ for (let pos = 0; pos < len; ) {
3935
+ const take = Math.min(blockLen - this.pos, len - pos);
3936
+ for (let i = 0; i < take; i++)
3937
+ state[this.pos++] ^= data[pos++];
3938
+ if (this.pos === blockLen)
3939
+ this.keccak();
3940
+ }
3941
+ return this;
3942
+ }
3943
+ finish() {
3944
+ if (this.finished)
3945
+ return;
3946
+ this.finished = true;
3947
+ const { state, suffix, pos, blockLen } = this;
3948
+ state[pos] ^= suffix;
3949
+ if ((suffix & 128) !== 0 && pos === blockLen - 1)
3950
+ this.keccak();
3951
+ state[blockLen - 1] ^= 128;
3952
+ this.keccak();
3953
+ }
3954
+ writeInto(out) {
3955
+ (0, utils_ts_1.aexists)(this, false);
3956
+ (0, utils_ts_1.abytes)(out);
3957
+ this.finish();
3958
+ const bufferOut = this.state;
3959
+ const { blockLen } = this;
3960
+ for (let pos = 0, len = out.length; pos < len; ) {
3961
+ if (this.posOut >= blockLen)
3962
+ this.keccak();
3963
+ const take = Math.min(blockLen - this.posOut, len - pos);
3964
+ out.set(bufferOut.subarray(this.posOut, this.posOut + take), pos);
3965
+ this.posOut += take;
3966
+ pos += take;
3967
+ }
3968
+ return out;
3969
+ }
3970
+ xofInto(out) {
3971
+ if (!this.enableXOF)
3972
+ throw new Error("XOF is not possible for this instance");
3973
+ return this.writeInto(out);
3974
+ }
3975
+ xof(bytes) {
3976
+ (0, utils_ts_1.anumber)(bytes);
3977
+ return this.xofInto(new Uint8Array(bytes));
3978
+ }
3979
+ digestInto(out) {
3980
+ (0, utils_ts_1.aoutput)(out, this);
3981
+ if (this.finished)
3982
+ throw new Error("digest() was already called");
3983
+ this.writeInto(out);
3984
+ this.destroy();
3985
+ return out;
3986
+ }
3987
+ digest() {
3988
+ return this.digestInto(new Uint8Array(this.outputLen));
3989
+ }
3990
+ destroy() {
3991
+ this.destroyed = true;
3992
+ (0, utils_ts_1.clean)(this.state);
3993
+ }
3994
+ _cloneInto(to) {
3995
+ const { blockLen, suffix, outputLen, rounds, enableXOF } = this;
3996
+ to || (to = new Keccak(blockLen, suffix, outputLen, enableXOF, rounds));
3997
+ to.state32.set(this.state32);
3998
+ to.pos = this.pos;
3999
+ to.posOut = this.posOut;
4000
+ to.finished = this.finished;
4001
+ to.rounds = rounds;
4002
+ to.suffix = suffix;
4003
+ to.outputLen = outputLen;
4004
+ to.enableXOF = enableXOF;
4005
+ to.destroyed = this.destroyed;
4006
+ return to;
4007
+ }
4008
+ }
4009
+ sha3.Keccak = Keccak;
4010
+ const gen = (suffix, blockLen, outputLen) => (0, utils_ts_1.createHasher)(() => new Keccak(blockLen, suffix, outputLen));
4011
+ sha3.sha3_224 = (() => gen(6, 144, 224 / 8))();
4012
+ sha3.sha3_256 = (() => gen(6, 136, 256 / 8))();
4013
+ sha3.sha3_384 = (() => gen(6, 104, 384 / 8))();
4014
+ sha3.sha3_512 = (() => gen(6, 72, 512 / 8))();
4015
+ sha3.keccak_224 = (() => gen(1, 144, 224 / 8))();
4016
+ sha3.keccak_256 = (() => gen(1, 136, 256 / 8))();
4017
+ sha3.keccak_384 = (() => gen(1, 104, 384 / 8))();
4018
+ sha3.keccak_512 = (() => gen(1, 72, 512 / 8))();
4019
+ const genShake = (suffix, blockLen, outputLen) => (0, utils_ts_1.createXOFer)((opts = {}) => new Keccak(blockLen, suffix, opts.dkLen === void 0 ? outputLen : opts.dkLen, true));
4020
+ sha3.shake128 = (() => genShake(31, 168, 128 / 8))();
4021
+ sha3.shake256 = (() => genShake(31, 136, 256 / 8))();
4022
+ return sha3;
4023
+ }
4024
+
4025
+ var hasRequiredSrc;
4026
+
4027
+ function requireSrc () {
4028
+ if (hasRequiredSrc) return src;
4029
+ hasRequiredSrc = 1;
4030
+ const { sha3_512: sha3 } = /*@__PURE__*/ requireSha3();
4031
+ const defaultLength = 24;
4032
+ const bigLength = 32;
4033
+ const createEntropy = (length = 4, random = Math.random) => {
4034
+ let entropy = "";
4035
+ while (entropy.length < length) {
4036
+ entropy = entropy + Math.floor(random() * 36).toString(36);
4037
+ }
4038
+ return entropy;
4039
+ };
4040
+ function bufToBigInt(buf) {
4041
+ let bits = 8n;
4042
+ let value = 0n;
4043
+ for (const i of buf.values()) {
4044
+ const bi = BigInt(i);
4045
+ value = (value << bits) + bi;
4046
+ }
4047
+ return value;
4048
+ }
4049
+ const hash = (input = "") => {
4050
+ return bufToBigInt(sha3(input)).toString(36).slice(1);
4051
+ };
4052
+ const alphabet = Array.from(
4053
+ { length: 26 },
4054
+ (x, i) => String.fromCharCode(i + 97)
4055
+ );
4056
+ const randomLetter = (random) => alphabet[Math.floor(random() * alphabet.length)];
4057
+ const createFingerprint = ({
4058
+ globalObj = typeof commonjsGlobal !== "undefined" ? commonjsGlobal : typeof window !== "undefined" ? window : {},
4059
+ random = Math.random
4060
+ } = {}) => {
4061
+ const globals = Object.keys(globalObj).toString();
4062
+ const sourceString = globals.length ? globals + createEntropy(bigLength, random) : createEntropy(bigLength, random);
4063
+ return hash(sourceString).substring(0, bigLength);
4064
+ };
4065
+ const createCounter = (count) => () => {
4066
+ return count++;
4067
+ };
4068
+ const initialCountMax = 476782367;
4069
+ const init = ({
4070
+ // Fallback if the user does not pass in a CSPRNG. This should be OK
4071
+ // because we don't rely solely on the random number generator for entropy.
4072
+ // We also use the host fingerprint, current time, and a session counter.
4073
+ random = Math.random,
4074
+ counter = createCounter(Math.floor(random() * initialCountMax)),
4075
+ length = defaultLength,
4076
+ fingerprint = createFingerprint({ random })
4077
+ } = {}) => {
4078
+ return function cuid2() {
4079
+ const firstLetter = randomLetter(random);
4080
+ const time = Date.now().toString(36);
4081
+ const count = counter().toString(36);
4082
+ const salt = createEntropy(length, random);
4083
+ const hashInput = `${time + salt + count + fingerprint}`;
4084
+ return `${firstLetter + hash(hashInput).substring(1, length)}`;
4085
+ };
4086
+ };
4087
+ const createId = init();
4088
+ const isCuid = (id, { minLength = 2, maxLength = bigLength } = {}) => {
4089
+ const length = id.length;
4090
+ const regex = /^[0-9a-z]+$/;
4091
+ try {
4092
+ if (typeof id === "string" && length >= minLength && length <= maxLength && regex.test(id))
4093
+ return true;
4094
+ } finally {
4095
+ }
4096
+ return false;
4097
+ };
4098
+ src.getConstants = () => ({ defaultLength, bigLength });
4099
+ src.init = init;
4100
+ src.createId = createId;
4101
+ src.bufToBigInt = bufToBigInt;
4102
+ src.createCounter = createCounter;
4103
+ src.createFingerprint = createFingerprint;
4104
+ src.isCuid = isCuid;
4105
+ return src;
4106
+ }
4107
+
4108
+ var hasRequiredCuid2;
4109
+
4110
+ function requireCuid2 () {
4111
+ if (hasRequiredCuid2) return cuid2;
4112
+ hasRequiredCuid2 = 1;
4113
+ const { createId, init, getConstants, isCuid } = requireSrc();
4114
+ cuid2.createId = createId;
4115
+ cuid2.init = init;
4116
+ cuid2.getConstants = getConstants;
4117
+ cuid2.isCuid = isCuid;
4118
+ return cuid2;
4119
+ }
4120
+
4121
+ var cuid2Exports = requireCuid2();
4122
+
4123
+ const sessionRoleSchema = z.enum(["user", "agent"]);
4124
+ const sessionTextEventSchema = z.object({
4125
+ t: z.literal("text"),
4126
+ text: z.string(),
4127
+ thinking: z.boolean().optional()
4128
+ });
4129
+ const sessionTextDeltaEventSchema = z.object({
4130
+ t: z.literal("text-delta"),
4131
+ stream: z.string(),
4132
+ delta: z.string(),
4133
+ thinking: z.boolean().optional()
4134
+ });
4135
+ const sessionServiceMessageEventSchema = z.object({
4136
+ t: z.literal("service"),
4137
+ text: z.string()
4138
+ });
4139
+ const sessionToolCallStartEventSchema = z.object({
4140
+ t: z.literal("tool-call-start"),
4141
+ call: z.string(),
4142
+ name: z.string(),
4143
+ title: z.string(),
4144
+ description: z.string(),
4145
+ args: z.record(z.string(), z.unknown())
4146
+ });
4147
+ const sessionToolCallEndEventSchema = z.object({
4148
+ t: z.literal("tool-call-end"),
4149
+ call: z.string(),
4150
+ /** Background task ID when Bash command runs with run_in_background */
4151
+ backgroundTaskId: z.string().optional(),
4152
+ /** Path to the task output file on the CLI machine */
4153
+ outputFile: z.string().optional()
4154
+ });
4155
+ const sessionFileEventSchema = z.object({
4156
+ t: z.literal("file"),
4157
+ ref: z.string(),
4158
+ name: z.string(),
4159
+ size: z.number(),
4160
+ image: z.object({
4161
+ width: z.number(),
4162
+ height: z.number(),
4163
+ thumbhash: z.string()
4164
+ }).optional()
4165
+ });
4166
+ const sessionTurnStartEventSchema = z.object({
4167
+ t: z.literal("turn-start")
4168
+ });
4169
+ const sessionStartEventSchema = z.object({
4170
+ t: z.literal("start"),
4171
+ title: z.string().optional()
4172
+ });
4173
+ const sessionTurnEndStatusSchema = z.enum([
4174
+ "completed",
4175
+ "failed",
4176
+ "cancelled"
4177
+ ]);
4178
+ const sessionModelUsageSchema = z.object({
4179
+ inputTokens: z.number(),
4180
+ outputTokens: z.number(),
4181
+ cacheReadInputTokens: z.number(),
4182
+ cacheCreationInputTokens: z.number(),
4183
+ costUSD: z.number(),
4184
+ contextWindow: z.number(),
4185
+ maxOutputTokens: z.number()
4186
+ });
4187
+ const sessionTurnEndEventSchema = z.object({
4188
+ t: z.literal("turn-end"),
4189
+ status: sessionTurnEndStatusSchema,
4190
+ model: z.string().optional(),
4191
+ usage: z.object({
4192
+ input_tokens: z.number(),
4193
+ output_tokens: z.number(),
4194
+ cache_creation_input_tokens: z.number().optional(),
4195
+ cache_read_input_tokens: z.number().optional()
4196
+ }).optional(),
4197
+ durationMs: z.number().optional(),
4198
+ totalCostUsd: z.number().optional(),
4199
+ numTurns: z.number().optional(),
4200
+ modelUsage: z.record(z.string(), sessionModelUsageSchema).optional()
4201
+ });
4202
+ const sessionStopEventSchema = z.object({
4203
+ t: z.literal("stop")
4204
+ });
4205
+ const sessionUsageUpdateEventSchema = z.object({
4206
+ t: z.literal("usage-update"),
4207
+ model: z.string().optional(),
4208
+ usage: z.object({
4209
+ input_tokens: z.number(),
4210
+ output_tokens: z.number(),
4211
+ cache_creation_input_tokens: z.number().optional(),
4212
+ cache_read_input_tokens: z.number().optional()
4213
+ }),
4214
+ durationMs: z.number().optional()
4215
+ });
4216
+ const sessionTaskStartEventSchema = z.object({
4217
+ t: z.literal("task-start"),
4218
+ taskId: z.string(),
4219
+ toolUseId: z.string().optional(),
4220
+ description: z.string(),
4221
+ taskType: z.string().optional(),
4222
+ /** meta.name from the workflow script (e.g. 'spec'). Only set when taskType is 'local_workflow'. */
4223
+ workflowName: z.string().optional()
4224
+ });
4225
+ const sessionTaskProgressEventSchema = z.object({
4226
+ t: z.literal("task-progress"),
4227
+ taskId: z.string(),
4228
+ description: z.string(),
4229
+ usage: z.object({
4230
+ totalTokens: z.number(),
4231
+ toolUses: z.number(),
4232
+ durationMs: z.number()
4233
+ }).optional(),
4234
+ lastToolName: z.string().optional(),
4235
+ /** AI-generated progress summary (~30s interval, from agentProgressSummaries) */
4236
+ summary: z.string().optional()
4237
+ });
4238
+ const sessionTaskEndEventSchema = z.object({
4239
+ t: z.literal("task-end"),
4240
+ taskId: z.string(),
4241
+ status: z.enum(["completed", "failed", "stopped"]),
4242
+ summary: z.string(),
4243
+ usage: z.object({
4244
+ totalTokens: z.number(),
4245
+ toolUses: z.number(),
4246
+ durationMs: z.number()
4247
+ }).optional()
4248
+ });
4249
+ const sessionToolProgressEventSchema = z.object({
4250
+ t: z.literal("tool-progress"),
4251
+ toolUseId: z.string(),
4252
+ toolName: z.string(),
4253
+ elapsedSeconds: z.number(),
4254
+ taskId: z.string().optional()
4255
+ });
4256
+ const sessionPromptSuggestionEventSchema = z.object({
4257
+ t: z.literal("prompt-suggestion"),
4258
+ suggestion: z.string()
4259
+ });
4260
+ const sessionNeedsContinueEventSchema = z.object({
4261
+ t: z.literal("needs-continue")
4262
+ });
4263
+ const sessionStateChangedEventSchema = z.object({
4264
+ t: z.literal("session-state-changed"),
4265
+ /** Authoritative session lifecycle state from the SDK */
4266
+ state: z.enum(["idle", "running", "requires_action"])
4267
+ });
4268
+ const sessionContextUsageCategorySchema = z.object({
4269
+ name: z.string(),
4270
+ tokens: z.number(),
4271
+ color: z.string().optional()
4272
+ });
4273
+ const sessionTaskLogEventSchema = z.object({
4274
+ t: z.literal("task-log"),
4275
+ /** Background task ID or tool call ID that owns this log stream */
4276
+ taskId: z.string(),
4277
+ /** Path to the output file on the CLI machine */
4278
+ outputFile: z.string(),
4279
+ /** Incremental log content (new lines since last push) */
4280
+ chunk: z.string(),
4281
+ /** Byte offset in the output file where this chunk starts */
4282
+ offset: z.number()
4283
+ });
4284
+ const sessionContextUsageEventSchema = z.object({
4285
+ t: z.literal("context-usage"),
4286
+ totalTokens: z.number(),
4287
+ maxTokens: z.number(),
4288
+ percentage: z.number(),
4289
+ model: z.string().optional(),
4290
+ categories: z.array(sessionContextUsageCategorySchema).optional(),
4291
+ isAutoCompactEnabled: z.boolean().optional(),
4292
+ autoCompactThreshold: z.number().optional(),
4293
+ messageBreakdown: z.object({
4294
+ toolCallTokens: z.number(),
4295
+ toolResultTokens: z.number(),
4296
+ attachmentTokens: z.number(),
4297
+ assistantMessageTokens: z.number(),
4298
+ userMessageTokens: z.number()
4299
+ }).optional()
4300
+ });
4301
+ const sessionEventSchema = z.discriminatedUnion("t", [
4302
+ sessionTextEventSchema,
4303
+ sessionTextDeltaEventSchema,
4304
+ sessionServiceMessageEventSchema,
4305
+ sessionToolCallStartEventSchema,
4306
+ sessionToolCallEndEventSchema,
4307
+ sessionFileEventSchema,
4308
+ sessionTurnStartEventSchema,
4309
+ sessionStartEventSchema,
4310
+ sessionTurnEndEventSchema,
4311
+ sessionStopEventSchema,
4312
+ sessionUsageUpdateEventSchema,
4313
+ sessionTaskStartEventSchema,
4314
+ sessionTaskProgressEventSchema,
4315
+ sessionTaskEndEventSchema,
4316
+ sessionToolProgressEventSchema,
4317
+ sessionPromptSuggestionEventSchema,
4318
+ sessionNeedsContinueEventSchema,
4319
+ sessionStateChangedEventSchema,
4320
+ sessionContextUsageEventSchema,
4321
+ sessionTaskLogEventSchema
4322
+ ]);
4323
+ const sessionEnvelopeSchema = z.object({
4324
+ id: z.string(),
4325
+ time: z.number(),
4326
+ role: sessionRoleSchema,
4327
+ turn: z.string().optional(),
4328
+ subagent: z.string().refine((value) => cuid2Exports.isCuid(value), {
4329
+ message: "subagent must be a cuid2 value"
4330
+ }).optional(),
4331
+ ev: sessionEventSchema
4332
+ }).superRefine((envelope, ctx) => {
4333
+ if (envelope.ev.t === "service" && envelope.role !== "agent") {
4334
+ ctx.addIssue({
4335
+ code: z.ZodIssueCode.custom,
4336
+ message: 'service events must use role "agent"',
4337
+ path: ["role"]
4338
+ });
4339
+ }
4340
+ if ((envelope.ev.t === "start" || envelope.ev.t === "stop" || envelope.ev.t === "usage-update" || envelope.ev.t === "task-start" || envelope.ev.t === "task-progress" || envelope.ev.t === "task-end" || envelope.ev.t === "tool-progress" || envelope.ev.t === "prompt-suggestion" || envelope.ev.t === "needs-continue" || envelope.ev.t === "session-state-changed" || envelope.ev.t === "context-usage" || envelope.ev.t === "task-log") && envelope.role !== "agent") {
4341
+ ctx.addIssue({
4342
+ code: z.ZodIssueCode.custom,
4343
+ message: `${envelope.ev.t} events must use role "agent"`,
4344
+ path: ["role"]
4345
+ });
4346
+ }
4347
+ });
4348
+
4349
+ const MessageMetaSchema = z.object({
4350
+ sentFrom: z.string().optional(),
4351
+ permissionMode: z.enum(["default", "acceptEdits", "bypassPermissions", "plan", "dontAsk", "auto", "read-only", "safe-yolo", "yolo"]).optional(),
4352
+ model: z.string().nullable().optional(),
4353
+ fallbackModel: z.string().nullable().optional(),
4354
+ customSystemPrompt: z.string().nullable().optional(),
4355
+ appendSystemPrompt: z.string().nullable().optional(),
4356
+ allowedTools: z.array(z.string()).nullable().optional(),
4357
+ disallowedTools: z.array(z.string()).nullable().optional(),
4358
+ displayText: z.string().optional(),
4359
+ /**
4360
+ * When false, the message is appended to the transcript without triggering
4361
+ * an assistant turn. Requires @anthropic-ai/claude-agent-sdk 0.2.110+ on CLI.
4362
+ * Defaults to true when unset (normal turn-triggering message).
4363
+ */
4364
+ shouldQuery: z.boolean().optional()
4365
+ });
4366
+
4367
+ const UserMessageSchema = z.object({
4368
+ role: z.literal("user"),
4369
+ content: z.object({
4370
+ type: z.literal("text"),
4371
+ text: z.string()
4372
+ }),
4373
+ localKey: z.string().optional(),
4374
+ meta: MessageMetaSchema.optional()
4375
+ });
4376
+ const AgentMessageSchema = z.object({
4377
+ role: z.literal("agent"),
4378
+ content: z.object({
4379
+ type: z.string()
4380
+ }).passthrough(),
4381
+ meta: MessageMetaSchema.optional()
4382
+ });
4383
+ z.discriminatedUnion("role", [UserMessageSchema, AgentMessageSchema]);
4384
+
4385
+ const SessionMessageContentSchema = z.object({
4386
+ c: z.string(),
4387
+ t: z.literal("encrypted")
4388
+ });
4389
+ const SessionMessageSchema = z.object({
4390
+ id: z.string(),
4391
+ seq: z.number(),
4392
+ localId: z.string().nullish(),
4393
+ content: SessionMessageContentSchema,
4394
+ createdAt: z.number(),
4395
+ updatedAt: z.number()
4396
+ });
4397
+ const SessionProtocolMessageSchema = z.object({
4398
+ role: z.literal("session"),
4399
+ content: sessionEnvelopeSchema,
4400
+ meta: MessageMetaSchema.optional()
4401
+ });
4402
+ z.discriminatedUnion("role", [
4403
+ UserMessageSchema,
4404
+ AgentMessageSchema,
4405
+ SessionProtocolMessageSchema
4406
+ ]);
4407
+ const VersionedEncryptedValueSchema = z.object({
4408
+ version: z.number(),
4409
+ value: z.string()
4410
+ });
4411
+ const VersionedNullableEncryptedValueSchema = z.object({
4412
+ version: z.number(),
4413
+ value: z.string().nullable()
4414
+ });
4415
+ const UpdateNewMessageBodySchema = z.object({
4416
+ t: z.literal("new-message"),
4417
+ sid: z.string(),
4418
+ message: SessionMessageSchema
4419
+ });
4420
+ const UpdateSessionBodySchema = z.object({
4421
+ t: z.literal("update-session"),
4422
+ id: z.string(),
4423
+ metadata: VersionedEncryptedValueSchema.nullish(),
4424
+ agentState: VersionedNullableEncryptedValueSchema.nullish(),
4425
+ preferences: VersionedNullableEncryptedValueSchema.nullish()
4426
+ });
4427
+ const VersionedMachineEncryptedValueSchema = z.object({
4428
+ version: z.number(),
4429
+ value: z.string()
4430
+ });
4431
+ const UpdateMachineBodySchema = z.object({
4432
+ t: z.literal("update-machine"),
4433
+ machineId: z.string(),
4434
+ metadata: VersionedMachineEncryptedValueSchema.nullish(),
4435
+ daemonState: VersionedMachineEncryptedValueSchema.nullish(),
4436
+ active: z.boolean().optional(),
4437
+ activeAt: z.number().optional()
4438
+ });
4439
+ const CoreUpdateBodySchema = z.discriminatedUnion("t", [
4440
+ UpdateNewMessageBodySchema,
4441
+ UpdateSessionBodySchema,
4442
+ UpdateMachineBodySchema
4443
+ ]);
4444
+ z.object({
4445
+ id: z.string(),
4446
+ seq: z.number(),
4447
+ body: CoreUpdateBodySchema,
4448
+ createdAt: z.number()
4449
+ });
4450
+
4451
+ z.object({
4452
+ host: z.string(),
4453
+ platform: z.string(),
4454
+ happyCliVersion: z.string(),
4455
+ homeDir: z.string(),
4456
+ happyHomeDir: z.string(),
4457
+ happyLibDir: z.string()
4458
+ });
4459
+ const TailscaleServeEntrySchema = z.object({
4460
+ port: z.number(),
4461
+ path: z.string().optional(),
4462
+ protocol: z.string(),
4463
+ target: z.string(),
4464
+ funnel: z.boolean(),
4465
+ hostname: z.string()
4466
+ });
4467
+ const TailscaleInfoSchema = z.object({
4468
+ status: z.enum(["connected", "disconnected", "not-installed"]),
4469
+ ipv4: z.string().optional(),
4470
+ ipv6: z.string().optional(),
4471
+ hostname: z.string().optional(),
4472
+ tailnetName: z.string().optional(),
4473
+ version: z.string().optional(),
4474
+ serves: z.array(TailscaleServeEntrySchema).optional()
4475
+ });
4476
+ const TunnelEntrySchema = z.object({
4477
+ provider: z.string(),
4478
+ localPort: z.number(),
4479
+ remotePort: z.number().optional(),
4480
+ protocol: z.string(),
4481
+ path: z.string().optional(),
4482
+ target: z.string(),
4483
+ publicUrl: z.string().optional(),
4484
+ accessScope: z.enum(["public", "private", "tailnet"]),
4485
+ hostname: z.string().optional(),
4486
+ metadata: z.record(z.string(), z.string()).optional()
4487
+ });
4488
+ const TunnelProviderInfoSchema = z.object({
4489
+ provider: z.string(),
4490
+ status: z.enum(["available", "unavailable", "not-installed"]),
4491
+ version: z.string().optional(),
4492
+ entries: z.array(TunnelEntrySchema),
4493
+ metadata: z.record(z.string(), z.string()).optional()
4494
+ });
4495
+ const TunnelStateSchema = z.object({
4496
+ providers: z.array(TunnelProviderInfoSchema)
4497
+ });
4498
+ const AutomationPrioritySchema = z.enum(["urgent", "user", "background"]);
4499
+ const AutomationJobKindSchema = z.enum(["supervisor", "webhook", "agent_loop", "task"]);
4500
+ const AutomationJobStatusSchema = z.enum([
4501
+ "queued",
4502
+ "dispatching",
4503
+ "running",
4504
+ "completed",
4505
+ "failed",
4506
+ "cancelled"
4507
+ ]);
4508
+ const AutomationJobSummarySchema = z.object({
4509
+ id: z.string(),
4510
+ kind: AutomationJobKindSchema,
4511
+ status: AutomationJobStatusSchema,
4512
+ priority: AutomationPrioritySchema,
4513
+ dedupeKey: z.string(),
4514
+ attempt: z.number(),
4515
+ maxAttempts: z.number(),
4516
+ createdAt: z.number(),
4517
+ updatedAt: z.number(),
4518
+ dispatchedAt: z.number().optional(),
4519
+ completedAt: z.number().optional(),
4520
+ nextRunAt: z.number().optional(),
4521
+ sessionId: z.string().optional(),
4522
+ label: z.string().optional(),
4523
+ projectId: z.string().optional(),
4524
+ runId: z.string().optional(),
4525
+ loopId: z.string().optional(),
4526
+ loopIteration: z.number().optional(),
4527
+ continuityKey: z.string().optional(),
4528
+ errorMessage: z.string().optional(),
4529
+ recovered: z.boolean().optional()
4530
+ });
4531
+ const AutomationGuardianSummarySchema = z.object({
4532
+ key: z.string(),
4533
+ projectId: z.string(),
4534
+ loopId: z.string().optional(),
4535
+ sessionId: z.string(),
4536
+ updatedAt: z.number(),
4537
+ lastRunId: z.string().optional(),
4538
+ attached: z.boolean().optional(),
4539
+ recovered: z.boolean().optional()
4540
+ });
4541
+ const AutomationGuardianUsageSummarySchema = z.object({
4542
+ key: z.string(),
4543
+ projectId: z.string().optional(),
4544
+ loopId: z.string().optional(),
4545
+ reuseCount: z.number(),
4546
+ rememberCount: z.number(),
4547
+ resetCount: z.number(),
4548
+ lastUsedAt: z.number(),
4549
+ currentSessionId: z.string().optional()
4550
+ });
4551
+ const AutomationAuditEventSummarySchema = z.object({
4552
+ id: z.string(),
4553
+ occurredAt: z.number(),
4554
+ kind: z.string(),
4555
+ jobId: z.string().optional(),
4556
+ dedupeKey: z.string().optional(),
4557
+ sessionId: z.string().optional(),
4558
+ projectId: z.string().optional(),
4559
+ runId: z.string().optional(),
4560
+ loopId: z.string().optional(),
4561
+ trigger: z.string().optional(),
4562
+ status: z.string().optional(),
4563
+ guardianKey: z.string().optional(),
4564
+ guardianSessionId: z.string().optional(),
4565
+ message: z.string().optional()
4566
+ });
4567
+ const AutomationAuditStatsSchema = z.object({
4568
+ totalEvents: z.number(),
4569
+ lastEventAt: z.number().optional(),
4570
+ queuedCount: z.number(),
4571
+ sessionStartedCount: z.number(),
4572
+ terminalCompletedCount: z.number(),
4573
+ terminalFailedCount: z.number(),
4574
+ terminalCancelledCount: z.number(),
4575
+ guardianReuseCount: z.number(),
4576
+ guardianRememberCount: z.number(),
4577
+ guardianResetCount: z.number(),
4578
+ sessionReattachedCount: z.number(),
4579
+ watchdogStopCount: z.number(),
4580
+ stopRequestCount: z.number(),
4581
+ guardianEligibleRunCount: z.number(),
4582
+ guardianReuseRate: z.number(),
4583
+ activeGuardianCount: z.number()
4584
+ });
4585
+ const AutomationCountsSchema = z.object({
4586
+ queued: z.number(),
4587
+ dispatching: z.number(),
4588
+ running: z.number(),
4589
+ completed: z.number(),
4590
+ failed: z.number(),
4591
+ cancelled: z.number()
4592
+ });
4593
+ const AgentLoopSummarySchema = z.object({
4594
+ id: z.string(),
4595
+ name: z.string().optional(),
4596
+ directory: z.string(),
4597
+ enabled: z.boolean(),
4598
+ intervalMs: z.number(),
4599
+ cronExpression: z.string().optional(),
4600
+ iteration: z.number(),
4601
+ nextRunAt: z.number(),
4602
+ runtimeState: z.string(),
4603
+ phase: z.string(),
4604
+ lastTriggerSource: z.string().optional(),
4605
+ lastBriefSummary: z.string().optional(),
4606
+ lastError: z.string().optional(),
4607
+ agent: z.string()
4608
+ });
4609
+ const BootstrapProfileSummarySchema = z.object({
4610
+ id: z.string(),
4611
+ name: z.string().optional(),
4612
+ rootDirectory: z.string(),
4613
+ intervalMs: z.number(),
4614
+ enabled: z.boolean(),
4615
+ status: z.string(),
4616
+ statusUpdatedAt: z.number(),
4617
+ lastRunAt: z.number().optional(),
4618
+ lastRepoCount: z.number().optional(),
4619
+ lastSuggestionCount: z.number().optional(),
4620
+ lastError: z.string().optional()
4621
+ });
4622
+ const AutoDreamProfileSummarySchema = z.object({
4623
+ id: z.string(),
4624
+ name: z.string().optional(),
4625
+ rootDirectory: z.string(),
4626
+ intervalMs: z.number(),
4627
+ enabled: z.boolean(),
4628
+ nextRunAt: z.number(),
4629
+ status: z.string(),
4630
+ stage: z.string(),
4631
+ statusUpdatedAt: z.number(),
4632
+ lastRunAt: z.number().optional(),
4633
+ lastMemoryFiles: z.number().optional(),
4634
+ lastError: z.string().optional()
4635
+ });
4636
+ const AutomationStateSchema = z.object({
4637
+ updatedAt: z.number(),
4638
+ counts: AutomationCountsSchema,
4639
+ recentJobs: z.array(AutomationJobSummarySchema),
4640
+ guardians: z.array(AutomationGuardianSummarySchema).optional(),
4641
+ guardianUsage: z.array(AutomationGuardianUsageSummarySchema).optional(),
4642
+ auditStats: AutomationAuditStatsSchema.optional(),
4643
+ recentAuditEvents: z.array(AutomationAuditEventSummarySchema).optional(),
4644
+ loops: z.array(AgentLoopSummarySchema).optional(),
4645
+ bootstrapProfiles: z.array(BootstrapProfileSummarySchema).optional(),
4646
+ autoDreamProfiles: z.array(AutoDreamProfileSummarySchema).optional()
4647
+ });
4648
+ const BriefMessageSchema = z.object({
4649
+ loopId: z.string(),
4650
+ loopName: z.string().optional(),
4651
+ status: z.enum(["completed", "failed", "cancelled"]),
4652
+ summary: z.string(),
4653
+ detail: z.string(),
4654
+ generatedAt: z.number(),
4655
+ sessionId: z.string().optional()
4656
+ });
4657
+ const CliInstallSourceSchema = z.enum([
4658
+ "npm-global",
4659
+ "local-source",
4660
+ "unknown"
4661
+ ]);
4662
+ const CliInstallInfoSchema = z.object({
4663
+ source: CliInstallSourceSchema,
4664
+ canSelfUpgrade: z.boolean()
4665
+ });
4666
+ z.object({
4667
+ status: z.union([
4668
+ z.enum(["running", "shutting-down"]),
4669
+ z.string()
4670
+ ]),
4671
+ pid: z.number().optional(),
4672
+ httpPort: z.number().optional(),
4673
+ startTime: z.union([z.number(), z.string()]).optional(),
4674
+ startedAt: z.number().optional(),
4675
+ startedWithCliVersion: z.string().optional(),
4676
+ shutdownRequestedAt: z.number().optional(),
4677
+ shutdownSource: z.union([
4678
+ z.enum(["mobile-app", "cli", "os-signal", "unknown"]),
4679
+ z.string()
4680
+ ]).optional(),
4681
+ tailscale: TailscaleInfoSchema.optional(),
4682
+ tunnels: TunnelStateSchema.optional(),
4683
+ automation: AutomationStateSchema.optional(),
4684
+ recentBriefs: z.array(BriefMessageSchema).optional(),
4685
+ cliInstall: CliInstallInfoSchema.optional(),
4686
+ killed: z.boolean().optional()
4687
+ });
4688
+
4689
+ const KnowledgeEntryTypeSchema = z.enum([
4690
+ "discovery",
4691
+ // New insight or finding
4692
+ "decision",
4693
+ // Architecture / tech choice
4694
+ "fix",
4695
+ // Bug fix record
4696
+ "convention",
4697
+ // Code convention / process rule
4698
+ "warning"
4699
+ // Known pitfall or gotcha
4700
+ ]);
4701
+ const KnowledgeContributorTypeSchema = z.enum([
4702
+ "session",
4703
+ // Auto-generated by Claude session
4704
+ "supervisor",
4705
+ // Generated by Supervisor analysis
4706
+ "user"
4707
+ // Manually added by user
4708
+ ]);
4709
+ const KnowledgeActionSchema = z.enum([
4710
+ "create",
4711
+ // New entry
4712
+ "amend",
4713
+ // Correction / supplement
4714
+ "supersede",
4715
+ // Replace old knowledge
4716
+ "verify"
4717
+ // Confirm still valid
4718
+ ]);
4719
+ const KnowledgeStatusSchema = z.enum([
4720
+ "active",
4721
+ // Currently valid
4722
+ "superseded",
4723
+ // Replaced by newer knowledge
4724
+ "archived"
4725
+ // Manually archived by user
4726
+ ]);
4727
+ const KnowledgeConfidenceSchema = z.enum(["high", "medium", "low"]);
4728
+ z.object({
4729
+ entryType: KnowledgeEntryTypeSchema,
4730
+ contributorType: KnowledgeContributorTypeSchema,
4731
+ action: KnowledgeActionSchema,
4732
+ title: z.string().min(1).max(200),
4733
+ content: z.string().min(1),
4734
+ // Structured SOAP-like fields (optional)
4735
+ request: z.string().optional(),
4736
+ // S: What the user asked
4737
+ findings: z.string().optional(),
4738
+ // O: What was discovered
4739
+ analysis: z.string().optional(),
4740
+ // A: Root cause / assessment
4741
+ outcome: z.string().optional(),
4742
+ // P: What was done
4743
+ nextSteps: z.string().optional(),
4744
+ // Follow-up suggestions
4745
+ tags: z.array(z.string().max(50)).max(20).default([]),
4746
+ confidence: KnowledgeConfidenceSchema.default("medium"),
4747
+ sessionId: z.string().optional(),
4748
+ model: z.string().optional(),
4749
+ supersedesId: z.string().optional(),
4750
+ relatedIds: z.array(z.string()).max(10).default([]),
4751
+ affectedFiles: z.array(z.string()).max(50).default([])
4752
+ });
4753
+ z.object({
4754
+ status: KnowledgeStatusSchema.optional(),
4755
+ pinned: z.boolean().optional(),
4756
+ title: z.string().min(1).max(200).optional(),
4757
+ content: z.string().min(1).optional(),
4758
+ tags: z.array(z.string().max(50)).max(20).optional(),
4759
+ confidence: KnowledgeConfidenceSchema.optional()
4760
+ });
4761
+ z.object({
4762
+ entryType: KnowledgeEntryTypeSchema.optional(),
4763
+ status: KnowledgeStatusSchema.optional(),
4764
+ tags: z.array(z.string()).optional(),
4765
+ search: z.string().max(500).optional(),
4766
+ limit: z.number().int().min(1).max(100).default(20),
4767
+ offset: z.number().int().min(0).default(0)
4768
+ });
4769
+ const ProjectProfileSchema = z.object({
4770
+ techStack: z.array(z.string()),
4771
+ architectureType: z.string().optional(),
4772
+ knownPitfalls: z.array(z.string()),
4773
+ coreConventions: z.array(z.string()),
4774
+ lastUpdatedAt: z.number(),
4775
+ lastUpdatedBy: z.string().optional()
4776
+ });
4777
+ const KnowledgeInjectionModeSchema = z.enum(["auto", "full", "minimal"]);
4778
+ z.object({
4779
+ mode: KnowledgeInjectionModeSchema,
4780
+ contextHints: z.array(z.string()).optional()
4781
+ // Keywords from user message for relevance
4782
+ });
4783
+ z.object({
4784
+ profile: ProjectProfileSchema.nullable(),
4785
+ entries: z.array(z.object({
4786
+ id: z.string(),
4787
+ entryType: KnowledgeEntryTypeSchema,
4788
+ title: z.string(),
4789
+ content: z.string(),
4790
+ tags: z.array(z.string()),
4791
+ confidence: KnowledgeConfidenceSchema,
4792
+ createdAt: z.string()
4793
+ }))
4794
+ });
4795
+ const KnowledgeChainRelationSchema = z.object({
4796
+ from: z.string(),
4797
+ to: z.string(),
4798
+ type: z.enum(["supersedes", "related"])
4799
+ });
4800
+ const KnowledgeChainEntrySchema = z.object({
4801
+ id: z.string(),
4802
+ entryType: KnowledgeEntryTypeSchema,
4803
+ action: KnowledgeActionSchema,
4804
+ status: KnowledgeStatusSchema,
4805
+ title: z.string(),
4806
+ content: z.string(),
4807
+ tags: z.array(z.string()),
4808
+ confidence: KnowledgeConfidenceSchema,
4809
+ supersedesId: z.string().nullable(),
4810
+ createdAt: z.string()
4811
+ });
4812
+ z.object({
4813
+ chain: z.array(KnowledgeChainEntrySchema),
4814
+ relations: z.array(KnowledgeChainRelationSchema)
4815
+ });
4816
+ const CrossProjectSearchResultSchema = z.object({
4817
+ id: z.string(),
4818
+ projectId: z.string(),
4819
+ projectPath: z.string(),
4820
+ entryType: KnowledgeEntryTypeSchema,
4821
+ title: z.string(),
4822
+ content: z.string(),
4823
+ tags: z.array(z.string()),
4824
+ confidence: KnowledgeConfidenceSchema,
4825
+ similarity: z.number().optional(),
4826
+ // Present when using semantic search
4827
+ createdAt: z.string()
4828
+ });
4829
+ z.object({
4830
+ results: z.array(CrossProjectSearchResultSchema),
4831
+ total: z.number()
4832
+ });
4833
+ z.object({
4834
+ projectId: z.string(),
4835
+ sessionId: z.string(),
4836
+ model: z.string(),
4837
+ turnId: z.string(),
4838
+ turnData: z.object({
4839
+ userMessage: z.string().max(2e3),
4840
+ assistantText: z.string().max(5e3),
4841
+ fileEdits: z.array(z.object({
4842
+ path: z.string(),
4843
+ type: z.enum(["create", "edit"])
4844
+ })).max(50),
4845
+ toolCallCount: z.number().int(),
4846
+ outputTokens: z.number().int()
4847
+ })
4848
+ });
4849
+
4850
+ const VoiceTokenAllowedSchema = z.object({
4851
+ allowed: z.literal(true),
4852
+ token: z.string(),
4853
+ agentId: z.string(),
4854
+ elevenUserId: z.string(),
4855
+ usedSeconds: z.number(),
4856
+ limitSeconds: z.number()
4857
+ });
4858
+ const VoiceTokenDeniedSchema = z.object({
4859
+ allowed: z.literal(false),
4860
+ reason: z.enum(["voice_limit_reached", "subscription_required"]),
4861
+ usedSeconds: z.number(),
4862
+ limitSeconds: z.number(),
4863
+ agentId: z.string()
4864
+ });
4865
+ z.discriminatedUnion("allowed", [
4866
+ VoiceTokenAllowedSchema,
4867
+ VoiceTokenDeniedSchema
4868
+ ]);
4869
+
4870
+ const CODEX_APP_SERVER_BACKEND = "codex-app-server";
4871
+ const CODEX_MCP_LEGACY_BACKEND = "codex-mcp-legacy";
4872
+ const CodexBackendModeSchema = z.enum([
4873
+ "auto",
4874
+ CODEX_APP_SERVER_BACKEND,
4875
+ CODEX_MCP_LEGACY_BACKEND
4876
+ ]);
4877
+ const CodexRequestedBackendSchema = CodexBackendModeSchema;
4878
+ const CodexResolvedBackendSchema = z.enum([
4879
+ CODEX_APP_SERVER_BACKEND,
4880
+ CODEX_MCP_LEGACY_BACKEND
4881
+ ]);
4882
+ const CodexConfigModeSchema = z.enum([
4883
+ "inherit",
4884
+ "managed-profile",
4885
+ "managed-overrides"
4886
+ ]);
4887
+ const CODEX_REQUESTED_BACKEND_ALIASES = {
4888
+ auto: ["", "auto"],
4889
+ [CODEX_APP_SERVER_BACKEND]: ["app-server", "appserver", CODEX_APP_SERVER_BACKEND],
4890
+ [CODEX_MCP_LEGACY_BACKEND]: [
4891
+ "legacy",
4892
+ "mcp",
4893
+ "mcp-legacy",
4894
+ CODEX_MCP_LEGACY_BACKEND
4895
+ ]
4896
+ };
4897
+ new Map(
4898
+ Object.entries(CODEX_REQUESTED_BACKEND_ALIASES).flatMap(
4899
+ ([backend, aliases]) => aliases.map((alias) => [alias, backend])
4900
+ )
4901
+ );
4902
+
4903
+ function isTemplateAwareUrl(value) {
4904
+ if (!value) return true;
4905
+ if (/^\$\{[A-Z_][A-Z0-9_]*(:-[^}]*)?\}$/.test(value)) return true;
4906
+ try {
4907
+ new URL(value);
4908
+ return true;
4909
+ } catch {
4910
+ return false;
4911
+ }
4912
+ }
4913
+ const BuiltInAIBackendProfileIdSchema = z$1.enum([
4914
+ "anthropic",
4915
+ "deepseek",
4916
+ "zai",
4917
+ "openai",
4918
+ "azure-openai",
4919
+ "minimax",
4920
+ "kimi"
4921
+ ]);
4922
+ new Set(
4923
+ BuiltInAIBackendProfileIdSchema.options
4924
+ );
4925
+ const EnvironmentVariableSchema = z$1.object({
4926
+ name: z$1.string().regex(/^[A-Z_][A-Z0-9_]*$/, "Invalid environment variable name"),
4927
+ value: z$1.string()
4928
+ });
4929
+ const ProfileCompatibilitySchema = z$1.object({
4930
+ claude: z$1.boolean().default(true),
4931
+ codex: z$1.boolean().default(true),
4932
+ gemini: z$1.boolean().default(true)
4933
+ });
4934
+ const AnthropicConfigSchema = z$1.object({
4935
+ baseUrl: z$1.string().refine(isTemplateAwareUrl, {
4936
+ message: "Must be a valid URL or ${VAR} or ${VAR:-default} template string"
4937
+ }).optional(),
4938
+ authToken: z$1.string().optional(),
4939
+ model: z$1.string().optional()
4940
+ });
4941
+ const OpenAIConfigSchema = z$1.object({
4942
+ apiKey: z$1.string().optional(),
4943
+ baseUrl: z$1.string().refine(isTemplateAwareUrl, {
4944
+ message: "Must be a valid URL or ${VAR} or ${VAR:-default} template string"
4945
+ }).optional(),
4946
+ model: z$1.string().optional()
4947
+ });
4948
+ const AzureOpenAIConfigSchema = z$1.object({
4949
+ apiKey: z$1.string().optional(),
4950
+ endpoint: z$1.string().refine(isTemplateAwareUrl, {
4951
+ message: "Must be a valid URL or ${VAR} or ${VAR:-default} template string"
4952
+ }).optional(),
4953
+ apiVersion: z$1.string().optional(),
4954
+ deploymentName: z$1.string().optional()
4955
+ });
4956
+ const TogetherAIConfigSchema = z$1.object({
4957
+ apiKey: z$1.string().optional(),
4958
+ model: z$1.string().optional()
4959
+ });
4960
+ const CodexConfigSchema = z$1.object({
4961
+ backendMode: CodexBackendModeSchema.optional(),
4962
+ configMode: CodexConfigModeSchema.optional(),
4963
+ codexProfileName: z$1.string().optional(),
4964
+ model: z$1.string().optional(),
4965
+ reasoningEffort: z$1.string().optional(),
4966
+ reasoningSummary: z$1.string().optional(),
4967
+ verbosity: z$1.string().optional(),
4968
+ personality: z$1.string().optional(),
4969
+ serviceTier: z$1.string().optional(),
4970
+ webSearchEnabled: z$1.boolean().optional(),
4971
+ approvalPolicy: z$1.string().optional(),
4972
+ sandboxMode: z$1.string().optional()
4973
+ });
4974
+ const TmuxConfigSchema = z$1.object({
4975
+ sessionName: z$1.string().optional(),
4976
+ tmpDir: z$1.string().optional(),
4977
+ updateEnvironment: z$1.boolean().optional()
4978
+ });
4979
+ const CustomModelSchema = z$1.object({
4980
+ id: z$1.string().min(1),
4981
+ name: z$1.string().min(1).max(100),
4982
+ description: z$1.string().nullish()
4983
+ });
4984
+ const DefaultPermissionModeSchema = z$1.enum([
4985
+ "default",
4986
+ "acceptEdits",
4987
+ "auto",
4988
+ "bypassPermissions",
4989
+ "plan",
4990
+ "read-only",
4991
+ "safe-yolo",
4992
+ "yolo"
4993
+ ]);
4994
+ z$1.object({
4995
+ id: z$1.string().min(1),
4996
+ name: z$1.string().min(1).max(100),
4997
+ description: z$1.string().max(500).optional(),
4998
+ anthropicConfig: AnthropicConfigSchema.optional(),
4999
+ openaiConfig: OpenAIConfigSchema.optional(),
5000
+ azureOpenAIConfig: AzureOpenAIConfigSchema.optional(),
5001
+ togetherAIConfig: TogetherAIConfigSchema.optional(),
5002
+ codexConfig: CodexConfigSchema.optional(),
5003
+ tmuxConfig: TmuxConfigSchema.optional(),
5004
+ startupBashScript: z$1.string().optional(),
5005
+ environmentVariables: z$1.array(EnvironmentVariableSchema).default([]),
5006
+ customModels: z$1.array(CustomModelSchema).optional(),
5007
+ modelMappings: z$1.record(z$1.string(), z$1.string()).optional(),
5008
+ defaultSessionType: z$1.enum(["simple", "worktree"]).optional(),
5009
+ defaultPermissionMode: DefaultPermissionModeSchema.optional(),
5010
+ defaultModelMode: z$1.string().optional(),
5011
+ compatibility: ProfileCompatibilitySchema.default({
5012
+ claude: true,
5013
+ codex: true,
5014
+ gemini: true
5015
+ }),
5016
+ isBuiltIn: z$1.boolean().default(false),
5017
+ createdAt: z$1.number().default(() => Date.now()),
5018
+ updatedAt: z$1.number().default(() => Date.now()),
5019
+ version: z$1.string().default("1.0.0")
5020
+ });
5021
+ const RuntimeProfileSourceSchema = z$1.enum([
5022
+ "built-in-profile",
5023
+ "account-profile",
5024
+ "local-profile",
5025
+ "ad-hoc"
5026
+ ]);
5027
+ const RuntimeProfileTrustSchema = z$1.enum(["trusted", "untrusted"]);
5028
+ const RESOLVED_RUNTIME_PROFILE_SCHEMA_VERSION = 1;
5029
+ const ResolvedRuntimeProfileSchema = z$1.object({
5030
+ schemaVersion: z$1.literal(RESOLVED_RUNTIME_PROFILE_SCHEMA_VERSION).default(RESOLVED_RUNTIME_PROFILE_SCHEMA_VERSION),
5031
+ profileId: z$1.string().optional(),
5032
+ profileName: z$1.string().optional(),
5033
+ source: RuntimeProfileSourceSchema,
5034
+ trust: RuntimeProfileTrustSchema,
5035
+ isBuiltIn: z$1.boolean().optional(),
5036
+ compatibility: ProfileCompatibilitySchema.optional(),
5037
+ environmentVariables: z$1.record(z$1.string(), z$1.string()).default({}),
5038
+ startupBashScript: z$1.string().optional(),
5039
+ customModels: z$1.array(CustomModelSchema).optional(),
5040
+ modelMappings: z$1.record(z$1.string(), z$1.string()).optional(),
5041
+ defaultSessionType: z$1.enum(["simple", "worktree"]).optional(),
5042
+ defaultPermissionMode: DefaultPermissionModeSchema.optional(),
5043
+ defaultModelMode: z$1.string().optional()
5044
+ });
5045
+
5046
+ const TaskPrioritySchema = z.enum([
5047
+ "urgent",
5048
+ // User-initiated, needs immediate execution
5049
+ "user",
5050
+ // Normal user-created task (default)
5051
+ "background"
5052
+ // Automated / scheduled tasks
5053
+ ]);
5054
+ const TaskStatusSchema = z.enum([
5055
+ "queued",
5056
+ // Waiting in queue
5057
+ "dispatching",
5058
+ // Being sent to CLI daemon
5059
+ "running",
5060
+ // Executing on CLI
5061
+ "completed",
5062
+ // Finished successfully
5063
+ "failed",
5064
+ // Execution failed
5065
+ "cancelled"
5066
+ // Cancelled by user
5067
+ ]);
5068
+ const TaskTriggerTypeSchema = z.enum([
5069
+ "manual",
5070
+ // Created from App by user
5071
+ "cron",
5072
+ // Created by TriggerSchedule
5073
+ "webhook"
5074
+ // Created by WebhookTrigger
5075
+ ]);
5076
+ z.object({
5077
+ id: z.string(),
5078
+ projectId: z.string().nullable(),
5079
+ machineId: z.string(),
5080
+ priority: TaskPrioritySchema,
5081
+ status: TaskStatusSchema,
5082
+ triggerType: TaskTriggerTypeSchema,
5083
+ triggerRef: z.string().optional(),
5084
+ attempt: z.number(),
5085
+ maxAttempts: z.number(),
5086
+ sessionId: z.string().optional(),
5087
+ errorMessage: z.string().optional(),
5088
+ dispatchedAt: z.number().optional(),
5089
+ completedAt: z.number().optional(),
5090
+ createdAt: z.number(),
5091
+ updatedAt: z.number(),
5092
+ // Encrypted prompt preview (first 100 chars)
5093
+ promptPreview: z.string().optional(),
5094
+ // Names of bound skills for display
5095
+ skillNames: z.array(z.string()).optional()
5096
+ });
5097
+ z.object({
5098
+ projectId: z.string().optional(),
5099
+ machineId: z.string(),
5100
+ prompt: z.string().min(1),
5101
+ // Encrypted by App
5102
+ priority: TaskPrioritySchema.default("user"),
5103
+ maxAttempts: z.number().int().min(1).max(10).default(3),
5104
+ skillIds: z.array(z.string()).max(10).default([]),
5105
+ // Profile binding (wire 0.15.0). Business key — built-in id like
5106
+ // "anthropic" or AiBackendProfile.profileKey for the account. Optional:
5107
+ // when omitted the server falls back to Project.supervisorConfig.defaultProfileId
5108
+ // via the unified runtimeProfileResolver (feature-flagged).
5109
+ profileId: z.string().optional()
5110
+ });
5111
+ z.object({
5112
+ type: z.literal("task-trigger"),
5113
+ taskId: z.string(),
5114
+ prompt: z.string(),
5115
+ // Encrypted prompt
5116
+ directory: z.string(),
5117
+ // Project directory on machine
5118
+ priority: TaskPrioritySchema,
5119
+ projectId: z.string().optional(),
5120
+ resultToken: z.string().optional(),
5121
+ skillContents: z.array(z.object({
5122
+ name: z.string(),
5123
+ content: z.string()
5124
+ })).optional(),
5125
+ agentType: z.string().nullable().optional(),
5126
+ // "claude" | "codex" | "gemini" — null = inherit CLI default
5127
+ modelOverride: z.string().nullable().optional(),
5128
+ // e.g. "claude-sonnet-4-20250514" — null = agent default
5129
+ // Profile binding for this task. `profileId` references the AIBackendProfile
5130
+ // selected when the task was created (Task.profileId column). `runtimeProfile`
5131
+ // is the resolved snapshot (env vars, startup script, permission mode, etc.)
5132
+ // that the CLI should honor when spawning the session. Both optional for
5133
+ // backward compatibility; starting from wire 0.14.0 + server unified resolver
5134
+ // these are always populated for scheduled/webhook/manual tasks.
5135
+ profileId: z.string().optional(),
5136
+ runtimeProfile: ResolvedRuntimeProfileSchema.optional()
5137
+ });
5138
+ const TaskOutcomeSchema = z.enum([
5139
+ "completed",
5140
+ "failed",
5141
+ "blocked"
5142
+ ]);
5143
+ z.object({
5144
+ taskId: z.string(),
5145
+ status: TaskStatusSchema,
5146
+ outcome: TaskOutcomeSchema.optional(),
5147
+ sessionId: z.string().optional(),
5148
+ errorMessage: z.string().optional()
5149
+ });
5150
+ z.object({
5151
+ type: z.literal("task-status-changed"),
5152
+ taskId: z.string(),
5153
+ machineId: z.string().optional(),
5154
+ status: TaskStatusSchema,
5155
+ sessionId: z.string().optional(),
5156
+ errorMessage: z.string().optional(),
5157
+ completedAt: z.number().optional()
5158
+ });
5159
+
5160
+ z.object({
5161
+ id: z.string(),
5162
+ projectId: z.string().nullable(),
5163
+ name: z.string(),
5164
+ description: z.string().optional(),
5165
+ content: z.string(),
5166
+ attachments: z.array(z.string()),
5167
+ sourceKnowledgeId: z.string().optional(),
5168
+ archived: z.boolean(),
5169
+ createdAt: z.number(),
5170
+ updatedAt: z.number()
5171
+ });
5172
+ z.object({
5173
+ projectId: z.string().optional(),
5174
+ name: z.string().min(1).max(100),
5175
+ description: z.string().max(500).optional(),
5176
+ content: z.string().min(1).max(5e4),
5177
+ attachments: z.array(z.string()).max(10).default([]),
5178
+ sourceKnowledgeId: z.string().optional()
5179
+ });
5180
+ z.object({
5181
+ name: z.string().min(1).max(100).optional(),
5182
+ description: z.string().max(500).optional(),
5183
+ content: z.string().min(1).max(5e4).optional(),
5184
+ attachments: z.array(z.string()).max(10).optional(),
5185
+ archived: z.boolean().optional()
5186
+ });
5187
+ z.object({
5188
+ name: z.string(),
5189
+ content: z.string()
5190
+ });
5191
+
5192
+ const InboxCategorySchema = z.enum([
5193
+ "task",
5194
+ // Task queue events (completed, failed, cancelled)
5195
+ "trigger",
5196
+ // Cron/webhook trigger fired
5197
+ "supervisor",
5198
+ // Supervisor run results
5199
+ "session",
5200
+ // Session lifecycle events
5201
+ "knowledge",
5202
+ // Knowledge base changes
5203
+ "system"
5204
+ // System notifications
5205
+ ]);
5206
+ const InboxSeveritySchema = z.enum([
5207
+ "info",
5208
+ "warning",
5209
+ "error"
5210
+ ]);
5211
+ const InboxItemSummarySchema = z.object({
5212
+ id: z.string(),
5213
+ category: InboxCategorySchema,
5214
+ eventType: z.string(),
5215
+ // e.g. "task.completed", "trigger.cron.fired"
5216
+ severity: InboxSeveritySchema,
5217
+ title: z.string(),
5218
+ body: z.string().optional(),
5219
+ read: z.boolean(),
5220
+ referenceUrl: z.string().optional(),
5221
+ // Deep link, e.g. "/machine/xxx/tasks"
5222
+ refType: z.string().optional(),
5223
+ // Polymorphic ref: "task" | "trigger" | "session" | ...
5224
+ refId: z.string().optional(),
5225
+ // ID of referenced entity
5226
+ groupKey: z.string().optional(),
5227
+ // Dedup key (same source within 1h → skip)
5228
+ createdAt: z.number()
5229
+ });
5230
+ z.object({
5231
+ type: z.literal("inbox-new-item"),
5232
+ item: InboxItemSummarySchema
5233
+ });
5234
+ z.object({
5235
+ type: z.literal("inbox-unread-count"),
5236
+ count: z.number()
5237
+ });
5238
+
5239
+ const SessionEventTypeSchema = z.enum([
5240
+ "file_edit",
5241
+ // File created/modified/deleted
5242
+ "bash_command",
5243
+ // Shell command executed
5244
+ "tool_call",
5245
+ // Tool invocation (Read, Grep, etc.)
5246
+ "git_operation",
5247
+ // Git commit, push, branch, etc.
5248
+ "error",
5249
+ // Error occurred during session
5250
+ "session_start",
5251
+ // Session started
5252
+ "session_end"
5253
+ // Session ended
5254
+ ]);
5255
+ const SessionEventSummarySchema = z.object({
5256
+ id: z.string(),
5257
+ sessionId: z.string(),
5258
+ eventType: SessionEventTypeSchema,
5259
+ summary: z.string(),
5260
+ // Human-readable one-liner
5261
+ detail: z.record(z.string(), z.unknown()).optional(),
5262
+ // Structured metadata (JSON)
5263
+ createdAt: z.number()
5264
+ });
5265
+ z.object({
5266
+ sessionId: z.string(),
5267
+ eventType: SessionEventTypeSchema,
5268
+ summary: z.string().max(500),
5269
+ detail: z.record(z.string(), z.unknown()).optional()
5270
+ });
5271
+ z.object({
5272
+ type: z.literal("session-event-created"),
5273
+ event: SessionEventSummarySchema
5274
+ });
5275
+
5276
+ z.object({
5277
+ /** Shell to use (defaults to user's default shell) */
5278
+ shell: z.string().optional(),
5279
+ /** Working directory */
5280
+ cwd: z.string().optional(),
5281
+ /** Initial terminal dimensions */
5282
+ cols: z.number().int().min(1).max(500).optional(),
5283
+ rows: z.number().int().min(1).max(200).optional()
5284
+ });
5285
+ z.object({
5286
+ success: z.boolean(),
5287
+ terminalId: z.string().optional(),
5288
+ error: z.string().optional()
5289
+ });
5290
+ z.object({
5291
+ terminalId: z.string(),
5292
+ cols: z.number().int().min(1).max(500),
5293
+ rows: z.number().int().min(1).max(200)
5294
+ });
5295
+ z.object({
5296
+ terminalId: z.string()
5297
+ });
5298
+ z.object({
5299
+ machineId: z.string(),
5300
+ terminalId: z.string(),
5301
+ data: z.string()
5302
+ });
5303
+ z.object({
5304
+ machineId: z.string(),
5305
+ terminalId: z.string(),
5306
+ data: z.string()
5307
+ });
5308
+ z.object({
5309
+ machineId: z.string(),
5310
+ terminalId: z.string(),
5311
+ exitCode: z.number()
5312
+ });
5313
+
5314
+ const sessionProgressTodoStatusSchema = z.enum([
5315
+ "pending",
5316
+ "in_progress",
5317
+ "completed"
5318
+ ]);
5319
+ const sessionProgressTodoSchema = z.object({
5320
+ content: z.string(),
5321
+ status: sessionProgressTodoStatusSchema,
5322
+ /** SDK-native: imperative-present form shown when status is in_progress. */
5323
+ activeForm: z.string().optional(),
5324
+ /** Optional phase/stage label a step belongs to, e.g. "Phase 2". */
5325
+ stage: z.string().optional(),
5326
+ /**
5327
+ * Carried over from SDK's `TodoWriteOutput.verificationNudgeNeeded` — SDK
5328
+ * flags items it suspects were marked completed without verification.
5329
+ */
5330
+ verificationNudgeNeeded: z.boolean().optional()
5331
+ });
5332
+ const sessionProgressListSchema = z.object({
5333
+ /** Stable UUID for tab switching / explicit Agent addressing. */
5334
+ id: z.string(),
5335
+ /** Short human-readable label; auto-derived from first todo if absent. */
5336
+ label: z.string().optional(),
5337
+ todos: z.array(sessionProgressTodoSchema),
5338
+ /** Optional overall stage for this list (set via MCP). */
5339
+ currentStage: z.string().optional(),
5340
+ /** Optional blocker list (set via MCP). */
5341
+ blockers: z.array(z.string()).optional(),
5342
+ startedAt: z.number(),
5343
+ updatedAt: z.number(),
5344
+ /** When this list stopped being active (got pushed to history). */
5345
+ archivedAt: z.number().optional(),
5346
+ /**
5347
+ * Tool-call message IDs for file-editing tools (Edit/Write/MultiEdit/
5348
+ * NotebookEdit) that ran while this list was the active one. Consumers
5349
+ * resolve these against the session message stream to render per-list
5350
+ * file change summaries without duplicating diff content into metadata.
5351
+ */
5352
+ toolCallIds: z.array(z.string()).optional(),
5353
+ /**
5354
+ * Timestamp at which an auto-summary was triggered for this list's
5355
+ * completion (all todos completed → all completed transition). Dedup flag
5356
+ * so the CLI hook only fires ONE synthetic summary-trigger message per
5357
+ * list lifecycle, even if subsequent TodoWrite calls keep it all done.
5358
+ */
5359
+ summaryGeneratedAt: z.number().optional()
5360
+ });
5361
+ z.object({
5362
+ /** Ordered by startedAt asc; last item is typically the active one. */
5363
+ lists: z.array(sessionProgressListSchema).optional(),
5364
+ /** Points at the active list within `lists`. */
5365
+ currentListId: z.string().optional(),
5366
+ /**
5367
+ * Legacy flat fields. Still written for backward compat with older
5368
+ * readers — kept in sync with `lists[currentListId]` on each update.
5369
+ */
5370
+ todos: z.array(sessionProgressTodoSchema).optional(),
5371
+ currentStage: z.string().optional(),
5372
+ blockers: z.array(z.string()).optional(),
5373
+ updatedAt: z.number()
5374
+ });
5375
+ const sessionSummaryStateSchema = z.object({
5376
+ goal: z.string(),
5377
+ currentFocus: z.string().optional(),
5378
+ keyDecisions: z.array(z.string()).optional(),
5379
+ openQuestions: z.array(z.string()).optional(),
5380
+ impactScope: z.array(z.string()).optional(),
5381
+ updatedAt: z.number()
5382
+ });
5383
+ const sessionSummaryRefreshActiveRequestSchema = z.object({
5384
+ requestId: z.string().min(1),
5385
+ requestedAt: z.number(),
5386
+ requester: z.enum(["happy-agent", "app", "system"]),
5387
+ command: z.literal("summary-refresh"),
5388
+ requireSummary: z.boolean()
5389
+ });
5390
+ const sessionSummaryRefreshRecentEntrySchema = z.object({
5391
+ requestId: z.string().min(1),
5392
+ status: z.enum(["applied", "superseded"]),
5393
+ resolvedAt: z.number(),
5394
+ summaryUpdatedAt: z.number().optional(),
5395
+ supersededByRequestId: z.string().min(1).optional()
5396
+ });
5397
+ const sessionSummaryRefreshStateSchema = z.object({
5398
+ protocolVersion: z.literal(1),
5399
+ active: sessionSummaryRefreshActiveRequestSchema.optional(),
5400
+ recent: z.array(sessionSummaryRefreshRecentEntrySchema).optional()
5401
+ });
5402
+
5403
+ const HAPPY_MCP_TOOL_NAMES = [
5404
+ "change_title",
5405
+ "query_project_knowledge",
5406
+ "update_progress",
5407
+ "update_session_summary"
5408
+ ];
5409
+ const HAPPY_MCP_TOOL_SPECS = {
5410
+ change_title: {
5411
+ title: "Change Title",
5412
+ description: 'Set or update the chat session title. Titles should be short (under 50 chars) and action-oriented, e.g. "Fix auth token refresh".',
5413
+ failureLabel: "Failed to change chat title",
5414
+ inputSchema: {
5415
+ title: z$1.string().describe("The new title for the chat session")
5416
+ },
5417
+ hideSuccessfulCall: true,
5418
+ autoApproveByDefault: true,
5419
+ permissionAction: "Waiting for approval to update chat title",
5420
+ dynamicAction: "Updating chat title",
5421
+ fallbackAction: "Update chat title",
5422
+ reasonPhrases: ["title update", "title updates", "change_title"]
5423
+ },
5424
+ query_project_knowledge: {
5425
+ title: "Project Knowledge",
5426
+ description: "Search the project knowledge base for relevant context, past decisions, known pitfalls, and conventions.",
5427
+ failureLabel: "Knowledge query failed",
5428
+ inputSchema: {
5429
+ query: z$1.string().describe("Search query describing what you want to know")
5430
+ },
5431
+ hideSuccessfulCall: false,
5432
+ autoApproveByDefault: false,
5433
+ permissionAction: "Waiting for approval to search project knowledge",
5434
+ dynamicAction: "Searching project knowledge",
5435
+ fallbackAction: "Search project knowledge",
5436
+ reasonPhrases: []
5437
+ },
5438
+ update_progress: {
5439
+ title: "Update Progress",
5440
+ description: 'Optional override for the App\'s Progress tab. In most cases your TodoWrite calls are auto-mirrored, so you do NOT need to call this. Use it only when you want to set extra fields the CLI hook does not capture (currentStage, blockers) or to force a new list boundary with `listId: "new"`.',
5441
+ failureLabel: "Failed to update progress",
5442
+ inputSchema: {
5443
+ todos: z$1.array(
5444
+ z$1.object({
5445
+ content: z$1.string().describe("Concise description of the task"),
5446
+ status: z$1.enum(["pending", "in_progress", "completed"]).describe("Current status of the task"),
5447
+ activeForm: z$1.string().optional().describe(
5448
+ "Imperative-present form shown when status is in_progress"
5449
+ ),
5450
+ stage: z$1.string().optional().describe("Optional phase/stage label")
5451
+ })
5452
+ ).describe("The full checklist \u2014 always send every item, not a delta"),
5453
+ currentStage: z$1.string().optional().describe("Optional overall stage name for the checklist"),
5454
+ blockers: z$1.array(z$1.string()).optional().describe("Optional list of things blocking progress"),
5455
+ listId: z$1.string().optional().describe("Target list id. Use 'new' to force a fresh list"),
5456
+ label: z$1.string().optional().describe("Short human-readable name for this task list")
5457
+ },
5458
+ hideSuccessfulCall: false,
5459
+ autoApproveByDefault: true,
5460
+ permissionAction: "Waiting for approval to update progress",
5461
+ dynamicAction: "Updating progress",
5462
+ fallbackAction: "Update progress",
5463
+ reasonPhrases: ["progress update", "progress updates", "update_progress"]
5464
+ },
5465
+ update_session_summary: {
5466
+ title: "Update Session Summary",
5467
+ description: "Write a narrative session summary the App shows above the progress checklist. Call at milestones, not per task: after first understanding the goal, when scope shifts significantly, when key decisions are made, or when moving to a new phase. Full rewrite each call.",
5468
+ failureLabel: "Failed to update session summary",
5469
+ inputSchema: {
5470
+ goal: z$1.string().describe("What the user ultimately wants to accomplish"),
5471
+ currentFocus: z$1.string().optional().describe("Brief description of the active task or phase"),
5472
+ keyDecisions: z$1.array(z$1.string()).optional().describe("Important choices already made this session"),
5473
+ openQuestions: z$1.array(z$1.string()).optional().describe("Unresolved questions or pending decisions"),
5474
+ impactScope: z$1.array(z$1.string()).optional().describe("Modules/files/areas affected by this session's work"),
5475
+ requestId: z$1.string().optional().describe(
5476
+ "Optional request identifier that runtimes may record in sessionSummaryRefresh recent history for request-level confirmation"
5477
+ )
5478
+ },
5479
+ hideSuccessfulCall: false,
5480
+ autoApproveByDefault: true,
5481
+ permissionAction: "Waiting for approval to update session summary",
5482
+ dynamicAction: "Updating session summary",
5483
+ fallbackAction: "Update session summary",
5484
+ reasonPhrases: [
5485
+ "session summary",
5486
+ "update_session_summary",
5487
+ "summary update"
5488
+ ]
5489
+ }
5490
+ };
5491
+ new Set(HAPPY_MCP_TOOL_NAMES);
5492
+ HAPPY_MCP_TOOL_NAMES.filter(
5493
+ (toolName) => HAPPY_MCP_TOOL_SPECS[toolName].autoApproveByDefault
5494
+ );
5495
+ HAPPY_MCP_TOOL_NAMES.filter(
5496
+ (toolName) => HAPPY_MCP_TOOL_SPECS[toolName].hideSuccessfulCall
5497
+ );
5498
+
5499
+ const CodexRuntimeConfigSchema = z.object({
5500
+ model: z.string().nullish(),
5501
+ profile: z.string().nullish(),
5502
+ approvalPolicy: z.string().nullish(),
5503
+ sandboxMode: z.string().nullish(),
5504
+ serviceTier: z.string().nullish(),
5505
+ reasoningEffort: z.string().nullish(),
5506
+ reasoningSummary: z.string().nullish(),
5507
+ verbosity: z.string().nullish(),
5508
+ webSearch: z.string().nullish()
5509
+ });
5510
+ const CodexAccountSchema = z.object({
5511
+ type: z.enum(["apiKey", "chatgpt"]).nullable().optional(),
5512
+ email: z.string().nullish(),
5513
+ planType: z.string().nullish(),
5514
+ requiresOpenaiAuth: z.boolean().optional()
5515
+ });
5516
+ const CodexRateLimitsSchema = z.object({
5517
+ limitId: z.string().nullish(),
5518
+ limitName: z.string().nullish(),
5519
+ planType: z.string().nullish(),
5520
+ hasCredits: z.boolean().optional()
5521
+ });
5522
+ const CodexExperimentalFeatureSchema = z.object({
5523
+ name: z.string(),
5524
+ stage: z.string(),
5525
+ enabled: z.boolean(),
5526
+ defaultEnabled: z.boolean()
5527
+ });
5528
+ const CodexSkillSummarySchema = z.object({
5529
+ name: z.string(),
5530
+ description: z.string(),
5531
+ path: z.string(),
5532
+ enabled: z.boolean()
5533
+ });
5534
+ const CodexPromptSummarySchema = z.object({
5535
+ name: z.string(),
5536
+ path: z.string(),
5537
+ description: z.string().nullish()
5538
+ });
5539
+ const CodexAgentSummarySchema = z.object({
5540
+ name: z.string(),
5541
+ path: z.string()
5542
+ });
5543
+ const CodexMcpServerSummarySchema = z.object({
5544
+ name: z.string(),
5545
+ authStatus: z.string(),
5546
+ toolCount: z.number()
5547
+ });
5548
+ z.object({
5549
+ requestedBackend: CodexRequestedBackendSchema.optional(),
5550
+ resolvedBackend: CodexResolvedBackendSchema.optional(),
5551
+ configMode: CodexConfigModeSchema.optional(),
5552
+ fallbackReason: z.string().optional(),
5553
+ backendVersion: z.string().optional(),
5554
+ threadId: z.string().optional(),
5555
+ config: CodexRuntimeConfigSchema.optional(),
5556
+ account: CodexAccountSchema.optional(),
5557
+ rateLimits: CodexRateLimitsSchema.optional(),
5558
+ experimentalFeatures: z.array(CodexExperimentalFeatureSchema).optional(),
5559
+ skills: z.array(CodexSkillSummarySchema).optional(),
5560
+ prompts: z.array(CodexPromptSummarySchema).optional(),
5561
+ agents: z.array(CodexAgentSummarySchema).optional(),
5562
+ mcpServers: z.array(CodexMcpServerSummarySchema).optional()
5563
+ });
5564
+
5565
+ z$1.object({}).strict();
5566
+ z$1.object({
5567
+ /** Pre-formatted single-line summary (same text `/usage` prints in non-interactive mode). */
5568
+ formatted: z$1.string(),
5569
+ /** Total USD spent on this session so far. */
5570
+ totalUsd: z$1.number().nonnegative(),
5571
+ /** Optional breakdown by model. */
5572
+ byModel: z$1.record(z$1.string(), z$1.object({
5573
+ inputTokens: z$1.number().int().nonnegative(),
5574
+ outputTokens: z$1.number().int().nonnegative(),
5575
+ cacheCreationInputTokens: z$1.number().int().nonnegative().optional(),
5576
+ cacheReadInputTokens: z$1.number().int().nonnegative().optional(),
5577
+ costUsd: z$1.number().nonnegative()
5578
+ })).optional()
5579
+ }).strict();
5580
+ z$1.object({}).strict();
5581
+ z$1.object({
5582
+ /** Remote Claude Code binary version string, e.g. "2.1.119". */
5583
+ version: z$1.string(),
5584
+ /** Path to the binary if resolvable, informational only. */
5585
+ binaryPath: z$1.string().optional(),
5586
+ /** Happy-cli package version for context. */
5587
+ happyCliVersion: z$1.string().optional()
5588
+ }).strict();
5589
+ z$1.object({
5590
+ /** Agent color name or the literal "default" to reset. */
5591
+ color: z$1.string().min(1).max(64)
5592
+ }).strict();
5593
+ z$1.object({
5594
+ success: z$1.literal(true),
5595
+ color: z$1.string()
5596
+ }).strict();
5597
+ z$1.object({
5598
+ /** Path relative to cwd or absolute. CLI applies path blacklist + Read-tool permission gating. */
5599
+ path: z$1.string().min(1).max(4096),
5600
+ /** Optional max bytes to return; server-side hard cap enforces <= 1 MiB. */
5601
+ maxBytes: z$1.number().int().positive().max(1024 * 1024).optional()
5602
+ }).strict();
5603
+ z$1.object({
5604
+ /** Null when permission denied / missing / blocked by CLI path blacklist. */
5605
+ result: z$1.object({
5606
+ contents: z$1.string(),
5607
+ absPath: z$1.string(),
5608
+ truncated: z$1.boolean().optional()
5609
+ }).nullable(),
5610
+ /** Machine-readable reason when result is null. */
5611
+ deniedReason: z$1.enum(["not_found", "permission_denied", "blacklisted_path", "too_large", "error"]).optional()
5612
+ }).strict();
5613
+ z$1.object({
5614
+ /** Fully-qualified MCP tool name, e.g. `mcp__fs__read`. Must pass CLI whitelist. */
5615
+ tool: z$1.string().regex(/^mcp__[a-z0-9_-]+__[a-z0-9_.-]+$/i, "must be of form mcp__<server>__<tool>"),
5616
+ /** Tool arguments; schema-free, CLI passes through to MCP server. */
5617
+ arguments: z$1.record(z$1.string(), z$1.unknown()).optional(),
5618
+ /**
5619
+ * Client-nonce that App must have displayed to the user in a 2-step
5620
+ * confirm dialog. CLI uses this only for audit logging — the actual
5621
+ * confirmation happens on App side and is logged for security review.
5622
+ */
5623
+ clientConfirmToken: z$1.string().min(8).max(128)
5624
+ }).strict();
5625
+ z$1.object({
5626
+ success: z$1.boolean(),
5627
+ /** Tool response payload, shape defined by each MCP tool. */
5628
+ result: z$1.unknown().optional(),
5629
+ /** Error code for UI to localize; see CLI handler for enum values. */
5630
+ errorCode: z$1.enum([
5631
+ "not_whitelisted",
5632
+ "server_unavailable",
5633
+ "tool_not_found",
5634
+ "invalid_arguments",
5635
+ "permission_denied",
5636
+ /**
5637
+ * SDK 0.2.119 defines the `mcp_call` control protocol type but does
5638
+ * not expose a public runtime method on the `Query` interface. Until
5639
+ * upstream lands a `callMcpTool()` / equivalent, the CLI handler
5640
+ * returns this code so the App can surface an honest "waiting on
5641
+ * SDK" state instead of masking the gap as a server error.
5642
+ */
5643
+ "sdk_not_implemented",
5644
+ "unknown"
5645
+ ]).optional(),
5646
+ errorMessage: z$1.string().optional()
5647
+ }).strict();
5648
+
5649
+ function buildSummaryRefreshPrompt(requestId) {
5650
+ return [
5651
+ "Please call mcp__happy__update_session_summary to record the current session summary with: goal, currentFocus, keyDecisions (if any), openQuestions (if any), impactScope (if any). Keep it accurate and concise.",
5652
+ "",
5653
+ `Request ID: ${requestId}`,
5654
+ "Important: include this requestId exactly in the tool input as `requestId` when you call mcp__happy__update_session_summary."
5655
+ ].join("\n");
5656
+ }
5657
+ function toMetadataRecord(metadata) {
5658
+ if (metadata == null || typeof metadata !== "object" || Array.isArray(metadata)) {
5659
+ return {};
5660
+ }
5661
+ return metadata;
5662
+ }
5663
+ function appendRecentEntry(existing, entry) {
5664
+ return [
5665
+ ...(existing ?? []).filter((item) => item.requestId !== entry.requestId),
5666
+ entry
5667
+ ].slice(-4);
5668
+ }
5669
+ function extractSessionSummaryState(metadata) {
5670
+ const parsed = sessionSummaryStateSchema.safeParse(
5671
+ toMetadataRecord(metadata).sessionSummary
5672
+ );
5673
+ return parsed.success ? parsed.data : null;
5674
+ }
5675
+ function extractSessionSummaryRefreshState(metadata) {
5676
+ const parsed = sessionSummaryRefreshStateSchema.safeParse(
5677
+ toMetadataRecord(metadata).sessionSummaryRefresh
5678
+ );
5679
+ return parsed.success ? parsed.data : null;
5680
+ }
5681
+ function buildActiveSummaryRefreshState(args) {
5682
+ const existing = extractSessionSummaryRefreshState(args.metadata);
5683
+ const previousActive = existing?.active;
5684
+ const recent = previousActive && previousActive.requestId !== args.requestId ? appendRecentEntry(existing?.recent, {
5685
+ requestId: previousActive.requestId,
5686
+ status: "superseded",
5687
+ resolvedAt: args.requestedAt,
5688
+ supersededByRequestId: args.requestId
5689
+ }) : [...existing?.recent ?? []];
5690
+ return {
5691
+ protocolVersion: 1,
5692
+ active: {
5693
+ requestId: args.requestId,
5694
+ requestedAt: args.requestedAt,
5695
+ requester: "happy-agent",
5696
+ command: "summary-refresh",
5697
+ requireSummary: args.requireSummary
5698
+ },
5699
+ recent
5700
+ };
5701
+ }
5702
+ function getRecentSummaryRefreshEntry(metadata, requestId) {
5703
+ const refresh = extractSessionSummaryRefreshState(metadata);
5704
+ const recent = refresh?.recent;
5705
+ if (!recent) {
5706
+ return null;
5707
+ }
5708
+ for (let index = recent.length - 1; index >= 0; index -= 1) {
5709
+ if (recent[index]?.requestId === requestId) {
5710
+ return recent[index] ?? null;
5711
+ }
5712
+ }
5713
+ return null;
5714
+ }
5715
+ function waitForSummaryRefreshRecentApplied(client, opts) {
5716
+ const getEntry = (metadata) => getRecentSummaryRefreshEntry(metadata, opts.requestId);
5717
+ const immediate = getEntry(client.getMetadata());
5718
+ if (immediate?.status === "applied") {
5719
+ return Promise.resolve(immediate);
5720
+ }
5721
+ if (immediate?.status === "superseded") {
5722
+ return Promise.reject(
5723
+ new Error(
5724
+ `Summary refresh request ${opts.requestId} was superseded${immediate.supersededByRequestId ? ` by ${immediate.supersededByRequestId}` : ""}`
5725
+ )
5726
+ );
5727
+ }
5728
+ return new Promise((resolve, reject) => {
5729
+ const onStateChange = (data) => {
5730
+ const entry = getEntry(data.metadata ?? client.getMetadata());
5731
+ if (!entry) {
5732
+ return;
5733
+ }
5734
+ if (entry.status === "applied") {
5735
+ cleanup();
5736
+ resolve(entry);
5737
+ return;
5738
+ }
5739
+ cleanup();
5740
+ reject(
5741
+ new Error(
5742
+ `Summary refresh request ${opts.requestId} was superseded${entry.supersededByRequestId ? ` by ${entry.supersededByRequestId}` : ""}`
5743
+ )
5744
+ );
5745
+ };
5746
+ const onDisconnect = () => {
5747
+ cleanup();
5748
+ reject(
5749
+ new Error(
5750
+ "Socket disconnected while waiting for summary refresh acknowledgement"
5751
+ )
5752
+ );
5753
+ };
5754
+ const cleanup = () => {
5755
+ clearTimeout(timeout);
5756
+ client.removeListener("state-change", onStateChange);
5757
+ client.removeListener("disconnected", onDisconnect);
5758
+ };
5759
+ const timeout = setTimeout(() => {
5760
+ cleanup();
5761
+ reject(new Error("Timeout waiting for summary refresh acknowledgement"));
5762
+ }, opts.timeoutMs);
5763
+ client.on("state-change", onStateChange);
5764
+ client.on("disconnected", onDisconnect);
5765
+ });
5766
+ }
5767
+
3431
5768
  function formatTime(ts) {
3432
5769
  if (!ts) return "-";
3433
5770
  const date = new Date(ts);
5771
+ if (Number.isNaN(date.getTime())) return "-";
3434
5772
  const now = /* @__PURE__ */ new Date();
3435
5773
  const diffMs = now.getTime() - date.getTime();
3436
5774
  const diffMin = Math.floor(diffMs / 6e4);
@@ -3467,7 +5805,7 @@ function normalizeListValue(value) {
3467
5805
  function toNonEmptyString(value) {
3468
5806
  return typeof value === "string" && value.trim().length > 0 ? value : void 0;
3469
5807
  }
3470
- function extractSessionSummary(meta) {
5808
+ function extractSessionName(meta) {
3471
5809
  const direct = toNonEmptyString(meta.summary);
3472
5810
  if (direct) return direct;
3473
5811
  if (meta.summary != null && typeof meta.summary === "object") {
@@ -3475,13 +5813,21 @@ function extractSessionSummary(meta) {
3475
5813
  }
3476
5814
  return void 0;
3477
5815
  }
5816
+ function formatMarkdownListSection(title, items) {
5817
+ if (items.length === 0) return [];
5818
+ return [
5819
+ "",
5820
+ `### ${title}`,
5821
+ ...items.map((item) => `- ${normalizeListValue(item)}`)
5822
+ ];
5823
+ }
3478
5824
  function formatSessionTable(sessions) {
3479
5825
  if (sessions.length === 0) {
3480
5826
  return "## Sessions\n\n- Total: 0\n- Items: none";
3481
5827
  }
3482
5828
  const sections = sessions.map((s, index) => {
3483
5829
  const meta = s.metadata ?? {};
3484
- const name = normalizeListValue(extractSessionSummary(meta) ?? toNonEmptyString(meta.tag) ?? "-");
5830
+ const name = normalizeListValue(extractSessionName(meta) ?? toNonEmptyString(meta.tag) ?? "-");
3485
5831
  const path = normalizeListValue(toNonEmptyString(meta.path) ?? "-");
3486
5832
  const status = s.active ? "active" : "inactive";
3487
5833
  const lastActive = normalizeListValue(formatLastActive(s.activeAt));
@@ -3504,7 +5850,7 @@ function formatSessionStatus(session) {
3504
5850
  const meta = session.metadata ?? {};
3505
5851
  const state = session.agentState ?? null;
3506
5852
  const tag = toNonEmptyString(meta.tag);
3507
- const summary = extractSessionSummary(meta);
5853
+ const summary = extractSessionName(meta);
3508
5854
  const path = toNonEmptyString(meta.path);
3509
5855
  const host = toNonEmptyString(meta.host);
3510
5856
  const lifecycleState = toNonEmptyString(meta.lifecycleState);
@@ -3533,6 +5879,30 @@ function formatSessionStatus(session) {
3533
5879
  }
3534
5880
  return lines.join("\n");
3535
5881
  }
5882
+ function formatSessionNarrativeSummary(session) {
5883
+ const summary = extractSessionSummaryState(session.metadata);
5884
+ const lines = [
5885
+ "## Session Summary",
5886
+ "",
5887
+ `- Session ID: ${toMarkdownInline(session.id)}`
5888
+ ];
5889
+ if (!summary) {
5890
+ lines.push("- Status: missing");
5891
+ lines.push(
5892
+ `- Hint: Run ${toMarkdownInline(`happy-agent summary refresh ${session.id}`)} to request one.`
5893
+ );
5894
+ return lines.join("\n");
5895
+ }
5896
+ lines.push(`- Updated: ${formatLastActive(summary.updatedAt)}`);
5897
+ lines.push(`- Goal: ${normalizeListValue(summary.goal)}`);
5898
+ if (summary.currentFocus) {
5899
+ lines.push(`- Focus: ${normalizeListValue(summary.currentFocus)}`);
5900
+ }
5901
+ lines.push(...formatMarkdownListSection("Key Decisions", summary.keyDecisions ?? []));
5902
+ lines.push(...formatMarkdownListSection("Open Questions", summary.openQuestions ?? []));
5903
+ lines.push(...formatMarkdownListSection("Impact Scope", summary.impactScope ?? []));
5904
+ return lines.join("\n");
5905
+ }
3536
5906
  function formatMessageHistory(messages) {
3537
5907
  if (messages.length === 0) {
3538
5908
  return "## Message History\n\n- Count: 0\n- Items: none";
@@ -3599,9 +5969,48 @@ function createClient(session, creds, config) {
3599
5969
  encryptionVariant: session.encryption.variant,
3600
5970
  token: creds.token,
3601
5971
  serverUrl: config.serverUrl,
5972
+ initialMetadata: session.metadata ?? null,
5973
+ initialMetadataVersion: session.metadataVersion,
3602
5974
  initialAgentState: session.agentState ?? null
3603
5975
  });
3604
5976
  }
5977
+ function sleep(ms) {
5978
+ return new Promise((resolve) => setTimeout(resolve, ms));
5979
+ }
5980
+ async function hydrateSessionLiveState(session, creds, config) {
5981
+ const client = createClient(session, creds, config);
5982
+ let liveData = false;
5983
+ try {
5984
+ await new Promise((resolve) => {
5985
+ let resolved = false;
5986
+ const done = () => {
5987
+ if (resolved) return;
5988
+ resolved = true;
5989
+ clearTimeout(timeout);
5990
+ client.removeAllListeners("state-change");
5991
+ client.removeAllListeners("connect_error");
5992
+ resolve();
5993
+ };
5994
+ const timeout = setTimeout(done, 3e3);
5995
+ client.once(
5996
+ "state-change",
5997
+ (data) => {
5998
+ session.metadata = data.metadata ?? session.metadata;
5999
+ session.metadataVersion = client.getMetadataVersion();
6000
+ session.agentState = data.agentState ?? session.agentState;
6001
+ liveData = true;
6002
+ done();
6003
+ }
6004
+ );
6005
+ client.once("connect_error", () => {
6006
+ done();
6007
+ });
6008
+ });
6009
+ } finally {
6010
+ client.close();
6011
+ }
6012
+ return liveData;
6013
+ }
3605
6014
  const program = new Command();
3606
6015
  program.name("happy-agent").description("CLI client for controlling Happy Coder agents remotely").version(version);
3607
6016
  program.command("auth").description("Manage authentication").addCommand(
@@ -3634,36 +6043,7 @@ program.command("status").description("Get live session state").argument("<sessi
3634
6043
  const config = loadConfig();
3635
6044
  const creds = requireCredentials(config);
3636
6045
  const session = await resolveSession(config, creds, sessionId);
3637
- const client = createClient(session, creds, config);
3638
- let liveData = false;
3639
- try {
3640
- await new Promise((resolve) => {
3641
- let resolved = false;
3642
- const done = () => {
3643
- if (resolved) return;
3644
- resolved = true;
3645
- clearTimeout(timeout);
3646
- client.removeAllListeners("state-change");
3647
- client.removeAllListeners("connect_error");
3648
- resolve();
3649
- };
3650
- const timeout = setTimeout(done, 3e3);
3651
- client.once(
3652
- "state-change",
3653
- (data) => {
3654
- session.metadata = data.metadata ?? session.metadata;
3655
- session.agentState = data.agentState ?? session.agentState;
3656
- liveData = true;
3657
- done();
3658
- }
3659
- );
3660
- client.once("connect_error", () => {
3661
- done();
3662
- });
3663
- });
3664
- } finally {
3665
- client.close();
3666
- }
6046
+ const liveData = await hydrateSessionLiveState(session, creds, config);
3667
6047
  if (opts.json) {
3668
6048
  console.log(formatJson(session));
3669
6049
  } else {
@@ -3673,6 +6053,131 @@ program.command("status").description("Get live session state").argument("<sessi
3673
6053
  console.log(formatSessionStatus(session));
3674
6054
  }
3675
6055
  });
6056
+ program.command("summary").description("Inspect or refresh session summaries").addCommand(
6057
+ new Command("show").description("Show the narrative session summary").argument("<session-id>", "Session ID or prefix").option("--json", "Output as JSON").action(async (sessionId, opts) => {
6058
+ const config = loadConfig();
6059
+ const creds = requireCredentials(config);
6060
+ const session = await resolveSession(config, creds, sessionId);
6061
+ const liveData = await hydrateSessionLiveState(session, creds, config);
6062
+ const summary = extractSessionSummaryState(session.metadata);
6063
+ if (opts.json) {
6064
+ console.log(
6065
+ formatJson({
6066
+ sessionId: session.id,
6067
+ live: liveData,
6068
+ summary
6069
+ })
6070
+ );
6071
+ } else {
6072
+ if (!liveData) {
6073
+ console.log("> Note: showing cached summary (could not get live state).");
6074
+ }
6075
+ console.log(formatSessionNarrativeSummary(session));
6076
+ }
6077
+ })
6078
+ ).addCommand(
6079
+ new Command("refresh").description("Ask the agent to rewrite the session summary").argument("<session-id>", "Session ID or prefix").option("--wait", "Wait for agent to become idle").option(
6080
+ "--require-summary",
6081
+ "Wait until this refresh request is acknowledged in sessionSummaryRefresh.recent"
6082
+ ).option(
6083
+ "--timeout <seconds>",
6084
+ "Timeout in seconds when using --wait or --require-summary",
6085
+ (v) => {
6086
+ const n = parseInt(v, 10);
6087
+ if (isNaN(n) || n <= 0)
6088
+ throw new Error("--timeout must be a positive integer");
6089
+ return n;
6090
+ },
6091
+ 300
6092
+ ).option("--json", "Output as JSON").action(
6093
+ async (sessionId, opts) => {
6094
+ const config = loadConfig();
6095
+ const creds = requireCredentials(config);
6096
+ const session = await resolveSession(config, creds, sessionId);
6097
+ const timeoutMs = opts.timeout * 1e3;
6098
+ const requestId = `summary-refresh_${randomUUID$1()}`;
6099
+ const requestedAt = Date.now();
6100
+ let summaryConfirmed = false;
6101
+ const client = createClient(session, creds, config);
6102
+ try {
6103
+ await client.waitForConnect();
6104
+ if (opts.requireSummary) {
6105
+ await client.updateMetadataWith((current) => {
6106
+ const base = current != null && typeof current === "object" && !Array.isArray(current) ? current : {};
6107
+ return {
6108
+ ...base,
6109
+ sessionSummaryRefresh: buildActiveSummaryRefreshState({
6110
+ metadata: current,
6111
+ requestId,
6112
+ requestedAt,
6113
+ requireSummary: true
6114
+ })
6115
+ };
6116
+ });
6117
+ }
6118
+ const summaryAckPromise = opts.requireSummary ? waitForSummaryRefreshRecentApplied(client, {
6119
+ requestId,
6120
+ timeoutMs
6121
+ }) : null;
6122
+ client.sendMessage(buildSummaryRefreshPrompt(requestId), {
6123
+ sentFrom: "happy-agent-summary-refresh",
6124
+ requestId
6125
+ });
6126
+ if (summaryAckPromise) {
6127
+ await summaryAckPromise;
6128
+ summaryConfirmed = true;
6129
+ }
6130
+ if (opts.wait) {
6131
+ await sleep(500);
6132
+ await client.waitForIdle(timeoutMs);
6133
+ } else if (!opts.requireSummary) {
6134
+ await sleep(500);
6135
+ }
6136
+ const latestMetadata = client.getMetadata();
6137
+ if (latestMetadata !== null) {
6138
+ session.metadata = latestMetadata;
6139
+ }
6140
+ session.metadataVersion = client.getMetadataVersion();
6141
+ } finally {
6142
+ client.close();
6143
+ }
6144
+ const summary = extractSessionSummaryState(session.metadata);
6145
+ if (opts.json) {
6146
+ console.log(
6147
+ formatJson({
6148
+ sessionId: session.id,
6149
+ requestId,
6150
+ requested: true,
6151
+ requiredSummary: opts.requireSummary === true,
6152
+ summaryConfirmed,
6153
+ waited: opts.wait === true,
6154
+ summary: opts.wait === true || opts.requireSummary === true ? summary : void 0
6155
+ })
6156
+ );
6157
+ } else if (opts.wait || opts.requireSummary) {
6158
+ if (!summary) {
6159
+ console.log(
6160
+ opts.requireSummary ? "> Note: summary update was required, but no valid narrative summary is available." : "> Note: summary was requested, but the session has not recorded a narrative summary yet."
6161
+ );
6162
+ }
6163
+ console.log(formatSessionNarrativeSummary(session));
6164
+ } else {
6165
+ console.log(
6166
+ [
6167
+ "## Summary Refresh Requested",
6168
+ "",
6169
+ `- Session ID: \`${session.id}\``,
6170
+ `- Request ID: \`${requestId}\``,
6171
+ `- Required Summary Update: ${opts.requireSummary ? "yes" : "no"}`,
6172
+ `- Summary Confirmed: ${summaryConfirmed ? "yes" : "no"}`,
6173
+ `- Waited For Idle: ${opts.wait ? "yes" : "no"}`,
6174
+ `- Hint: Run \`happy-agent summary show ${session.id}\` to inspect the updated summary.`
6175
+ ].join("\n")
6176
+ );
6177
+ }
6178
+ }
6179
+ )
6180
+ );
3676
6181
  program.command("create").description("Create a new session").requiredOption("--tag <tag>", "Session tag").option("--path <path>", "Working directory path").option("--json", "Output as JSON").action(async (opts) => {
3677
6182
  const config = loadConfig();
3678
6183
  const creds = requireCredentials(config);